From d090e98bd4916f8d4d0e402a3852a39c708258b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= <6766154+Zumorica@users.noreply.github.com> Date: Thu, 28 Mar 2019 14:31:49 +0100 Subject: [PATCH] [Ready] SoundComponent (#164) Requires https://github.com/space-wizards/space-station-14/pull/768 - [x] Play sounds - [x] SoundSchedules actually work - [x] Send sound to specific users - [x] Make existing components use SoundComponent - [x] Add ScheduledSounds from prototypes - [x] Add Play methods equivalent to those of AudioSystem. - [x] Document most code. --- Content.Client/Content.Client.csproj | 1 + Content.Client/EntryPoint.cs | 2 + .../Components/Sound/SoundComponent.cs | 109 +++++++++++++++ Content.Server/Content.Server.csproj | 1 + Content.Server/EntryPoint.cs | 2 + .../Construction/ConstructionComponent.cs | 23 ++-- .../Construction/ConstructorComponent.cs | 4 +- .../Components/Power/ApcComponent.cs | 6 +- .../Components/Power/PoweredLightComponent.cs | 4 +- .../Components/Sound/SoundComponent.cs | 72 ++++++++++ .../Ranged/Hitscan/HitscanWeaponComponent.cs | 5 +- .../BallisticMagazineWeaponComponent.cs | 12 +- .../Projectile/BallisticWeaponComponent.cs | 4 +- .../Ranged/Projectile/ProjectileWeapon.cs | 3 +- Content.Shared/Content.Shared.csproj | 3 +- .../Components/Sound/SharedSoundComponent.cs | 125 ++++++++++++++++++ Content.Shared/GameObjects/ContentNetIDs.cs | 1 + Resources/Prototypes/Entities/Lights.yml | 1 + Resources/Prototypes/Entities/Power.yml | 1 + Resources/Prototypes/Entities/Weapons.yml | 1 + .../Prototypes/Entities/weapons/guns.yml | 1 + 21 files changed, 350 insertions(+), 31 deletions(-) create mode 100644 Content.Client/GameObjects/Components/Sound/SoundComponent.cs create mode 100644 Content.Server/GameObjects/Components/Sound/SoundComponent.cs create mode 100644 Content.Shared/GameObjects/Components/Sound/SharedSoundComponent.cs diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj index 7e484e6eee..81c68a9997 100644 --- a/Content.Client/Content.Client.csproj +++ b/Content.Client/Content.Client.csproj @@ -84,6 +84,7 @@ + diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index ac22770bb2..cb53bb6d8a 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -26,6 +26,7 @@ using SS14.Shared.IoC; using SS14.Shared.Prototypes; using System; using Content.Client.GameObjects.Components.Mobs; +using Content.Client.GameObjects.Components.Sound; using Content.Client.UserInterface; using Content.Shared.GameObjects.Components.Markers; using Content.Shared.GameObjects.Components.Mobs; @@ -82,6 +83,7 @@ namespace Content.Client factory.Register(); factory.Register(); factory.Register(); + factory.Register(); factory.RegisterReference(); diff --git a/Content.Client/GameObjects/Components/Sound/SoundComponent.cs b/Content.Client/GameObjects/Components/Sound/SoundComponent.cs new file mode 100644 index 0000000000..6dc1d362bb --- /dev/null +++ b/Content.Client/GameObjects/Components/Sound/SoundComponent.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.Sound; +using SS14.Client.GameObjects.EntitySystems; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.Interfaces.Network; +using SS14.Shared.Interfaces.Timers; +using SS14.Shared.IoC; +using SS14.Shared.Log; +using SS14.Shared.Serialization; +using SS14.Shared.Timers; + +namespace Content.Client.GameObjects.Components.Sound +{ + public class SoundComponent : SharedSoundComponent + { + private readonly List _schedules = new List(); + private AudioSystem _audioSystem; + private Random Random; + + public override void StopAllSounds() + { + foreach (var schedule in _schedules) + { + schedule.Play = false; + } + _schedules.Clear(); + } + + public override void StopScheduledSound(string filename) + { + foreach (var schedule in _schedules.ToArray()) + { + if (schedule.Filename != filename) continue; + schedule.Play = false; + _schedules.Remove(schedule); + } + } + + public override void AddScheduledSound(ScheduledSound schedule) + { + _schedules.Add(schedule); + Play(schedule); + } + + public void Play(ScheduledSound schedule) + { + if (!schedule.Play) return; + if (Random == null) Random = new Random(Owner.Uid.GetHashCode() ^ DateTime.Now.GetHashCode()); + + Timer.Spawn((int) schedule.Delay + (Random.Next((int) schedule.RandomDelay)),() => + { + if (!schedule.Play) return; // We make sure this hasn't changed. + if (_audioSystem == null) _audioSystem = IoCManager.Resolve().GetEntitySystem(); + _audioSystem.Play(schedule.Filename, Owner, schedule.AudioParams); + + if (schedule.Times == 0) + { + _schedules.Remove(schedule); + return; + } + + if (schedule.Times > 0) + schedule.Times--; + + Play(schedule); + }); + } + + public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null) + { + base.HandleMessage(message, netChannel, component); + switch (message) + { + case ScheduledSoundMessage msg: + AddScheduledSound(msg.Schedule); + break; + + case StopSoundScheduleMessage msg: + StopScheduledSound(msg.Filename); + break; + + case StopAllSoundsMessage msg: + StopAllSounds(); + break; + } + } + + public override void Initialize() + { + base.Initialize(); + IoCManager.Resolve().TryGetEntitySystem(out _audioSystem); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + if (serializer.Writing) return; + serializer.TryReadDataField("schedules", out List schedules); + if (schedules == null) return; + foreach (var schedule in schedules) + { + if (schedule == null) continue; + AddScheduledSound(schedule); + } + } + } +} diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj index 1896fea3d9..aa5e33e006 100644 --- a/Content.Server/Content.Server.csproj +++ b/Content.Server/Content.Server.csproj @@ -99,6 +99,7 @@ + diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index ad1855b06e..96c671a4b3 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -35,6 +35,7 @@ using Content.Server.Mobs; using Content.Server.Players; using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Markers; +using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.Components.Weapon.Ranged; using Content.Server.GameTicking; using Content.Server.Interfaces; @@ -107,6 +108,7 @@ namespace Content.Server factory.Register(); factory.Register(); + factory.Register(); factory.Register(); diff --git a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs index 0118f01143..8ea9badc00 100644 --- a/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs +++ b/Content.Server/GameObjects/Components/Construction/ConstructionComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Content.Server.GameObjects.Components.Interactable.Tools; +using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Construction; @@ -28,7 +29,6 @@ namespace Content.Server.GameObjects.Components.Construction SpriteComponent Sprite; ITransformComponent Transform; - AudioSystem AudioSystem; Random random; public override void Initialize() @@ -38,7 +38,6 @@ namespace Content.Server.GameObjects.Components.Construction Sprite = Owner.GetComponent(); Transform = Owner.GetComponent(); var systemman = IoCManager.Resolve(); - AudioSystem = systemman.GetEntitySystem(); random = new Random(); } @@ -95,6 +94,8 @@ namespace Content.Server.GameObjects.Components.Construction bool TryProcessStep(ConstructionStep step, IEntity slapped) { + var sound = IoCManager.Resolve().GetEntitySystem(); + switch (step) { case ConstructionStepMaterial matStep: @@ -105,9 +106,9 @@ namespace Content.Server.GameObjects.Components.Construction return false; } if (matStep.Material == MaterialType.Cable) - AudioSystem.Play("/Audio/items/zip.ogg", Transform.GridPosition); + sound.Play("/Audio/items/zip.ogg", Transform.GridPosition); else - AudioSystem.Play("/Audio/items/deconstruct.ogg", Transform.GridPosition); + sound.Play("/Audio/items/deconstruct.ogg", Transform.GridPosition); return true; case ConstructionStepTool toolStep: switch (toolStep.Tool) @@ -115,7 +116,7 @@ namespace Content.Server.GameObjects.Components.Construction case ToolType.Crowbar: if (slapped.HasComponent()) { - AudioSystem.Play("/Audio/items/crowbar.ogg", Transform.GridPosition); + sound.Play("/Audio/items/crowbar.ogg", Transform.GridPosition); return true; } return false; @@ -123,16 +124,16 @@ namespace Content.Server.GameObjects.Components.Construction if (slapped.TryGetComponent(out WelderComponent welder) && welder.TryUse(toolStep.Amount)) { if (random.NextDouble() > 0.5) - AudioSystem.Play("/Audio/items/welder.ogg", Transform.GridPosition); + sound.Play("/Audio/items/welder.ogg", Transform.GridPosition); else - AudioSystem.Play("/Audio/items/welder2.ogg", Transform.GridPosition); + sound.Play("/Audio/items/welder2.ogg", Transform.GridPosition); return true; } return false; case ToolType.Wrench: if (slapped.HasComponent()) { - AudioSystem.Play("/Audio/items/ratchet.ogg", Transform.GridPosition); + sound.Play("/Audio/items/ratchet.ogg", Transform.GridPosition); return true; } return false; @@ -140,16 +141,16 @@ namespace Content.Server.GameObjects.Components.Construction if (slapped.HasComponent()) { if (random.NextDouble() > 0.5) - AudioSystem.Play("/Audio/items/screwdriver.ogg", Transform.GridPosition); + sound.Play("/Audio/items/screwdriver.ogg", Transform.GridPosition); else - AudioSystem.Play("/Audio/items/screwdriver2.ogg", Transform.GridPosition); + sound.Play("/Audio/items/screwdriver2.ogg", Transform.GridPosition); return true; } return false; case ToolType.Wirecutters: if (slapped.HasComponent()) { - AudioSystem.Play("/Audio/items/wirecutter.ogg", Transform.GridPosition); + sound.Play("/Audio/items/wirecutter.ogg", Transform.GridPosition); return true; } return false; diff --git a/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs b/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs index f074411855..824994ed42 100644 --- a/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs +++ b/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Content.Server.GameObjects.Components.Materials; +using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.Components.Stack; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Construction; @@ -75,8 +76,7 @@ namespace Content.Server.GameObjects.Components.Construction // OK WE'RE GOOD CONSTRUCTION STARTED. var entMgr = IoCManager.Resolve(); - var AudioSystem = IoCManager.Resolve().GetEntitySystem(); - AudioSystem.Play("/Audio/items/deconstruct.ogg", loc); + IoCManager.Resolve().GetEntitySystem().Play("/Audio/items/deconstruct.ogg", loc); if (prototype.Stages.Count == 2) { // Exactly 2 stages, so don't make an intermediate frame. diff --git a/Content.Server/GameObjects/Components/Power/ApcComponent.cs b/Content.Server/GameObjects/Components/Power/ApcComponent.cs index 2cc349714c..e8d32c9279 100644 --- a/Content.Server/GameObjects/Components/Power/ApcComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.Components.Sound; +using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Power; using SS14.Server.GameObjects; using SS14.Server.GameObjects.Components.UserInterface; @@ -118,8 +119,7 @@ namespace Content.Server.GameObjects.Components.Power private void _clickSound() { - IoCManager.Resolve().GetEntitySystem() - .Play("/Audio/machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f)); + Owner.GetComponent().Play("/Audio/machines/machine_switch.ogg", AudioParams.Default.WithVolume(-2f)); } } } diff --git a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs index 8fa309f15d..74e168398a 100644 --- a/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PoweredLightComponent.cs @@ -1,4 +1,5 @@ using System; +using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects; @@ -150,8 +151,7 @@ namespace Content.Server.GameObjects.Components.Power if (time > _lastThunk + _thunkDelay) { _lastThunk = time; - IoCManager.Resolve().GetEntitySystem() - .Play("/Audio/machines/light_tube_on.ogg", Owner, AudioParams.Default.WithVolume(-10f)); + Owner.GetComponent().Play("/Audio/machines/light_tube_on.ogg", AudioParams.Default.WithVolume(-10f)); } } else diff --git a/Content.Server/GameObjects/Components/Sound/SoundComponent.cs b/Content.Server/GameObjects/Components/Sound/SoundComponent.cs new file mode 100644 index 0000000000..5045dbe48d --- /dev/null +++ b/Content.Server/GameObjects/Components/Sound/SoundComponent.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.Sound; +using SS14.Server.GameObjects.EntitySystems; +using SS14.Shared.Audio; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.Interfaces.Network; +using SS14.Shared.Log; +using SS14.Shared.Map; +using SS14.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.Sound +{ + public class SoundComponent : SharedSoundComponent + { + /// + /// Stops all sounds. + /// + /// User that will be affected. + public void StopAllSounds(INetChannel channel) + { + SendNetworkMessage(new StopAllSoundsMessage(), channel); + } + + /// + /// Stops a certain scheduled sound from playing. + /// + /// User that will be affected. + public void StopScheduledSound(string filename, INetChannel channel) + { + SendNetworkMessage(new StopSoundScheduleMessage(){Filename = filename}, channel); + } + + /// + /// Adds an scheduled sound to be played. + /// + /// User that will be affected. + public void AddScheduledSound(ScheduledSound schedule, INetChannel channel) + { + SendNetworkMessage(new ScheduledSoundMessage() {Schedule = schedule}, channel); + } + + public override void StopAllSounds() + { + StopAllSounds(null); + } + + public override void StopScheduledSound(string filename) + { + StopScheduledSound(filename, null); + } + + public override void AddScheduledSound(ScheduledSound schedule) + { + AddScheduledSound(schedule, null); + } + + /// + /// Play an audio file following the entity. + /// + /// The resource path to the OGG Vorbis file to play. + /// User that will be affected. + public void Play(string filename, AudioParams? audioParams = null, INetChannel channel = null) + { + AddScheduledSound(new ScheduledSound() + { + Filename = filename, + AudioParams = audioParams, + }, channel); + } + } +} diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs index 2fa08b8f28..b876d4e08c 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Hitscan/HitscanWeaponComponent.cs @@ -12,7 +12,8 @@ using SS14.Shared.Maths; using SS14.Shared.Physics; using SS14.Shared.Serialization; using System; -using SS14.Shared.GameObjects; + using Content.Server.GameObjects.Components.Sound; + using SS14.Shared.GameObjects; namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan { @@ -81,7 +82,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Hitscan }; var mgr = IoCManager.Resolve(); mgr.GetEntitySystem().CreateParticle(message); - mgr.GetEntitySystem().Play("/Audio/laser.ogg", Owner, AudioParams.Default.WithVolume(-5)); + Owner.GetComponent().Play("/Audio/laser.ogg", AudioParams.Default.WithVolume(-5)); } } } diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs index 497bc80434..e319ae3d75 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticMagazineWeaponComponent.cs @@ -1,4 +1,5 @@ using System; +using Content.Server.GameObjects.Components.Sound; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; using Content.Shared.GameObjects.Components.Weapons.Ranged; @@ -110,8 +111,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile if (_magInSound != null) { - var audioSystem = IoCManager.Resolve().GetEntitySystem(); - audioSystem.Play(_magInSound, Owner); + Owner.GetComponent().Play(_magInSound); } component.OnAmmoCountChanged += _magazineAmmoCountChanged; @@ -142,8 +142,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile entity.Transform.GridPosition = Owner.Transform.GridPosition; if (_magOutSound != null) { - var audioSystem = IoCManager.Resolve().GetEntitySystem(); - audioSystem.Play(_magOutSound, Owner); + Owner.GetComponent().Play(_magOutSound); } _updateAppearance(); @@ -163,9 +162,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile var entity = RemoveFromChamber(chamber); entity.Transform.GridPosition = Owner.Transform.GridPosition; entity.Transform.LocalRotation = _bulletDropRandom.Pick(_randomBulletDirs).ToAngle(); - var audioSystem = IoCManager.Resolve().GetEntitySystem(); var effect = $"/Audio/items/weapons/casingfall{_bulletDropRandom.Next(1, 4)}.ogg"; - audioSystem.Play(effect, entity, AudioParams.Default.WithVolume(-3)); + Owner.GetComponent().Play(effect, AudioParams.Default.WithVolume(-3)); if (Magazine != null) { @@ -181,7 +179,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile EjectMagazine(); if (_autoEjectSound != null) { - audioSystem.Play(_autoEjectSound, Owner, AudioParams.Default.WithVolume(-5)); + Owner.GetComponent().Play(_autoEjectSound, AudioParams.Default.WithVolume(-5)); } } } diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticWeaponComponent.cs index cb23dd4e0e..2c1c9fa3c6 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/BallisticWeaponComponent.cs @@ -1,5 +1,6 @@ using System; using Content.Server.GameObjects.Components.Interactable; +using Content.Server.GameObjects.Components.Sound; using Content.Shared.GameObjects; using SS14.Server.Chat; using SS14.Server.GameObjects.Components.Container; @@ -69,8 +70,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile { if (_soundGunEmpty != null) { - var audioSystem = IoCManager.Resolve().GetEntitySystem(); - audioSystem.Play(_soundGunEmpty, Owner); + Owner.GetComponent().Play(_soundGunEmpty); } } var chambered = GetChambered(0); diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/ProjectileWeapon.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/ProjectileWeapon.cs index 9fa5d127f4..0e1de9a103 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/ProjectileWeapon.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Projectile/ProjectileWeapon.cs @@ -1,6 +1,7 @@ using System; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Projectiles; +using Content.Server.GameObjects.Components.Sound; using SS14.Server.GameObjects; using SS14.Server.GameObjects.EntitySystems; using SS14.Server.Interfaces.GameObjects; @@ -90,7 +91,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Projectile projectile.Transform.LocalRotation = angle.Theta; // Sound! - IoCManager.Resolve().GetEntitySystem().Play("/Audio/gunshot_c20.ogg", user); + Owner.GetComponent().Play("/Audio/gunshot_c20.ogg"); } /// diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj index 93f267c422..c8c3c80e4e 100644 --- a/Content.Shared/Content.Shared.csproj +++ b/Content.Shared/Content.Shared.csproj @@ -72,6 +72,7 @@ + @@ -126,4 +127,4 @@ - + \ No newline at end of file diff --git a/Content.Shared/GameObjects/Components/Sound/SharedSoundComponent.cs b/Content.Shared/GameObjects/Components/Sound/SharedSoundComponent.cs new file mode 100644 index 0000000000..67b9b9fe8e --- /dev/null +++ b/Content.Shared/GameObjects/Components/Sound/SharedSoundComponent.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Content.Shared.GameObjects; +using SS14.Shared.Audio; +using SS14.Shared.GameObjects; +using SS14.Shared.Interfaces.GameObjects; +using SS14.Shared.Interfaces.Serialization; +using SS14.Shared.IoC; +using SS14.Shared.Map; +using SS14.Shared.Serialization; +using SS14.Shared.Timers; + +namespace Content.Shared.GameObjects.Components.Sound +{ + public class SharedSoundComponent : Component + { + public override string Name => "Sound"; + public override uint? NetID => ContentNetIDs.SOUND; + + /// + /// Stops all sounds. + /// + public virtual void StopAllSounds() + {} + + /// + /// Stops a certain scheduled sound from playing. + /// + public virtual void StopScheduledSound(string filename) + {} + + /// + /// Adds an scheduled sound to be played. + /// + public virtual void AddScheduledSound(ScheduledSound scheduledSound) + {} + + /// + /// Play an audio file following the entity. + /// + /// The resource path to the OGG Vorbis file to play. + public void Play(string filename, AudioParams? audioParams = null) + { + AddScheduledSound(new ScheduledSound() + { + Filename = filename, + AudioParams = audioParams, + }); + } + } + + [NetSerializable, Serializable] + public class ScheduledSoundMessage : ComponentMessage + { + public ScheduledSound Schedule; + public ScheduledSoundMessage() + { + Directed = true; + } + } + + [NetSerializable, Serializable] + public class StopSoundScheduleMessage : ComponentMessage + { + public string Filename; + public StopSoundScheduleMessage() + { + Directed = true; + } + } + + [NetSerializable, Serializable] + public class StopAllSoundsMessage : ComponentMessage + { + public StopAllSoundsMessage() + { + Directed = true; + } + } + + [Serializable, NetSerializable] + public class ScheduledSound : IExposeData + { + public string Filename = ""; + + /// + /// The parameters to play the sound with. + /// + public AudioParams? AudioParams; + + /// + /// Delay in milliseconds before playing the sound, + /// and delay between repetitions if Times is not 0. + /// + public uint Delay = 0; + + /// + /// Maximum number of milliseconds to add to the delay randomly. + /// Useful for random ambience noises. Generated value differs from client to client. + /// + public uint RandomDelay = 0; + + /// + /// How many times to repeat the sound. If it's 0, it will play the sound once. + /// If it's less than 0, it will repeat the sound indefinitely. + /// If it's greater than 0, it will play the sound n+1 times. + /// + public int Times = 0; + + /// + /// Whether the sound will play or not. + /// + public bool Play = true; + + public void ExposeData(ObjectSerializer serializer) + { + Filename = serializer.ReadDataField("filename", ""); + Delay = serializer.ReadDataField("delay", 0u); + RandomDelay = serializer.ReadDataField("randomdelay", 0u); + Times = serializer.ReadDataField("times", 0); + AudioParams = serializer.ReadDataField("audioparams", SS14.Shared.Audio.AudioParams.Default); + } + } +} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index 14871ceb3f..cffb1f54b4 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -14,5 +14,6 @@ public const uint SPECIES = 1009; public const uint RANGED_WEAPON = 1010; public const uint CAMERA_RECOIL = 1011; + public const uint SOUND = 1012; } } diff --git a/Resources/Prototypes/Entities/Lights.yml b/Resources/Prototypes/Entities/Lights.yml index fbcf4e8ac2..7a94c3f73d 100644 --- a/Resources/Prototypes/Entities/Lights.yml +++ b/Resources/Prototypes/Entities/Lights.yml @@ -4,6 +4,7 @@ components: - type: Clickable - type: BoundingBox + - type: Sound - type: Sprite sprite: Buildings/light_tube.rsi state: on diff --git a/Resources/Prototypes/Entities/Power.yml b/Resources/Prototypes/Entities/Power.yml index 7487ddadd2..94dc3a0533 100644 --- a/Resources/Prototypes/Entities/Power.yml +++ b/Resources/Prototypes/Entities/Power.yml @@ -95,6 +95,7 @@ type: ApcBoundUserInterface - type: BoundingBox aabb: -0.25, -0.25, 0.25, 0.3 + - type: Sound - type: entity id: SMES diff --git a/Resources/Prototypes/Entities/Weapons.yml b/Resources/Prototypes/Entities/Weapons.yml index fe9adcf64d..e7432c623b 100644 --- a/Resources/Prototypes/Entities/Weapons.yml +++ b/Resources/Prototypes/Entities/Weapons.yml @@ -18,6 +18,7 @@ Size: 24 sprite: Objects/laser_retro.rsi prefix: 100 + - type: Sound - type: entity name: Spear diff --git a/Resources/Prototypes/Entities/weapons/guns.yml b/Resources/Prototypes/Entities/weapons/guns.yml index fc9f855527..686ade94a9 100644 --- a/Resources/Prototypes/Entities/weapons/guns.yml +++ b/Resources/Prototypes/Entities/weapons/guns.yml @@ -11,6 +11,7 @@ - type: Icon sprite: Objects/c20r.rsi state: c20r-5 + - type: Sound - type: RangedWeapon automatic: true firerate: 8