6
2026-01-24 12:49:55 +03:00

175 lines
5.6 KiB
C#

using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Content.Shared._Horizon.Bark;
using Robust.Client.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Content.Shared._Horizon.CCVar;
using Robust.Client.Player;
using Robust.Shared.Timing;
using Robust.Shared.Map;
namespace Content.Client._Horizon.Bark;
public sealed class SpeechBarksSystem : SharedSpeechBarksSystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private const float MinimalVolume = -10f;
private const float WhisperFade = 4f;
private float _volume = 0.0f;
private List<ActiveBark> _activeBarks = new();
public override void Initialize()
{
base.Initialize();
_cfg.OnValueChanged(HorizonCCVars.BarksVolume, OnVolumeChanged, true);
SubscribeNetworkEvent<PlaySpeechBarksEvent>(OnEntitySpoke);
}
public override void Shutdown()
{
base.Shutdown();
_cfg.UnsubValueChanged(HorizonCCVars.BarksVolume, OnVolumeChanged);
}
private void OnVolumeChanged(float volume)
=> _volume = volume;
private float AdjustVolume(string message, bool isWhisper)
{
var volume = isWhisper ? _volume - WhisperFade : _volume;
if (message.EndsWith("!"))
volume += 1.5f;
return MinimalVolume + SharedAudioSystem.GainToVolume(volume);
}
private float AdjustDistance(bool isWhisper)
{
return isWhisper ? 5 : 10;
}
private async void OnEntitySpoke(PlaySpeechBarksEvent ev)
{
if (ev.Message == null)
return;
if (!TryGetEntity(ev.Source, out var source) || Transform(source.Value).MapID == MapId.Nullspace)
return;
var bark = new ActiveBark(source,
ev.Sound,
AdjustVolume(ev.Message, ev.IsWhisper),
ev.Pitch,
AdjustDistance(ev.IsWhisper),
(ev.LowVar, ev.HighVar),
ev.Message.Length / 3);
_activeBarks.Add(bark);
}
public async void PlayDataPrewiew(string protoId, float pitch, float lowVar, float highVar)
{
if (!_proto.TryIndex<BarkPrototype>(protoId, out var proto))
return;
var bark = new ActiveBark(null,
proto.Sound,
AdjustVolume("Test message", false),
pitch,
AdjustDistance(false),
(lowVar, highVar),
9);
_activeBarks.Add(bark);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
if (_player.LocalSession == null)
return;
for (var i = _activeBarks.Count - 1; i >= 0; i--)
{
var item = _activeBarks[i];
if (item.NextSound > _timing.CurTime)
continue;
if (item.BarksPlayed >= item.Length)
{
_activeBarks.Remove(item);
continue;
}
var pitch = _random.NextFloat(item.Pitch - 0.1f, item.Pitch + 0.1f);
var audioParams = AudioParams.Default.WithVolume(item.Volume).WithPitchScale(pitch);
item.BarksPlayed++;
item.NextSound = _timing.CurTime + TimeSpan.FromSeconds(_random.NextFloat(item.DelayVariation.Item1, item.DelayVariation.Item2));
if (item.HasSource != item.Source.HasValue)
{
_activeBarks.Remove(item);
continue;
}
if (item.Source == null)
{
_audio.PlayGlobal(_audio.ResolveSound(item.Sound), _player.LocalSession, audioParams);
continue;
}
if (_player.LocalEntity is { Valid: true } player)
{
if (item.Source == _player.LocalEntity)
_audio.PlayGlobal(_audio.ResolveSound(item.Sound), player, audioParams);
else
_audio.PlayEntity(_audio.ResolveSound(item.Sound), _player.LocalSession, item.Source.Value, audioParams);
}
else
{
_activeBarks.Remove(item);
continue;
}
}
}
private sealed class ActiveBark
{
public readonly EntityUid? Source;
public readonly SoundSpecifier Sound = default!;
public readonly float Volume = default!;
public readonly float Pitch = default!;
public readonly float Distance = default!;
public readonly (float, float) DelayVariation = default!;
public readonly int Length = default!;
public readonly bool HasSource;
public TimeSpan NextSound = TimeSpan.Zero;
public int BarksPlayed = 0;
public ActiveBark(EntityUid? source, SoundSpecifier sound, float volume, float pitch, float distance, (float, float) delay, int length)
{
Source = source;
HasSource = source.HasValue;
Sound = sound;
Volume = volume;
Pitch = pitch;
Distance = distance;
DelayVariation = delay;
Length = length;
}
}
}