From b567c34e927d38a2bccd672f6e92b50bef7b613a Mon Sep 17 00:00:00 2001 From: themias <89101928+themias@users.noreply.github.com> Date: Sun, 16 Oct 2022 13:44:50 -0400 Subject: [PATCH] Add voice trigger for modular grenades (#11449) --- .../Components/TriggerOnVoiceComponent.cs | 76 ++++++++++++++++++ .../EntitySystems/TriggerSystem.Voice.cs | 61 ++++++++++++++ .../Explosion/EntitySystems/TriggerSystem.cs | 1 + .../en-US/weapons/grenades/voice-trigger.ftl | 8 ++ .../Catalog/Research/technologies.yml | 1 + .../Objects/Devices/Electronics/triggers.yml | 15 ++++ .../Entities/Structures/Machines/lathe.yml | 1 + .../Prototypes/Recipes/Lathes/devices.yml | 11 +++ .../Objects/Devices/voice.rsi/meta.json | 17 ++++ .../Objects/Devices/voice.rsi/voice.png | Bin 0 -> 204 bytes 10 files changed, 191 insertions(+) create mode 100644 Content.Server/Explosion/Components/TriggerOnVoiceComponent.cs create mode 100644 Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs create mode 100644 Resources/Locale/en-US/weapons/grenades/voice-trigger.ftl create mode 100644 Resources/Textures/Objects/Devices/voice.rsi/meta.json create mode 100644 Resources/Textures/Objects/Devices/voice.rsi/voice.png diff --git a/Content.Server/Explosion/Components/TriggerOnVoiceComponent.cs b/Content.Server/Explosion/Components/TriggerOnVoiceComponent.cs new file mode 100644 index 0000000000..f7b9f15636 --- /dev/null +++ b/Content.Server/Explosion/Components/TriggerOnVoiceComponent.cs @@ -0,0 +1,76 @@ +using Content.Shared.Interaction; +using Content.Server.Radio.Components; +using Content.Shared.Radio; +using System.Text.RegularExpressions; +using Content.Server.Explosion.EntitySystems; +using Content.Server.Radio.EntitySystems; +using System; + +namespace Content.Server.Explosion.Components +{ + /// + /// Sends a trigger when the keyphrase is heard + /// + [RegisterComponent] + [ComponentReference(typeof(IListen))] + public sealed class TriggerOnVoiceComponent : Component, IListen + { + private SharedInteractionSystem _sharedInteractionSystem = default!; + private TriggerSystem _triggerSystem = default!; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("keyPhrase")] + public string? KeyPhrase; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("listenRange")] + public int ListenRange { get; private set; } = 4; + + [ViewVariables] + public bool IsRecording = false; + + [ViewVariables] + [DataField("minLength")] + public int MinLength = 3; + + [ViewVariables] + [DataField("maxLength")] + public int MaxLength = 50; + + /// + /// Displays 'recorded' popup only for the one who activated + /// it in order to allow for stealthily recording others + /// + [ViewVariables] + public EntityUid Activator; + + protected override void Initialize() + { + base.Initialize(); + + _sharedInteractionSystem = EntitySystem.Get(); + _triggerSystem = EntitySystem.Get(); + } + + bool IListen.CanListen(string message, EntityUid source, RadioChannelPrototype? channelPrototype) + { + //will hear standard speech and radio messages originating nearby but not independant whispers + return _sharedInteractionSystem.InRangeUnobstructed(Owner, source, range: ListenRange); + } + + void IListen.Listen(string message, EntityUid speaker, RadioChannelPrototype? channel) + { + message = message.Trim(); + + if (IsRecording && message.Length >= MinLength && message.Length <= MaxLength) + { + KeyPhrase = message; + _triggerSystem.ToggleRecord(this, Activator, true); + } + else if (KeyPhrase != null && message.Contains(KeyPhrase, StringComparison.InvariantCultureIgnoreCase)) + { + _triggerSystem.Trigger(Owner, speaker); + } + } + } +} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs new file mode 100644 index 0000000000..5140d296ff --- /dev/null +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs @@ -0,0 +1,61 @@ +using Content.Server.Explosion.Components; +using Content.Server.Nutrition.Components; +using Content.Shared.Examine; +using Content.Shared.Interaction.Events; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Microsoft.CodeAnalysis.Options; +using Robust.Shared.GameObjects; +using Robust.Shared.Physics.Events; +using Robust.Shared.Player; +using Robust.Shared.Utility; + +namespace Content.Server.Explosion.EntitySystems +{ + public sealed partial class TriggerSystem + { + private void InitializeVoice() + { + SubscribeLocalEvent(OnVoiceExamine); + SubscribeLocalEvent>(OnVoiceGetAltVerbs); + } + + private void OnVoiceGetAltVerbs(EntityUid uid, TriggerOnVoiceComponent component, GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + args.Verbs.Add(new AlternativeVerb() + { + Text = Loc.GetString("verb-trigger-voice-record"), + Act = () => ToggleRecord(component, args.User), + Priority = 1 + }); + } + + public void ToggleRecord(TriggerOnVoiceComponent component, EntityUid user, bool recorded = false) + { + component.IsRecording ^= true; + + if (recorded) //recording success popup + { + _popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-recorded"), component.Owner, Filter.Entities(user)); + } + else if (component.IsRecording) //recording start popup + { + component.Activator = user; + _popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-start-recording"), component.Owner, Filter.Entities(user)); + } + else //recording stopped manually popup + { + _popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-stop-recording"), component.Owner, Filter.Entities(user)); + } + } + + private void OnVoiceExamine(EntityUid uid, TriggerOnVoiceComponent component, ExaminedEvent args) + { + if (args.IsInDetailsRange) + args.PushText(Loc.GetString("examine-trigger-voice", ("keyphrase", component.KeyPhrase?? Loc.GetString("trigger-voice-uninitialized")))); + } + } +} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs index cd02f5321a..c0d019805a 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs @@ -57,6 +57,7 @@ namespace Content.Server.Explosion.EntitySystems InitializeOnUse(); InitializeSignal(); InitializeTimedCollide(); + InitializeVoice(); SubscribeLocalEvent(OnTriggerCollide); SubscribeLocalEvent(OnActivate); diff --git a/Resources/Locale/en-US/weapons/grenades/voice-trigger.ftl b/Resources/Locale/en-US/weapons/grenades/voice-trigger.ftl new file mode 100644 index 0000000000..52be5c7cb2 --- /dev/null +++ b/Resources/Locale/en-US/weapons/grenades/voice-trigger.ftl @@ -0,0 +1,8 @@ +examine-trigger-voice = The display reads "{$keyphrase}" +trigger-voice-uninitialized = Uninitialized... + +verb-trigger-voice-record = Record + +popup-trigger-voice-start-recording = Started recording +popup-trigger-voice-stop-recording = Stopped recording +popup-trigger-voice-recorded = Recorded \ No newline at end of file diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml index 0cf6a63a4c..fb28619f65 100644 --- a/Resources/Prototypes/Catalog/Research/technologies.yml +++ b/Resources/Prototypes/Catalog/Research/technologies.yml @@ -319,6 +319,7 @@ - GeneratorPlasmaMachineCircuitboard - Signaller - SignalTrigger + - VoiceTrigger - type: technology name: technologies-compact-power-technology diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml index f8bae2881c..aa4ae65c3b 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml @@ -43,3 +43,18 @@ - type: SignalReceiver - type: StaticPrice price: 40 + +- type: entity + parent: BaseItem + id: VoiceTrigger + name: voice trigger + description: Adds a machine link that is triggered by vocal keywords + components: + - type: Sprite + sprite: Objects/Devices/voice.rsi + state: voice + - type: PayloadTrigger + components: + - type: TriggerOnVoice + - type: StaticPrice + price: 40 diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 47d5600450..180cbf441b 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -217,6 +217,7 @@ - FlashPayload - Signaller - SignalTrigger + - VoiceTrigger - PowerCellSmall - PowerCellMedium - PowerCellHigh diff --git a/Resources/Prototypes/Recipes/Lathes/devices.yml b/Resources/Prototypes/Recipes/Lathes/devices.yml index 4aaa6d197d..c0dfdfc209 100644 --- a/Resources/Prototypes/Recipes/Lathes/devices.yml +++ b/Resources/Prototypes/Recipes/Lathes/devices.yml @@ -20,6 +20,17 @@ Steel: 300 Plastic: 200 +- type: latheRecipe + id: VoiceTrigger + icon: + sprite: Objects/Devices/voice.rsi + state: voice + result: VoiceTrigger + completetime: 2 + materials: + Steel: 300 + Plastic: 200 + - type: latheRecipe id: ChemicalPayload icon: diff --git a/Resources/Textures/Objects/Devices/voice.rsi/meta.json b/Resources/Textures/Objects/Devices/voice.rsi/meta.json new file mode 100644 index 0000000000..d4a4b57ddf --- /dev/null +++ b/Resources/Textures/Objects/Devices/voice.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c71e03214013191760284361aaff7af90505aaab", + + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "voice", + "directions": 1 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Devices/voice.rsi/voice.png b/Resources/Textures/Objects/Devices/voice.rsi/voice.png new file mode 100644 index 0000000000000000000000000000000000000000..42defce8d441ed572bb357066cd11a51c1e85904 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv^#Gp`*8>L*=;-Lk$;svA<+-@H zL`FuYq@*w~q!}9<2L=XeXlO8`&15(;vtZ6&U7!}mk|4ie28U-i(tw;`PZ!4!jfu$# z68{_+VjUQJ&!@DgEl63y!s5Z@5Th#EVz(?n!6VpRsAGm<_A!%OmBtfGy{GG~)^rFG x6cub;m6ZDYlv#@Lfi|Vc(+u0h?rtq%WymuUX19&V@d6sp;OXk;vd$@?2>`RXJYoO< literal 0 HcmV?d00001