forked from space-syndicate/space-station-14
From ss14-wega (_Wega): - DeleteOnDrop: auto-delete items when dropped - FriendlyFaction: prevent friendly fire by faction - NullRod: holy weapon that removes magic - EdibleMatter: edible entity component - Ghost Respawn: allow ghosts to respawn to lobby - Barks: NPC voice sounds system (99 audio files) From ss14-wl (_WL): - Day/Night Cycle: automatic lighting cycle for maps - Sleep on Buckle: sleep action when buckled - Height System: tall entities become large items - Freeze Component: freeze entities at high cold damage - Suckable Food: mouth-slot consumables (lollipops, gum, etc.) - GolemHeat: bonus feature (heat mechanics for golems) Includes: - 34 C# files - 99 audio files - 68 texture files - 9 prototype files - 2 locale files - WegaCVars configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
105 lines
3.8 KiB
C#
105 lines
3.8 KiB
C#
using Content.Client.Audio;
|
|
using Content.Shared.CCVar;
|
|
using Content.Shared.Chat;
|
|
using Content.Shared.Speech.Synthesis;
|
|
using Robust.Client.Audio;
|
|
using Robust.Client.ResourceManagement;
|
|
using Robust.Client.Player;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.Audio.Systems;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Utility;
|
|
using Content.Shared.SoundInsolation;
|
|
|
|
namespace Content.Client.Speech.Synthesis.System;
|
|
|
|
/// <summary>
|
|
/// Система отвечающая за прогрышь звука для каждого калиента
|
|
/// </summary>
|
|
public sealed class BarkSystem : EntitySystem
|
|
{
|
|
[Dependency] private readonly AudioSystem _audio = default!;
|
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
[Dependency] private readonly IPlayerManager _player = default!;
|
|
[Dependency] private readonly SoundInsulationSystem _soundInsulation = default!;
|
|
|
|
private const float MinimalVolume = -10f;
|
|
private const float WhisperFade = 4f;
|
|
|
|
public override void Initialize()
|
|
{
|
|
SubscribeNetworkEvent<PlayBarkEvent>(OnPlayBark);
|
|
}
|
|
|
|
public void RequestPreviewBark(string barkVoiceId)
|
|
{
|
|
RaiseNetworkEvent(new RequestPreviewBarkEvent(barkVoiceId));
|
|
}
|
|
|
|
private void OnPlayBark(PlayBarkEvent ev)
|
|
{
|
|
var sourceEntity = _entityManager.GetEntity(ev.SourceUid);
|
|
if (!_entityManager.EntityExists(sourceEntity) || _entityManager.Deleted(sourceEntity) || !HasComp<TransformComponent>(sourceEntity))
|
|
return;
|
|
|
|
float volumeMultiplier = 1f;
|
|
if (_player.LocalEntity != null && HasComp<TransformComponent>(_player.LocalEntity.Value))
|
|
{
|
|
var sourceTransform = Transform(sourceEntity);
|
|
var playerTransform = Transform(_player.LocalEntity.Value);
|
|
|
|
if (sourceTransform.Coordinates.TryDistance(EntityManager, playerTransform.Coordinates, out var distance) &&
|
|
distance > SharedChatSystem.VoiceRange)
|
|
return;
|
|
|
|
var insulation = _soundInsulation.GetSoundInsulation(sourceEntity, _player.LocalEntity.Value);
|
|
if (insulation >= 0.95f)
|
|
return;
|
|
|
|
if (insulation > 0.1f && insulation < 0.95f)
|
|
{
|
|
volumeMultiplier = 1f - MathHelper.Lerp(0.1f, 0.9f, insulation);
|
|
volumeMultiplier = Math.Clamp(volumeMultiplier, 0.1f, 0.9f);
|
|
}
|
|
}
|
|
|
|
var userVolume = _cfg.GetCVar(WegaCVars.BarksVolume);
|
|
var baseVolume = SharedAudioSystem.GainToVolume(userVolume * ContentAudioSystem.BarksMultiplier);
|
|
|
|
float volume = MinimalVolume + baseVolume * volumeMultiplier;
|
|
if (ev.Obfuscated)
|
|
volume -= WhisperFade;
|
|
|
|
var audioParams = new AudioParams
|
|
{
|
|
Volume = volume,
|
|
Variation = 0.125f
|
|
};
|
|
|
|
int messageLength = ev.Message.Length;
|
|
float totalDuration = messageLength * 0.05f;
|
|
float soundInterval = 0.15f / ev.PlaybackSpeed;
|
|
|
|
int soundCount = (int)(totalDuration / soundInterval);
|
|
soundCount = Math.Max(soundCount, 1);
|
|
|
|
var audioResource = new AudioResource();
|
|
audioResource.Load(IoCManager.Instance!, new ResPath(ev.SoundPath));
|
|
|
|
var soundSpecifier = new ResolvedPathSpecifier(ev.SoundPath);
|
|
|
|
for (int i = 0; i < soundCount; i++)
|
|
{
|
|
Timer.Spawn(TimeSpan.FromSeconds(i * soundInterval), () =>
|
|
{
|
|
if (!_entityManager.EntityExists(sourceEntity) || _entityManager.Deleted(sourceEntity))
|
|
return;
|
|
|
|
_audio.PlayEntity(audioResource.AudioStream, sourceEntity, soundSpecifier, audioParams);
|
|
});
|
|
}
|
|
}
|
|
}
|