diff --git a/Content.Client/Audio/AmbientSoundSystem.cs b/Content.Client/Audio/AmbientSoundSystem.cs
index d241df4f6f..8b5cf4ad06 100644
--- a/Content.Client/Audio/AmbientSoundSystem.cs
+++ b/Content.Client/Audio/AmbientSoundSystem.cs
@@ -13,304 +13,302 @@ using Robust.Shared.Utility;
using System.Linq;
using Robust.Client.GameObjects;
-namespace Content.Client.Audio
+namespace Content.Client.Audio;
+//TODO: This is using a incomplete version of the whole "only play nearest sounds" algo, that breaks down a bit should the ambient sound cap get hit.
+//TODO: This'll be fixed when GetEntitiesInRange produces consistent outputs.
+
+///
+/// Samples nearby and plays audio.
+///
+public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
{
- //TODO: This is using a incomplete version of the whole "only play nearest sounds" algo, that breaks down a bit should the ambient sound cap get hit.
- //TODO: This'll be fixed when GetEntitiesInRange produces consistent outputs.
+ [Dependency] private readonly AmbientSoundTreeSystem _treeSys = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly IConfigurationManager _cfg = default!;
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ protected override void QueueUpdate(EntityUid uid, AmbientSoundComponent ambience)
+ => _treeSys.QueueTreeUpdate(uid, ambience);
+
+ private AmbientSoundOverlay? _overlay;
+ private int _maxAmbientCount;
+ private bool _overlayEnabled;
+ private float _maxAmbientRange;
+ private float _cooldown;
+ private TimeSpan _targetTime = TimeSpan.Zero;
+ private float _ambienceVolume = 0.0f;
+
+ private static AudioParams _params = AudioParams.Default.WithVariation(0.01f).WithLoop(true).WithAttenuation(Attenuation.LinearDistance);
///
- /// Samples nearby and plays audio.
+ /// How many times we can be playing 1 particular sound at once.
///
- public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
+ private int MaxSingleSound => (int) (_maxAmbientCount / (16.0f / 6.0f));
+
+ private readonly Dictionary _playingSounds = new();
+ private readonly Dictionary _playingCount = new();
+
+ public bool OverlayEnabled
{
- [Dependency] private readonly AmbientSoundTreeSystem _treeSys = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
- [Dependency] private readonly IConfigurationManager _cfg = default!;
- [Dependency] private readonly IGameTiming _gameTiming = default!;
- [Dependency] private readonly IPlayerManager _playerManager = default!;
- [Dependency] private readonly IRobustRandom _random = default!;
-
- protected override void QueueUpdate(EntityUid uid, AmbientSoundComponent ambience)
- => _treeSys.QueueTreeUpdate(uid, ambience);
-
- private AmbientSoundOverlay? _overlay;
- private int _maxAmbientCount;
- private bool _overlayEnabled;
- private float _maxAmbientRange;
- private float _cooldown;
- private TimeSpan _targetTime = TimeSpan.Zero;
- private float _ambienceVolume = 0.0f;
-
- private static AudioParams _params = AudioParams.Default.WithVariation(0.01f).WithLoop(true).WithAttenuation(Attenuation.LinearDistance);
-
- ///
- /// How many times we can be playing 1 particular sound at once.
- ///
- private int MaxSingleSound => (int) (_maxAmbientCount / (16.0f / 6.0f));
-
- private readonly Dictionary _playingSounds = new();
- private readonly Dictionary _playingCount = new();
-
- public bool OverlayEnabled
+ get => _overlayEnabled;
+ set
{
- get => _overlayEnabled;
- set
- {
- if (_overlayEnabled == value) return;
- _overlayEnabled = value;
- var overlayManager = IoCManager.Resolve();
+ if (_overlayEnabled == value) return;
+ _overlayEnabled = value;
+ var overlayManager = IoCManager.Resolve();
- if (_overlayEnabled)
- {
- _overlay = new AmbientSoundOverlay(EntityManager, this, EntityManager.System());
- overlayManager.AddOverlay(_overlay);
- }
- else
- {
- overlayManager.RemoveOverlay(_overlay!);
- _overlay = null;
- }
+ if (_overlayEnabled)
+ {
+ _overlay = new AmbientSoundOverlay(EntityManager, this, EntityManager.System());
+ overlayManager.AddOverlay(_overlay);
+ }
+ else
+ {
+ overlayManager.RemoveOverlay(_overlay!);
+ _overlay = null;
}
}
+ }
- ///
- /// Is this AmbientSound actively playing right now?
- ///
- ///
- ///
- public bool IsActive(AmbientSoundComponent component)
+ ///
+ /// Is this AmbientSound actively playing right now?
+ ///
+ ///
+ ///
+ public bool IsActive(AmbientSoundComponent component)
+ {
+ return _playingSounds.ContainsKey(component);
+ }
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ UpdatesOutsidePrediction = true;
+ UpdatesAfter.Add(typeof(AmbientSoundTreeSystem));
+
+ _cfg.OnValueChanged(CCVars.AmbientCooldown, SetCooldown, true);
+ _cfg.OnValueChanged(CCVars.MaxAmbientSources, SetAmbientCount, true);
+ _cfg.OnValueChanged(CCVars.AmbientRange, SetAmbientRange, true);
+ _cfg.OnValueChanged(CCVars.AmbienceVolume, SetAmbienceVolume, true);
+ SubscribeLocalEvent(OnShutdown);
+ }
+
+ private void OnShutdown(EntityUid uid, AmbientSoundComponent component, ComponentShutdown args)
+ {
+ if (!_playingSounds.Remove(component, out var sound))
+ return;
+
+ sound.Stream?.Stop();
+ _playingCount[sound.Sound] -= 1;
+ if (_playingCount[sound.Sound] == 0)
+ _playingCount.Remove(sound.Sound);
+ }
+
+ private void SetAmbienceVolume(float value)
+ {
+ _ambienceVolume = value;
+
+ foreach (var (comp, values) in _playingSounds)
{
- return _playingSounds.ContainsKey(component);
+ 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 SetAmbientCount(int value) => _maxAmbientCount = value;
+ private void SetAmbientRange(float value) => _maxAmbientRange = value;
+
+ public override void Shutdown()
+ {
+ base.Shutdown();
+ ClearSounds();
+
+ _cfg.UnsubValueChanged(CCVars.AmbientCooldown, SetCooldown);
+ _cfg.UnsubValueChanged(CCVars.MaxAmbientSources, SetAmbientCount);
+ _cfg.UnsubValueChanged(CCVars.AmbientRange, SetAmbientRange);
+ _cfg.UnsubValueChanged(CCVars.AmbienceVolume, SetAmbienceVolume);
+ }
+
+ private int PlayingCount(string countSound)
+ {
+ var count = 0;
+
+ foreach (var (_, (_, sound)) in _playingSounds)
+ {
+ if (sound.Equals(countSound))
+ count++;
}
- public override void Initialize()
- {
- base.Initialize();
- UpdatesOutsidePrediction = true;
- UpdatesAfter.Add(typeof(AmbientSoundTreeSystem));
+ return count;
+ }
- _cfg.OnValueChanged(CCVars.AmbientCooldown, SetCooldown, true);
- _cfg.OnValueChanged(CCVars.MaxAmbientSources, SetAmbientCount, true);
- _cfg.OnValueChanged(CCVars.AmbientRange, SetAmbientRange, true);
- _cfg.OnValueChanged(CCVars.AmbienceVolume, SetAmbienceVolume, true);
- SubscribeLocalEvent(OnShutdown);
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ if (!_gameTiming.IsFirstTimePredicted)
+ return;
+
+ if (_cooldown <= 0f)
+ return;
+
+ if (_gameTiming.CurTime < _targetTime)
+ return;
+
+ _targetTime = _gameTiming.CurTime+TimeSpan.FromSeconds(_cooldown);
+
+ var player = _playerManager.LocalPlayer?.ControlledEntity;
+ if (!EntityManager.TryGetComponent(player, out TransformComponent? xform))
+ {
+ ClearSounds();
+ return;
}
- private void OnShutdown(EntityUid uid, AmbientSoundComponent component, ComponentShutdown args)
+ ProcessNearbyAmbience(xform);
+ }
+
+ private void ClearSounds()
+ {
+ foreach (var (stream, _) in _playingSounds.Values)
{
- if (!_playingSounds.Remove(component, out var sound))
- return;
+ stream?.Stop();
+ }
+
+ _playingSounds.Clear();
+ _playingCount.Clear();
+ }
+
+ private readonly struct QueryState
+ {
+ public readonly Dictionary> SourceDict = new();
+ public readonly Vector2 MapPos;
+ public readonly TransformComponent Player;
+ public readonly EntityQuery Query;
+
+ public QueryState(Vector2 mapPos, TransformComponent player, EntityQuery query)
+ {
+ MapPos = mapPos;
+ Player = player;
+ Query = query;
+ }
+ }
+
+ private static bool Callback(
+ ref QueryState state,
+ in ComponentTreeEntry value)
+ {
+ var (ambientComp, xform) = value;
+
+ DebugTools.Assert(ambientComp.Enabled);
+
+ var delta = xform.ParentUid == state.Player.ParentUid
+ ? xform.LocalPosition - state.Player.LocalPosition
+ : xform.WorldPosition - state.MapPos;
+
+ var range = delta.Length;
+ if (range >= ambientComp.Range)
+ return true;
+
+ string key;
+
+ if (ambientComp.Sound is SoundPathSpecifier path)
+ key = path.Path.ToString();
+ else
+ key = ((SoundCollectionSpecifier) ambientComp.Sound).Collection ?? string.Empty;
+
+ // Prioritize far away & loud sounds.
+ var importance = range * (ambientComp.Volume + 32);
+ state.SourceDict.GetOrNew(key).Add((importance, ambientComp));
+ return true;
+ }
+
+ ///
+ /// Get a list of ambient components in range and determine which ones to start playing.
+ ///
+ private void ProcessNearbyAmbience(TransformComponent playerXform)
+ {
+ var query = GetEntityQuery();
+ var metaQuery = GetEntityQuery();
+ var mapPos = playerXform.MapPosition;
+
+ // Remove out-of-range ambiences
+ foreach (var (comp, sound) in _playingSounds)
+ {
+ var entity = comp.Owner;
+
+ if (comp.Enabled &&
+ query.TryGetComponent(entity, out var xform) &&
+ xform.MapID == playerXform.MapID &&
+ !metaQuery.GetComponent(entity).EntityPaused)
+ {
+ var distance = (xform.ParentUid == playerXform.ParentUid)
+ ? xform.LocalPosition - playerXform.LocalPosition
+ : xform.WorldPosition - mapPos.Position;
+
+ if (distance.LengthSquared < comp.Range * comp.Range)
+ continue;
+ }
sound.Stream?.Stop();
+ _playingSounds.Remove(comp);
_playingCount[sound.Sound] -= 1;
if (_playingCount[sound.Sound] == 0)
_playingCount.Remove(sound.Sound);
}
- private void SetAmbienceVolume(float value)
- {
- _ambienceVolume = value;
+ if (_playingSounds.Count >= _maxAmbientCount)
+ return;
- foreach (var (comp, values) in _playingSounds)
+ var pos = mapPos.Position;
+ var state = new QueryState(pos, playerXform, query);
+ var worldAabb = new Box2(pos - _maxAmbientRange, pos + _maxAmbientRange);
+ _treeSys.QueryAabb(ref state, Callback, mapPos.MapId, worldAabb);
+
+ // Add in range ambiences
+ foreach (var (key, sources) in state.SourceDict)
+ {
+ if (_playingSounds.Count >= _maxAmbientCount)
+ break;
+
+ if (_playingCount.TryGetValue(key, out var playingCount) && playingCount >= MaxSingleSound)
+ continue;
+
+ sources.Sort(static (a, b) => b.Importance.CompareTo(a.Importance));
+
+ foreach (var (_, comp) in sources)
{
- if (values.Stream == null)
+ var uid = comp.Owner;
+
+ if (_playingSounds.ContainsKey(comp) ||
+ metaQuery.GetComponent(uid).EntityPaused)
continue;
- var stream = (AudioSystem.PlayingStream) values.Stream;
- stream.Volume = _params.Volume + comp.Volume + _ambienceVolume;
- }
- }
- private void SetCooldown(float value) => _cooldown = value;
- private void SetAmbientCount(int value) => _maxAmbientCount = value;
- private void SetAmbientRange(float value) => _maxAmbientRange = value;
+ var audioParams = _params
+ .AddVolume(comp.Volume + _ambienceVolume)
+ // Randomise start so 2 sources don't increase their volume.
+ .WithPlayOffset(_random.NextFloat(0.0f, 100.0f))
+ .WithMaxDistance(comp.Range);
- public override void Shutdown()
- {
- base.Shutdown();
- ClearSounds();
+ var stream = _audio.PlayPvs(comp.Sound, uid, audioParams);
+ if (stream == null)
+ continue;
- _cfg.UnsubValueChanged(CCVars.AmbientCooldown, SetCooldown);
- _cfg.UnsubValueChanged(CCVars.MaxAmbientSources, SetAmbientCount);
- _cfg.UnsubValueChanged(CCVars.AmbientRange, SetAmbientRange);
- _cfg.UnsubValueChanged(CCVars.AmbienceVolume, SetAmbienceVolume);
- }
+ _playingSounds[comp] = (stream, key);
+ playingCount++;
- private int PlayingCount(string countSound)
- {
- var count = 0;
-
- foreach (var (_, (_, sound)) in _playingSounds)
- {
- if (sound.Equals(countSound))
- count++;
- }
-
- return count;
- }
-
- public override void Update(float frameTime)
- {
- base.Update(frameTime);
-
- if (!_gameTiming.IsFirstTimePredicted)
- return;
-
- if (_cooldown <= 0f)
- return;
-
- if (_gameTiming.CurTime < _targetTime)
- return;
-
- _targetTime = _gameTiming.CurTime+TimeSpan.FromSeconds(_cooldown);
-
- var player = _playerManager.LocalPlayer?.ControlledEntity;
- if (!EntityManager.TryGetComponent(player, out TransformComponent? xform))
- {
- ClearSounds();
- return;
- }
-
- ProcessNearbyAmbience(xform);
- }
-
- private void ClearSounds()
- {
- foreach (var (stream, _) in _playingSounds.Values)
- {
- stream?.Stop();
- }
-
- _playingSounds.Clear();
- _playingCount.Clear();
- }
-
- private readonly struct QueryState
- {
- public readonly Dictionary> SourceDict = new();
- public readonly Vector2 MapPos;
- public readonly TransformComponent Player;
- public readonly EntityQuery Query;
-
- public QueryState(Vector2 mapPos, TransformComponent player, EntityQuery query)
- {
- MapPos = mapPos;
- Player = player;
- Query = query;
- }
- }
-
- private static bool Callback(
- ref QueryState state,
- in ComponentTreeEntry value)
- {
- var (ambientComp, xform) = value;
-
- DebugTools.Assert(ambientComp.Enabled);
-
- var delta = xform.ParentUid == state.Player.ParentUid
- ? xform.LocalPosition - state.Player.LocalPosition
- : xform.WorldPosition - state.MapPos;
-
- var range = delta.Length;
- if (range >= ambientComp.Range)
- return true;
-
- string key;
-
- if (ambientComp.Sound is SoundPathSpecifier path)
- key = path.Path.ToString();
- else
- key = ((SoundCollectionSpecifier) ambientComp.Sound).Collection ?? string.Empty;
-
- // Prioritize far away & loud sounds.
- var importance = range * (ambientComp.Volume + 32);
- state.SourceDict.GetOrNew(key).Add((importance, ambientComp));
- return true;
- }
-
- ///
- /// Get a list of ambient components in range and determine which ones to start playing.
- ///
- private void ProcessNearbyAmbience(TransformComponent playerXform)
- {
- var query = GetEntityQuery();
- var metaQuery = GetEntityQuery();
- var mapPos = playerXform.MapPosition;
-
- // Remove out-of-range ambiences
- foreach (var (comp, sound) in _playingSounds)
- {
- var entity = comp.Owner;
-
- if (comp.Enabled &&
- query.TryGetComponent(entity, out var xform) &&
- xform.MapID == playerXform.MapID &&
- !metaQuery.GetComponent(entity).EntityPaused)
- {
- var distance = (xform.ParentUid == playerXform.ParentUid)
- ? xform.LocalPosition - playerXform.LocalPosition
- : xform.WorldPosition - mapPos.Position;
-
- if (distance.LengthSquared < comp.Range * comp.Range)
- continue;
- }
-
- sound.Stream?.Stop();
- _playingSounds.Remove(comp);
- _playingCount[sound.Sound] -= 1;
- if (_playingCount[sound.Sound] == 0)
- _playingCount.Remove(sound.Sound);
- }
-
- if (_playingSounds.Count >= _maxAmbientCount)
- return;
-
- var pos = mapPos.Position;
- var state = new QueryState(pos, playerXform, query);
- var worldAabb = new Box2(pos - _maxAmbientRange, pos + _maxAmbientRange);
- _treeSys.QueryAabb(ref state, Callback, mapPos.MapId, worldAabb);
-
- // Add in range ambiences
- foreach (var (key, sources) in state.SourceDict)
- {
if (_playingSounds.Count >= _maxAmbientCount)
break;
-
- if (_playingCount.TryGetValue(key, out var playingCount) && playingCount >= MaxSingleSound)
- continue;
-
- sources.Sort(static (a, b) => b.Importance.CompareTo(a.Importance));
-
- foreach (var (_, comp) in sources)
- {
- var uid = comp.Owner;
-
- if (_playingSounds.ContainsKey(comp) ||
- metaQuery.GetComponent(uid).EntityPaused)
- continue;
-
- var audioParams = _params
- .AddVolume(comp.Volume + _ambienceVolume)
- // Randomise start so 2 sources don't increase their volume.
- .WithPlayOffset(_random.NextFloat(0.0f, 100.0f))
- .WithMaxDistance(comp.Range);
-
- var stream = _audio.PlayPvs(comp.Sound, uid, audioParams);
- if (stream == null)
- continue;
-
- _playingSounds[comp] = (stream, key);
- playingCount++;
-
- if (_playingSounds.Count >= _maxAmbientCount)
- break;
- }
-
- if (playingCount != 0)
- _playingCount[key] = playingCount;
}
- DebugTools.Assert(_playingCount.All(x => x.Value == PlayingCount(x.Key)));
+ if (playingCount != 0)
+ _playingCount[key] = playingCount;
}
+
+ DebugTools.Assert(_playingCount.All(x => x.Value == PlayingCount(x.Key)));
}
}
diff --git a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs
index 34bc83bdfb..15fc53222e 100644
--- a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs
+++ b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs
@@ -245,6 +245,12 @@ public sealed partial class ContentAudioSystem
if (player == null)
return null;
+ var ev = new PlayAmbientMusicEvent();
+ RaiseLocalEvent(ref ev);
+
+ if (ev.Cancelled)
+ return null;
+
var ambiences = _proto.EnumeratePrototypes().ToList();
ambiences.Sort((x, y) => y.Priority.CompareTo(x.Priority));
@@ -259,4 +265,13 @@ public sealed partial class ContentAudioSystem
_sawmill.Warning($"Unable to find fallback ambience track");
return null;
}
+
+ ///
+ /// Fades out the current ambient music temporarily.
+ ///
+ public void DisableAmbientMusic()
+ {
+ FadeOut(_ambientMusicStream);
+ _ambientMusicStream = null;
+ }
}
diff --git a/Content.Client/Audio/ContentAudioSystem.cs b/Content.Client/Audio/ContentAudioSystem.cs
index cd6a88f01d..696a5eb32d 100644
--- a/Content.Client/Audio/ContentAudioSystem.cs
+++ b/Content.Client/Audio/ContentAudioSystem.cs
@@ -122,3 +122,9 @@ public sealed partial class ContentAudioSystem : SharedContentAudioSystem
#endregion
}
+
+///
+/// Raised whenever ambient music tries to play.
+///
+[ByRefEvent]
+public record struct PlayAmbientMusicEvent(bool Cancelled = false);
diff --git a/Content.Client/Salvage/SalvageExpeditionComponent.cs b/Content.Client/Salvage/SalvageExpeditionComponent.cs
new file mode 100644
index 0000000000..0c3bdd15a6
--- /dev/null
+++ b/Content.Client/Salvage/SalvageExpeditionComponent.cs
@@ -0,0 +1,9 @@
+using Content.Shared.Salvage.Expeditions;
+
+namespace Content.Client.Salvage;
+
+[RegisterComponent]
+public sealed class SalvageExpeditionComponent : SharedSalvageExpeditionComponent
+{
+
+}
diff --git a/Content.Client/Salvage/SalvageSystem.cs b/Content.Client/Salvage/SalvageSystem.cs
index 97737bc3e3..0a73c727a4 100644
--- a/Content.Client/Salvage/SalvageSystem.cs
+++ b/Content.Client/Salvage/SalvageSystem.cs
@@ -1,8 +1,50 @@
+using Content.Client.Audio;
using Content.Shared.Salvage;
+using Content.Shared.Salvage.Expeditions;
+using Robust.Client.Player;
+using Robust.Shared.GameStates;
namespace Content.Client.Salvage;
public sealed class SalvageSystem : SharedSalvageSystem
{
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly ContentAudioSystem _audio = default!;
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnPlayAmbientMusic);
+ SubscribeLocalEvent(OnExpeditionHandleState);
+ }
+
+ private void OnExpeditionHandleState(EntityUid uid, SalvageExpeditionComponent component, ref ComponentHandleState args)
+ {
+ if (args.Current is not SalvageExpeditionComponentState state)
+ return;
+
+ component.Stage = state.Stage;
+
+ if (component.Stage >= ExpeditionStage.MusicCountdown)
+ {
+ _audio.DisableAmbientMusic();
+ }
+ }
+
+ private void OnPlayAmbientMusic(ref PlayAmbientMusicEvent ev)
+ {
+ if (ev.Cancelled)
+ return;
+
+ var player = _playerManager.LocalPlayer?.ControlledEntity;
+
+ if (!TryComp(player, out var xform) ||
+ !TryComp(xform.MapUid, out var expedition) ||
+ expedition.Stage < ExpeditionStage.MusicCountdown)
+ {
+ return;
+ }
+
+ ev.Cancelled = true;
+ }
}
diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs
index ccc9fc36d0..6f5ee423e6 100644
--- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs
+++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs
@@ -1,4 +1,5 @@
using Content.Shared.Salvage;
+using Content.Shared.Salvage.Expeditions;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
diff --git a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs
index fcc8f7af0d..c27f2ad317 100644
--- a/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs
+++ b/Content.Client/Salvage/UI/SalvageExpeditionWindow.xaml.cs
@@ -5,6 +5,7 @@ using Content.Client.UserInterface.Controls;
using Content.Shared.CCVar;
using Content.Shared.Parallax.Biomes;
using Content.Shared.Salvage;
+using Content.Shared.Salvage.Expeditions;
using Content.Shared.Salvage.Expeditions.Modifiers;
using Content.Shared.Shuttles.BUIStates;
using Robust.Client.AutoGenerated;
diff --git a/Content.Server/Audio/AmbientSoundSystem.cs b/Content.Server/Audio/AmbientSoundSystem.cs
index 2adf94f891..53a03be2aa 100644
--- a/Content.Server/Audio/AmbientSoundSystem.cs
+++ b/Content.Server/Audio/AmbientSoundSystem.cs
@@ -2,25 +2,24 @@ using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.Audio;
-namespace Content.Server.Audio
+namespace Content.Server.Audio;
+
+public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
{
- public sealed class AmbientSoundSystem : SharedAmbientSoundSystem
+ public override void Initialize()
{
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent(HandlePowerChange);
- SubscribeLocalEvent(HandlePowerSupply);
- }
+ base.Initialize();
+ SubscribeLocalEvent(HandlePowerChange);
+ SubscribeLocalEvent(HandlePowerSupply);
+ }
- private void HandlePowerSupply(EntityUid uid, AmbientOnPoweredComponent component, ref PowerNetBatterySupplyEvent args)
- {
- SetAmbience(uid, args.Supply);
- }
+ private void HandlePowerSupply(EntityUid uid, AmbientOnPoweredComponent component, ref PowerNetBatterySupplyEvent args)
+ {
+ SetAmbience(uid, args.Supply);
+ }
- private void HandlePowerChange(EntityUid uid, AmbientOnPoweredComponent component, ref PowerChangedEvent args)
- {
- SetAmbience(uid, args.Powered);
- }
+ private void HandlePowerChange(EntityUid uid, AmbientOnPoweredComponent component, ref PowerChangedEvent args)
+ {
+ SetAmbience(uid, args.Powered);
}
}
diff --git a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs
index 1fcc4c3003..ce53041456 100644
--- a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs
+++ b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs
@@ -1,9 +1,8 @@
-using Content.Shared.Random;
using Content.Shared.Salvage;
+using Content.Shared.Salvage.Expeditions;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Server.Salvage.Expeditions;
@@ -12,7 +11,7 @@ namespace Content.Server.Salvage.Expeditions;
/// Designates this entity as holding a salvage expedition.
///
[RegisterComponent]
-public sealed class SalvageExpeditionComponent : Component
+public sealed class SalvageExpeditionComponent : SharedSalvageExpeditionComponent
{
public SalvageMissionParams MissionParams = default!;
@@ -36,9 +35,6 @@ public sealed class SalvageExpeditionComponent : Component
[ViewVariables] public bool Completed = false;
- [ViewVariables(VVAccess.ReadWrite), DataField("stage")]
- public ExpeditionStage Stage = ExpeditionStage.Added;
-
///
/// Countdown audio stream.
///
@@ -50,7 +46,7 @@ public sealed class SalvageExpeditionComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("sound")]
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Misc/tension_session.ogg")
{
- Params = AudioParams.Default.WithVolume(-15),
+ Params = AudioParams.Default.WithVolume(-5),
};
///
@@ -65,12 +61,3 @@ public sealed class SalvageExpeditionComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("rewards", customTypeSerializer: typeof(PrototypeIdListSerializer))]
public List Rewards = default!;
}
-
-public enum ExpeditionStage : byte
-{
- Added,
- Running,
- Countdown,
- MusicCountdown,
- FinalCountdown,
-}
diff --git a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs
index 3239bc77e5..324bdf9e01 100644
--- a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs
+++ b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs
@@ -1,4 +1,5 @@
using Content.Shared.Salvage;
+using Content.Shared.Salvage.Expeditions;
using Robust.Server.GameObjects;
namespace Content.Server.Salvage;
diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs
index 12a1032cac..24b2b22196 100644
--- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs
+++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs
@@ -2,16 +2,15 @@ using Content.Server.Cargo.Components;
using Content.Server.Cargo.Systems;
using Content.Server.Salvage.Expeditions;
using Content.Server.Salvage.Expeditions.Structure;
-using Content.Server.Station.Systems;
using Content.Shared.CCVar;
-using Content.Shared.Random;
-using Content.Shared.Random.Helpers;
using Content.Shared.Examine;
using Content.Shared.Salvage;
using Robust.Shared.CPUJob.JobQueues;
using Robust.Shared.CPUJob.JobQueues.Queues;
using System.Linq;
using System.Threading;
+using Content.Shared.Salvage.Expeditions;
+using Robust.Shared.GameStates;
namespace Content.Server.Salvage;
@@ -42,6 +41,7 @@ public sealed partial class SalvageSystem
SubscribeLocalEvent(OnExpeditionShutdown);
SubscribeLocalEvent(OnExpeditionUnpaused);
+ SubscribeLocalEvent(OnExpeditionGetState);
SubscribeLocalEvent(OnStructureExamine);
@@ -51,6 +51,14 @@ public sealed partial class SalvageSystem
_configurationManager.OnValueChanged(CCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange);
}
+ private void OnExpeditionGetState(EntityUid uid, SalvageExpeditionComponent component, ref ComponentGetState args)
+ {
+ args.State = new SalvageExpeditionComponentState()
+ {
+ Stage = component.Stage
+ };
+ }
+
private void ShutdownExpeditions()
{
_configurationManager.UnsubValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange);
diff --git a/Content.Server/Salvage/SalvageSystem.Runner.cs b/Content.Server/Salvage/SalvageSystem.Runner.cs
index a52649ada0..208f3deca0 100644
--- a/Content.Server/Salvage/SalvageSystem.Runner.cs
+++ b/Content.Server/Salvage/SalvageSystem.Runner.cs
@@ -8,9 +8,7 @@ using Content.Shared.Chat;
using Content.Shared.Humanoid;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
-using Content.Shared.Salvage;
-using Content.Shared.Shuttles.Components;
-using Robust.Shared.Audio;
+using Content.Shared.Salvage.Expeditions;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
using Robust.Shared.Utility;
@@ -110,6 +108,7 @@ public sealed partial class SalvageSystem
Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-dungeon", ("direction", component.DungeonLocation.GetDir())));
component.Stage = ExpeditionStage.Running;
+ Dirty(component);
}
private void OnFTLStarted(ref FTLStartedEvent ev)
@@ -158,6 +157,7 @@ public sealed partial class SalvageSystem
if (comp.Stage < ExpeditionStage.FinalCountdown && remaining < TimeSpan.FromSeconds(30))
{
comp.Stage = ExpeditionStage.FinalCountdown;
+ Dirty(comp);
Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-seconds", ("duration", TimeSpan.FromSeconds(30).Seconds)));
}
else if (comp.Stage < ExpeditionStage.MusicCountdown && remaining < TimeSpan.FromMinutes(2))
@@ -165,11 +165,13 @@ public sealed partial class SalvageSystem
// TODO: Some way to play audio attached to a map for players.
comp.Stream = _audio.PlayGlobal(comp.Sound, Filter.BroadcastMap(Comp(uid).MapId), true);
comp.Stage = ExpeditionStage.MusicCountdown;
+ Dirty(comp);
Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(2).Minutes)));
}
else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(5))
{
comp.Stage = ExpeditionStage.Countdown;
+ Dirty(comp);
Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(5).Minutes)));
}
// Auto-FTL out any shuttles
diff --git a/Content.Shared/Audio/SharedAmbientSoundSystem.cs b/Content.Shared/Audio/SharedAmbientSoundSystem.cs
index c54e9589b2..3bda37c634 100644
--- a/Content.Shared/Audio/SharedAmbientSoundSystem.cs
+++ b/Content.Shared/Audio/SharedAmbientSoundSystem.cs
@@ -1,66 +1,65 @@
using Robust.Shared.GameStates;
-namespace Content.Shared.Audio
+namespace Content.Shared.Audio;
+
+public abstract class SharedAmbientSoundSystem : EntitySystem
{
- public abstract class SharedAmbientSoundSystem : EntitySystem
+ public override void Initialize()
{
- public override void Initialize()
+ base.Initialize();
+ SubscribeLocalEvent(GetCompState);
+ SubscribeLocalEvent(HandleCompState);
+ }
+
+ public virtual void SetAmbience(EntityUid uid, bool value, AmbientSoundComponent? ambience = null)
+ {
+ if (!Resolve(uid, ref ambience, false) || ambience.Enabled == value)
+ return;
+
+ ambience.Enabled = value;
+ QueueUpdate(uid, ambience);
+ Dirty(ambience);
+ }
+
+ public virtual void SetRange(EntityUid uid, float value, AmbientSoundComponent? ambience = null)
+ {
+ if (!Resolve(uid, ref ambience, false) || MathHelper.CloseToPercent(ambience.Range, value))
+ return;
+
+ ambience.Range = value;
+ QueueUpdate(uid, ambience);
+ Dirty(ambience);
+ }
+
+ protected virtual void QueueUpdate(EntityUid uid, AmbientSoundComponent ambience)
+ {
+ // client side tree
+ }
+
+ public virtual void SetVolume(EntityUid uid, float value, AmbientSoundComponent? ambience = null)
+ {
+ if (!Resolve(uid, ref ambience, false) || MathHelper.CloseToPercent(ambience.Volume, value))
+ return;
+
+ ambience.Volume = value;
+ Dirty(ambience);
+ }
+
+ private void HandleCompState(EntityUid uid, AmbientSoundComponent component, ref ComponentHandleState args)
+ {
+ if (args.Current is not AmbientSoundComponentState state) return;
+ SetAmbience(uid, state.Enabled, component);
+ SetRange(uid, state.Range, component);
+ SetVolume(uid, state.Volume, component);
+ }
+
+ private void GetCompState(EntityUid uid, AmbientSoundComponent component, ref ComponentGetState args)
+ {
+ args.State = new AmbientSoundComponentState
{
- base.Initialize();
- SubscribeLocalEvent(GetCompState);
- SubscribeLocalEvent(HandleCompState);
- }
-
- public virtual void SetAmbience(EntityUid uid, bool value, AmbientSoundComponent? ambience = null)
- {
- if (!Resolve(uid, ref ambience, false) || ambience.Enabled == value)
- return;
-
- ambience.Enabled = value;
- QueueUpdate(uid, ambience);
- Dirty(ambience);
- }
-
- public virtual void SetRange(EntityUid uid, float value, AmbientSoundComponent? ambience = null)
- {
- if (!Resolve(uid, ref ambience, false) || MathHelper.CloseToPercent(ambience.Range, value))
- return;
-
- ambience.Range = value;
- QueueUpdate(uid, ambience);
- Dirty(ambience);
- }
-
- protected virtual void QueueUpdate(EntityUid uid, AmbientSoundComponent ambience)
- {
- // client side tree
- }
-
- public virtual void SetVolume(EntityUid uid, float value, AmbientSoundComponent? ambience = null)
- {
- if (!Resolve(uid, ref ambience, false) || MathHelper.CloseToPercent(ambience.Volume, value))
- return;
-
- ambience.Volume = value;
- Dirty(ambience);
- }
-
- private void HandleCompState(EntityUid uid, AmbientSoundComponent component, ref ComponentHandleState args)
- {
- if (args.Current is not AmbientSoundComponentState state) return;
- SetAmbience(uid, state.Enabled, component);
- SetRange(uid, state.Range, component);
- SetVolume(uid, state.Volume, component);
- }
-
- private void GetCompState(EntityUid uid, AmbientSoundComponent component, ref ComponentGetState args)
- {
- args.State = new AmbientSoundComponentState
- {
- Enabled = component.Enabled,
- Range = component.Range,
- Volume = component.Volume,
- };
- }
+ Enabled = component.Enabled,
+ Range = component.Range,
+ Volume = component.Volume,
+ };
}
}
diff --git a/Content.Shared/Salvage/Expeditions/ExpeditionStage.cs b/Content.Shared/Salvage/Expeditions/ExpeditionStage.cs
new file mode 100644
index 0000000000..a92d6c292a
--- /dev/null
+++ b/Content.Shared/Salvage/Expeditions/ExpeditionStage.cs
@@ -0,0 +1,10 @@
+namespace Content.Shared.Salvage.Expeditions;
+
+public enum ExpeditionStage : byte
+{
+ Added,
+ Running,
+ Countdown,
+ MusicCountdown,
+ FinalCountdown,
+}
\ No newline at end of file
diff --git a/Content.Shared/Salvage/SalvageExpeditions.cs b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs
similarity index 98%
rename from Content.Shared/Salvage/SalvageExpeditions.cs
rename to Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs
index bac0819d57..85894d86fb 100644
--- a/Content.Shared/Salvage/SalvageExpeditions.cs
+++ b/Content.Shared/Salvage/Expeditions/SalvageExpeditions.cs
@@ -1,10 +1,9 @@
-using Content.Shared.Salvage.Expeditions;
using Content.Shared.Salvage.Expeditions.Modifiers;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
-namespace Content.Shared.Salvage;
+namespace Content.Shared.Salvage.Expeditions;
[Serializable, NetSerializable]
public sealed class SalvageExpeditionConsoleState : BoundUserInterfaceState
diff --git a/Content.Shared/Salvage/Expeditions/SharedSalvageExpeditionComponent.cs b/Content.Shared/Salvage/Expeditions/SharedSalvageExpeditionComponent.cs
new file mode 100644
index 0000000000..5fa7fe05e9
--- /dev/null
+++ b/Content.Shared/Salvage/Expeditions/SharedSalvageExpeditionComponent.cs
@@ -0,0 +1,17 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Salvage.Expeditions;
+
+[NetworkedComponent]
+public abstract class SharedSalvageExpeditionComponent : Component
+{
+ [ViewVariables(VVAccess.ReadWrite), DataField("stage")]
+ public ExpeditionStage Stage = ExpeditionStage.Added;
+}
+
+[Serializable, NetSerializable]
+public sealed class SalvageExpeditionComponentState : ComponentState
+{
+ public ExpeditionStage Stage;
+}