diff --git a/Content.Server/Speech/SpeechNoiseSystem.cs b/Content.Server/Speech/SpeechNoiseSystem.cs new file mode 100644 index 0000000000..d85c4e6d35 --- /dev/null +++ b/Content.Server/Speech/SpeechNoiseSystem.cs @@ -0,0 +1,80 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Audio; +using Content.Server.Chat; +using Content.Shared.Speech; +using Content.Shared.Sound; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using System; + +namespace Content.Server.Speech +{ + public sealed class SpeechSoundSystem : EntitySystem + { + + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnEntitySpoke); + SubscribeLocalEvent(OnStartup); + } + + private void OnStartup(EntityUid uid, SharedSpeechComponent component, ComponentStartup args) + { + //Cache prototype on component startup. + if (_proto.TryIndex(component.SpeechSoundsId, out SpeechSoundsPrototype? speechsnds)) + { + if (speechsnds != null) + { + component.SpeechSoundsCache = speechsnds; + } + } + } + + + private void OnEntitySpoke(EntityUid uid, SharedSpeechComponent component, EntitySpokeEvent args) + { + if (!component.PlaySpeechSound) return; + var cooldown = TimeSpan.FromSeconds(component.SoundCooldownTime); + //Ensure more than the cooldown time has passed since last speaking + if ((_gameTiming.CurTime - component.LastTimeSoundPlayed) < cooldown) return; + + //Play speech sound + + if (component.SpeechSoundsCache != null) + { + //Re-Index sounds prototype if cached proto ID is outdated, allows VV and changing the voice. + if (component.SpeechSoundsCache.ID != component.SpeechSoundsId) + { + if (_proto.TryIndex(component.SpeechSoundsId, out SpeechSoundsPrototype? speechsnds)) + { + if (speechsnds != null) + { + component.SpeechSoundsCache = speechsnds; + } + } + } + var contextSound = component.SpeechSoundsCache.SaySound; + //Different sounds for ask/exclaim based on last character + switch (args.Message[args.Message.Length-1]) + { + case '?': + contextSound = component.SpeechSoundsCache.AskSound; + break; + case '!': + contextSound = component.SpeechSoundsCache.ExclaimSound; + break; + + } + component.LastTimeSoundPlayed = _gameTiming.CurTime; + SoundSystem.Play(Filter.Pvs(uid), contextSound.GetSound(), uid, component.AudioParams); + } + } + + } +} diff --git a/Content.Shared/Speech/SharedSpeechComponent.cs b/Content.Shared/Speech/SharedSpeechComponent.cs index d42e922562..9c28936dc2 100644 --- a/Content.Shared/Speech/SharedSpeechComponent.cs +++ b/Content.Shared/Speech/SharedSpeechComponent.cs @@ -1,10 +1,18 @@ using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Audio; +using Content.Shared.Sound; +using Content.Shared.Speech; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using System; namespace Content.Shared.Speech { /// - /// Component required for entities to be able to speak. + /// Component required for entities to be able to speak. (TODO: Entities can speak fine without this, this only forbids them speak if they have it and enabled is false.) + /// Contains the option to let entities make noise when speaking, datafields for the sounds in question, and relevant AudioParams. /// [RegisterComponent] public sealed class SharedSpeechComponent : Component @@ -12,6 +20,29 @@ namespace Content.Shared.Speech [DataField("enabled")] private bool _enabled = true; + [ViewVariables(VVAccess.ReadWrite)] + [DataField("playSpeechSound")] + public bool PlaySpeechSound = false; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("speechSoundsId", customTypeSerializer:typeof(PrototypeIdSerializer))] + public string SpeechSoundsId { get; set; } = "Alto"; + + [DataField("audioParams")] + public AudioParams AudioParams = AudioParams.Default.WithVolume(5f); + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("soundCooldownTime")] + public float SoundCooldownTime { get; set; } = 0.5f; + + public TimeSpan LastTimeSoundPlayed = TimeSpan.Zero; + + //Don't use this. + //Cache for SpeechSoundsPrototype to avoid Indexing every single time someone talks. + public SpeechSoundsPrototype? SpeechSoundsCache = null; + + + public bool Enabled { get => _enabled; diff --git a/Content.Shared/Speech/SpeechSoundsPrototype.cs b/Content.Shared/Speech/SpeechSoundsPrototype.cs new file mode 100644 index 0000000000..1e3bafb69a --- /dev/null +++ b/Content.Shared/Speech/SpeechSoundsPrototype.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; +using Robust.Shared.Audio; +using Content.Shared.Sound; + +namespace Content.Shared.Speech +{ + [Prototype("speechSounds")] + public sealed class SpeechSoundsPrototype : IPrototype + { + [ViewVariables] + [IdDataFieldAttribute] + public string ID { get; } = default!; + + [DataField("saySound")] + public SoundSpecifier SaySound { get; set; } = new SoundPathSpecifier("/Audio/Voice/Talk/speak_2.ogg"); + + [DataField("askSound")] + public SoundSpecifier AskSound { get; set; } = new SoundPathSpecifier("/Audio/Voice/Talk/speak_2_ask.ogg"); + + [DataField("exclaimSound")] + public SoundSpecifier ExclaimSound { get; set; } = new SoundPathSpecifier("/Audio/Voice/Talk/speak_2_exclaim.ogg"); + } +} diff --git a/Resources/Audio/Machines/vending_jingle.ogg b/Resources/Audio/Machines/vending_jingle.ogg new file mode 100644 index 0000000000..548aa2a1f4 Binary files /dev/null and b/Resources/Audio/Machines/vending_jingle.ogg differ diff --git a/Resources/Audio/Voice/Talk/license.txt b/Resources/Audio/Voice/Talk/license.txt new file mode 100644 index 0000000000..e9e7b8134c --- /dev/null +++ b/Resources/Audio/Voice/Talk/license.txt @@ -0,0 +1,15 @@ +speak_1_ask.ogg +speak_1_exclaim.ogg +speak_1.ogg +speak_2_ask.ogg +speak_2_exclaim.ogg +speak_2.ogg +speak_3_ask.ogg +speak_3_exclaim.ogg +speak_3.ogg +speak_4_ask.ogg +speak_4_exclaim.ogg +speak_4.ogg +all taken from +https://github.com/goonstation/goonstation/tree/master/sound/misc/talk +licensed under CC BY-NC-SA 3.0 diff --git a/Resources/Audio/Voice/Talk/speak_1.ogg b/Resources/Audio/Voice/Talk/speak_1.ogg new file mode 100644 index 0000000000..ab8ddde4a6 Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_1.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_1_ask.ogg b/Resources/Audio/Voice/Talk/speak_1_ask.ogg new file mode 100644 index 0000000000..89d631c6f6 Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_1_ask.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_1_exclaim.ogg b/Resources/Audio/Voice/Talk/speak_1_exclaim.ogg new file mode 100644 index 0000000000..3be20fef39 Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_1_exclaim.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_2.ogg b/Resources/Audio/Voice/Talk/speak_2.ogg new file mode 100644 index 0000000000..a8c9444a52 Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_2.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_2_ask.ogg b/Resources/Audio/Voice/Talk/speak_2_ask.ogg new file mode 100644 index 0000000000..a2c9c86385 Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_2_ask.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_2_exclaim.ogg b/Resources/Audio/Voice/Talk/speak_2_exclaim.ogg new file mode 100644 index 0000000000..7e0838d721 Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_2_exclaim.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_3.ogg b/Resources/Audio/Voice/Talk/speak_3.ogg new file mode 100644 index 0000000000..33ec079b84 Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_3.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_3_ask.ogg b/Resources/Audio/Voice/Talk/speak_3_ask.ogg new file mode 100644 index 0000000000..13156c332e Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_3_ask.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_3_exclaim.ogg b/Resources/Audio/Voice/Talk/speak_3_exclaim.ogg new file mode 100644 index 0000000000..e10eb615b0 Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_3_exclaim.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_4.ogg b/Resources/Audio/Voice/Talk/speak_4.ogg new file mode 100644 index 0000000000..6de26114ae Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_4.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_4_ask.ogg b/Resources/Audio/Voice/Talk/speak_4_ask.ogg new file mode 100644 index 0000000000..76421d8fdd Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_4_ask.ogg differ diff --git a/Resources/Audio/Voice/Talk/speak_4_exclaim.ogg b/Resources/Audio/Voice/Talk/speak_4_exclaim.ogg new file mode 100644 index 0000000000..ae6f3985be Binary files /dev/null and b/Resources/Audio/Voice/Talk/speak_4_exclaim.ogg differ diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index d7db9e3140..31f6fd4179 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -17,6 +17,8 @@ state: bat sprite: Mobs/Animals/bat.rsi - type: Physics + - type: Speech + speechSoundsId: Squeak - type: Fixtures fixtures: - shape: @@ -663,6 +665,9 @@ makeSentient: true name: mouse description: A hungry and mischievous mouse. + - type: Speech + playSpeechSound: true + speechSoundsId: Squeak - type: Sprite drawdepth: FloorObjects layers: diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index af233d5754..fb6a072c5e 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -309,6 +309,7 @@ # - type: Recyclable Turns out turning off recycler safeties without considering the instagib is a bad idea # safe: false - type: Speech + playSpeechSound: true - type: Vocal - type: Emoting - type: Grammar @@ -414,7 +415,7 @@ - map: [ "pocket2" ] - map: ["hand-left"] - map: ["hand-right"] - - type: Markings + - type: Markings - type: Physics bodyType: Dynamic - type: Fixtures diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 5f6dcc2dd3..3bbe8f5d6a 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -52,6 +52,9 @@ BoardName: "Vending Machine" LayoutId: Vending - type: Anchorable + - type: Speech + playSpeechSound: true + speechSoundsId: Vending - type: DoAfter - type: Electrified enabled: false @@ -156,7 +159,7 @@ energy: 1.3 color: "#ffb0b0" - type: AccessReader - access: [["HeadOfPersonnel"]] + access: [["HeadOfPersonnel"]] - type: entity parent: VendingMachine diff --git a/Resources/Prototypes/Voice/speech_sounds.yml b/Resources/Prototypes/Voice/speech_sounds.yml new file mode 100644 index 0000000000..9a5d411d91 --- /dev/null +++ b/Resources/Prototypes/Voice/speech_sounds.yml @@ -0,0 +1,54 @@ +- type: speechSounds + id: Bass + saySound: + path: /Audio/Voice/Talk/speak_4.ogg + askSound: + path: /Audio/Voice/Talk/speak_4_ask.ogg + exclaimSound: + path: /Audio/Voice/Talk/speak_4_exclaim.ogg + +- type: speechSounds + id: Baritone + saySound: + path: /Audio/Voice/Talk/speak_1.ogg + askSound: + path: /Audio/Voice/Talk/speak_1_ask.ogg + exclaimSound: + path: /Audio/Voice/Talk/speak_1_exclaim.ogg + +- type: speechSounds + id: Tenor + saySound: + path: /Audio/Voice/Talk/speak_3.ogg + askSound: + path: /Audio/Voice/Talk/speak_3_ask.ogg + exclaimSound: + path: /Audio/Voice/Talk/speak_3_exclaim.ogg + +- type: speechSounds + id: Alto + saySound: + path: /Audio/Voice/Talk/speak_2.ogg + askSound: + path: /Audio/Voice/Talk/speak_2_ask.ogg + exclaimSound: + path: /Audio/Voice/Talk/speak_2_exclaim.ogg + +- type: speechSounds + id: Squeak + saySound: + path: /Audio/Animals/mouse_squeak.ogg + askSound: + path: /Audio/Animals/mouse_squeak.ogg + exclaimSound: + path: /Audio/Animals/mouse_squeak.ogg + +- type: speechSounds + id: Vending + saySound: + path: /Audio/Machines/vending_jingle.ogg + askSound: + path: /Audio/Machines/vending_jingle.ogg + exclaimSound: + path: /Audio/Machines/vending_jingle.ogg +