]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
voicemask can select speech verb (#25768)
authordeltanedas <39013340+deltanedas@users.noreply.github.com>
Thu, 28 Mar 2024 06:36:43 +0000 (06:36 +0000)
committerGitHub <noreply@github.com>
Thu, 28 Mar 2024 06:36:43 +0000 (17:36 +1100)
* add Name field to SpeechVerbPrototype

* extra locale for voice mask ui

* SpeechVerb ui and handling

* raaaaaaaaa

* reeeeeeeeal

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
* fix sort

* did you hear john syndicate died of ligma

* Update Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs
Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml
Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs
Content.Server/VoiceMask/VoiceMaskSystem.Equip.cs
Content.Server/VoiceMask/VoiceMaskSystem.cs
Content.Server/VoiceMask/VoiceMaskerComponent.cs
Content.Shared/Speech/SpeechVerbPrototype.cs
Content.Shared/VoiceMask/SharedVoiceMaskSystem.cs
Resources/Locale/en-US/chat/managers/chat-manager.ftl
Resources/Locale/en-US/voice-mask.ftl
Resources/Prototypes/Voice/speech_verbs.yml

index 0650482b108a8e10811c87d8e68e9615c65f0df2..f700c6663b9aec556d391bc4f1907edc86066608 100644 (file)
@@ -1,10 +1,13 @@
 using Content.Shared.VoiceMask;
 using Robust.Client.GameObjects;
+using Robust.Shared.Prototypes;
 
 namespace Content.Client.VoiceMask;
 
 public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
 {
+    [Dependency] private readonly IPrototypeManager _proto = default!;
+
     [ViewVariables]
     private VoiceMaskNameChangeWindow? _window;
 
@@ -16,10 +19,11 @@ public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
     {
         base.Open();
 
-        _window = new();
+        _window = new(_proto);
 
         _window.OpenCentered();
         _window.OnNameChange += OnNameSelected;
+        _window.OnVerbChange += verb => SendMessage(new VoiceMaskChangeVerbMessage(verb));
         _window.OnClose += Close;
     }
 
@@ -35,7 +39,7 @@ public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
             return;
         }
 
-        _window.UpdateState(cast.Name);
+        _window.UpdateState(cast.Name, cast.Verb);
     }
 
     protected override void Dispose(bool disposing)
index 2316ec9c7d851f94cf6f1fbc3205d602bc49d370..e23aca123919de60a0333c82b31c73fe1fd50507 100644 (file)
@@ -1,11 +1,16 @@
-<DefaultWindow xmlns="https://spacestation14.io"
+<controls:FancyWindow xmlns="https://spacestation14.io"
+               xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
                Title="{Loc 'voice-mask-name-change-window'}"
-               MinSize="5 20">
-    <BoxContainer Orientation="Vertical">
+               MinSize="5 30">
+    <BoxContainer Orientation="Vertical" Margin="5">
         <Label Text="{Loc 'voice-mask-name-change-info'}" />
-        <BoxContainer Orientation="Horizontal">
+        <BoxContainer Orientation="Horizontal" Margin="5">
             <LineEdit Name="NameSelector" HorizontalExpand="True" />
             <Button Name="NameSelectorSet" Text="{Loc 'voice-mask-name-change-set'}" />
         </BoxContainer>
+        <BoxContainer Orientation="Horizontal" Margin="5">
+            <Label Text="{Loc 'voice-mask-name-change-speech-style'}" />
+            <OptionButton Name="SpeechVerbSelector" /> <!-- Populated in LoadVerbs -->
+        </BoxContainer>
     </BoxContainer>
-</DefaultWindow>
+</controls:FancyWindow>
index e373acbd0a0120cb79a491d904807ca334b48f30..16a28f9d9b3ee2b25cbbe9ca680e4fc04904ec91 100644 (file)
@@ -1,26 +1,85 @@
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Speech;
 using Robust.Client.AutoGenerated;
 using Robust.Client.UserInterface.CustomControls;
 using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
 
 namespace Content.Client.VoiceMask;
 
 [GenerateTypedNameReferences]
-public sealed partial class VoiceMaskNameChangeWindow : DefaultWindow
+public sealed partial class VoiceMaskNameChangeWindow : FancyWindow
 {
     public Action<string>? OnNameChange;
+    public Action<string?>? OnVerbChange;
 
-    public VoiceMaskNameChangeWindow()
+    private List<(string, string)> _verbs = new();
+
+    private string? _verb;
+
+    public VoiceMaskNameChangeWindow(IPrototypeManager proto)
     {
         RobustXamlLoader.Load(this);
 
         NameSelectorSet.OnPressed += _ =>
         {
-            OnNameChange!(NameSelector.Text);
+            OnNameChange?.Invoke(NameSelector.Text);
+        };
+
+        SpeechVerbSelector.OnItemSelected += args =>
+        {
+            OnVerbChange?.Invoke((string?) args.Button.GetItemMetadata(args.Id));
+            SpeechVerbSelector.SelectId(args.Id);
         };
+
+        ReloadVerbs(proto);
+
+        AddVerbs();
+    }
+
+    private void ReloadVerbs(IPrototypeManager proto)
+    {
+        foreach (var verb in proto.EnumeratePrototypes<SpeechVerbPrototype>())
+        {
+            _verbs.Add((Loc.GetString(verb.Name), verb.ID));
+        }
+        _verbs.Sort((a, b) => a.Item1.CompareTo(b.Item1));
     }
 
-    public void UpdateState(string name)
+    private void AddVerbs()
+    {
+        SpeechVerbSelector.Clear();
+
+        AddVerb(Loc.GetString("chat-speech-verb-name-none"), null);
+        foreach (var (name, id) in _verbs)
+        {
+            AddVerb(name, id);
+        }
+    }
+
+    private void AddVerb(string name, string? verb)
+    {
+        var id = SpeechVerbSelector.ItemCount;
+        SpeechVerbSelector.AddItem(name);
+        if (verb is {} metadata)
+            SpeechVerbSelector.SetItemMetadata(id, metadata);
+
+        if (verb == _verb)
+            SpeechVerbSelector.SelectId(id);
+    }
+
+    public void UpdateState(string name, string? verb)
     {
         NameSelector.Text = name;
+        _verb = verb;
+
+        for (int id = 0; id < SpeechVerbSelector.ItemCount; id++)
+        {
+            if (string.Equals(verb, SpeechVerbSelector.GetItemMetadata(id)))
+            {
+                SpeechVerbSelector.SelectId(id);
+                break;
+            }
+        }
     }
 }
index 87b3b9ef323c77942ea44669bb478fc9e89fcd44..bd0c40f26a1df010821c898e847597466284a0d9 100644 (file)
@@ -21,6 +21,7 @@ public sealed partial class VoiceMaskSystem
 
         var comp = EnsureComp<VoiceMaskComponent>(user);
         comp.VoiceName = component.LastSetName;
+        comp.SpeechVerb = component.LastSpeechVerb;
 
         _actions.AddAction(user, ref component.ActionEntity, component.Action, uid);
     }
@@ -30,15 +31,23 @@ public sealed partial class VoiceMaskSystem
         RemComp<VoiceMaskComponent>(args.Equipee);
     }
 
-    private void TrySetLastKnownName(EntityUid maskWearer, string lastName)
+    private VoiceMaskerComponent? TryGetMask(EntityUid user)
     {
-        if (!HasComp<VoiceMaskComponent>(maskWearer)
-            || !_inventory.TryGetSlotEntity(maskWearer, MaskSlot, out var maskEntity)
-            || !TryComp<VoiceMaskerComponent>(maskEntity, out var maskComp))
-        {
-            return;
-        }
+        if (!HasComp<VoiceMaskComponent>(user) || !_inventory.TryGetSlotEntity(user, MaskSlot, out var maskEntity))
+            return null;
+
+        return CompOrNull<VoiceMaskerComponent>(maskEntity);
+    }
 
-        maskComp.LastSetName = lastName;
+    private void TrySetLastKnownName(EntityUid user, string name)
+    {
+        if (TryGetMask(user) is {} comp)
+            comp.LastSetName = name;
+    }
+
+    private void TrySetLastSpeechVerb(EntityUid user, string? verb)
+    {
+        if (TryGetMask(user) is {} comp)
+            comp.LastSpeechVerb = verb;
     }
 }
index 380eb7e7013478c80f97ec7aa8ac58f27b74ab4b..ac16e92259197bf9a4eb2b77dae8036a3f8134e8 100644 (file)
@@ -6,9 +6,11 @@ using Content.Shared.Database;
 using Content.Shared.Inventory.Events;
 using Content.Shared.Popups;
 using Content.Shared.Preferences;
+using Content.Shared.Speech;
 using Content.Shared.VoiceMask;
 using Robust.Server.GameObjects;
 using Robust.Shared.Player;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.VoiceMask;
 
@@ -17,11 +19,13 @@ public sealed partial class VoiceMaskSystem : EntitySystem
     [Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
     [Dependency] private readonly PopupSystem _popupSystem = default!;
     [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+    [Dependency] private readonly IPrototypeManager _proto = default!;
 
     public override void Initialize()
     {
         SubscribeLocalEvent<VoiceMaskComponent, TransformSpeakerNameEvent>(OnSpeakerNameTransform);
         SubscribeLocalEvent<VoiceMaskComponent, VoiceMaskChangeNameMessage>(OnChangeName);
+        SubscribeLocalEvent<VoiceMaskComponent, VoiceMaskChangeVerbMessage>(OnChangeVerb);
         SubscribeLocalEvent<VoiceMaskComponent, WearerMaskToggledEvent>(OnMaskToggled);
         SubscribeLocalEvent<VoiceMaskerComponent, GotEquippedEvent>(OnEquip);
         SubscribeLocalEvent<VoiceMaskerComponent, GotUnequippedEvent>(OnUnequip);
@@ -55,6 +59,21 @@ public sealed partial class VoiceMaskSystem : EntitySystem
         UpdateUI(uid, component);
     }
 
+    private void OnChangeVerb(Entity<VoiceMaskComponent> ent, ref VoiceMaskChangeVerbMessage msg)
+    {
+        if (msg.Verb is {} id && !_proto.HasIndex<SpeechVerbPrototype>(id))
+            return;
+
+        ent.Comp.SpeechVerb = msg.Verb;
+        // verb is only important to metagamers so no need to log as opposed to name
+
+        _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), ent, msg.Session);
+
+        TrySetLastSpeechVerb(ent, msg.Verb);
+
+        UpdateUI(ent, ent.Comp);
+    }
+
     private void OnSpeakerNameTransform(EntityUid uid, VoiceMaskComponent component, TransformSpeakerNameEvent args)
     {
         if (component.Enabled)
@@ -95,6 +114,6 @@ public sealed partial class VoiceMaskSystem : EntitySystem
         }
 
         if (_uiSystem.TryGetUi(owner, VoiceMaskUIKey.Key, out var bui))
-            _uiSystem.SetUiState(bui, new VoiceMaskBuiState(component.VoiceName));
+            _uiSystem.SetUiState(bui, new VoiceMaskBuiState(component.VoiceName, component.SpeechVerb));
     }
 }
index c3cc29c52717c81f6d09aa23bc6b6647b332ece1..afea5877df24ad4b5afef6b224c37e710f0ca89b 100644 (file)
@@ -1,15 +1,20 @@
+using Content.Shared.Speech;
 using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
 namespace Content.Server.VoiceMask;
 
 [RegisterComponent]
 public sealed partial class VoiceMaskerComponent : Component
 {
-    [ViewVariables(VVAccess.ReadWrite)] public string LastSetName = "Unknown";
+    [DataField]
+    public string LastSetName = "Unknown";
 
-    [DataField("action", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
-    public string Action = "ActionChangeVoiceMask";
+    [DataField]
+    public ProtoId<SpeechVerbPrototype>? LastSpeechVerb;
 
-    [DataField("actionEntity")] public EntityUid? ActionEntity;
+    [DataField]
+    public EntProtoId Action = "ActionChangeVoiceMask";
+
+    [DataField]
+    public EntityUid? ActionEntity;
 }
index 7ed1705f115680484ee87d870142034c4240d3de..951cac64f76503b7fe2896c61ba309502e5dc47f 100644 (file)
@@ -43,4 +43,10 @@ public sealed partial class SpeechVerbPrototype : IPrototype
     /// </summary>
     [DataField("priority")]
     public int Priority = 0;
+
+    /// <summary>
+    /// Name shown in the voicemask UI for this verb.
+    /// </summary>
+    [DataField(required: true)]
+    public LocId Name = string.Empty;
 }
index 2bb87819e30be18d7016b91dffb4382164962578..28558919461773a15b3b59603204251b53ec5474 100644 (file)
@@ -11,21 +11,37 @@ public enum VoiceMaskUIKey : byte
 [Serializable, NetSerializable]
 public sealed class VoiceMaskBuiState : BoundUserInterfaceState
 {
-    public string Name { get; }
+    public readonly string Name;
+    public readonly string? Verb;
 
-    public VoiceMaskBuiState(string name)
+    public VoiceMaskBuiState(string name, string? verb)
     {
         Name = name;
+        Verb = verb;
     }
 }
 
 [Serializable, NetSerializable]
 public sealed class VoiceMaskChangeNameMessage : BoundUserInterfaceMessage
 {
-    public string Name { get; }
+    public readonly string Name;
 
     public VoiceMaskChangeNameMessage(string name)
     {
         Name = name;
     }
 }
+
+/// <summary>
+/// Change the speech verb prototype to override, or null to use the user's verb.
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class VoiceMaskChangeVerbMessage : BoundUserInterfaceMessage
+{
+    public readonly string? Verb;
+
+    public VoiceMaskChangeVerbMessage(string? verb)
+    {
+        Verb = verb;
+    }
+}
index cf8c384dee28b7f537494bffd8ed0568c0018b78..1abe55da7ee88c2c579b959162b8710437cc18fe 100644 (file)
@@ -58,57 +58,79 @@ chat-speech-verb-suffix-question = ?
 chat-speech-verb-suffix-stutter = -
 chat-speech-verb-suffix-mumble = ..
 
+chat-speech-verb-name-none = None
+chat-speech-verb-name-default = Default
 chat-speech-verb-default = says
+chat-speech-verb-name-exclamation = Exclaiming
 chat-speech-verb-exclamation = exclaims
+chat-speech-verb-name-exclamation-strong = Yelling
 chat-speech-verb-exclamation-strong = yells
+chat-speech-verb-name-question = Asking
 chat-speech-verb-question = asks
+chat-speech-verb-name-stutter = Stuttering
 chat-speech-verb-stutter = stutters
+chat-speech-verb-name-mumble = Mumbling
 chat-speech-verb-mumble = mumbles
 
+chat-speech-verb-name-arachnid = Arachnid
 chat-speech-verb-insect-1 = chitters
 chat-speech-verb-insect-2 = chirps
 chat-speech-verb-insect-3 = clicks
 
+chat-speech-verb-name-moth = Moth
 chat-speech-verb-winged-1 = flutters
 chat-speech-verb-winged-2 = flaps
 chat-speech-verb-winged-3 = buzzes
 
+chat-speech-verb-name-slime = Slime
 chat-speech-verb-slime-1 = sloshes
 chat-speech-verb-slime-2 = burbles
 chat-speech-verb-slime-3 = oozes
 
+chat-speech-verb-name-plant = Diona
 chat-speech-verb-plant-1 = rustles
 chat-speech-verb-plant-2 = sways
 chat-speech-verb-plant-3 = creaks
 
+chat-speech-verb-name-robotic = Robotic
 chat-speech-verb-robotic-1 = states
 chat-speech-verb-robotic-2 = beeps
+chat-speech-verb-robotic-3 = boops
 
+chat-speech-verb-name-reptilian = Reptilian
 chat-speech-verb-reptilian-1 = hisses
 chat-speech-verb-reptilian-2 = snorts
 chat-speech-verb-reptilian-3 = huffs
 
+chat-speech-verb-name-skeleton = Skeleton
 chat-speech-verb-skeleton-1 = rattles
 chat-speech-verb-skeleton-2 = clacks
 chat-speech-verb-skeleton-3 = gnashes
 
+chat-speech-verb-name-vox = Vox
 chat-speech-verb-vox-1 = screeches
 chat-speech-verb-vox-2 = shrieks
 chat-speech-verb-vox-3 = croaks
 
+chat-speech-verb-name-canine = Canine
 chat-speech-verb-canine-1 = barks
 chat-speech-verb-canine-2 = woofs
 chat-speech-verb-canine-3 = howls
 
+chat-speech-verb-name-small-mob = Mouse
 chat-speech-verb-small-mob-1 = squeaks
 chat-speech-verb-small-mob-2 = pieps
 
+chat-speech-verb-name-large-mob = Carp
 chat-speech-verb-large-mob-1 = roars
 chat-speech-verb-large-mob-2 = growls
 
+chat-speech-verb-name-monkey = Monkey
 chat-speech-verb-monkey-1 = chimpers
 chat-speech-verb-monkey-2 = screeches
 
+chat-speech-verb-name-cluwne = Cluwne
+
 chat-speech-verb-parrot-1 = squawks
 chat-speech-verb-parrot-2 = tweets
 chat-speech-verb-parrot-3 = chirps
@@ -117,11 +139,13 @@ chat-speech-verb-cluwne-1 = giggles
 chat-speech-verb-cluwne-2 = guffaws
 chat-speech-verb-cluwne-3 = laughs
 
+chat-speech-verb-name-ghost = Ghost
 chat-speech-verb-ghost-1 = complains
 chat-speech-verb-ghost-2 = breathes
 chat-speech-verb-ghost-3 = hums
 chat-speech-verb-ghost-4 = mutters
 
+chat-speech-verb-name-electricity = Electricity
 chat-speech-verb-electricity-1 = crackles
 chat-speech-verb-electricity-2 = buzzes
 chat-speech-verb-electricity-3 = screeches
index cb6eb7768e5ec53a9218fd5694acbd3cc359d6d4..2f5acefee4118f8565330b098603675dd362b089 100644 (file)
@@ -1,5 +1,6 @@
 voice-mask-name-change-window = Voice Mask Name Change
 voice-mask-name-change-info = Type in the name you want to mimic.
+voice-mask-name-change-speech-style = Speech style
 voice-mask-name-change-set = Set name
 voice-mask-name-change-set-description = Change the name others hear to something else.
 
index 26e9370c017143015f80c16166dc573316669d0b..43fefe04e31413f9a064841626df7e2a53c71a3f 100644 (file)
@@ -1,30 +1,36 @@
 - type: speechVerb
   id: Default
+  name: chat-speech-verb-name-default
   speechVerbStrings:
   - chat-speech-verb-default
 
 - type: speechVerb
   id: DefaultQuestion
+  name: chat-speech-verb-name-question
   speechVerbStrings:
   - chat-speech-verb-question
 
 - type: speechVerb
   id: DefaultStutter
+  name: chat-speech-verb-name-stutter
   speechVerbStrings:
   - chat-speech-verb-stutter
 
 - type: speechVerb
   id: DefaultMumble
+  name: chat-speech-verb-name-mumble
   speechVerbStrings:
   - chat-speech-verb-mumble
 
 - type: speechVerb
   id: DefaultExclamation
+  name: chat-speech-verb-name-exclamation
   speechVerbStrings:
   - chat-speech-verb-exclamation
 
 - type: speechVerb
   id: DefaultExclamationStrong
+  name: chat-speech-verb-name-exclamation-strong
   bold: true
   speechVerbStrings:
   - chat-speech-verb-exclamation-strong
@@ -32,6 +38,7 @@
 
 - type: speechVerb
   id: Arachnid
+  name: chat-speech-verb-name-arachnid
   speechVerbStrings:
   - chat-speech-verb-insect-1
   - chat-speech-verb-insect-2
@@ -40,6 +47,7 @@
 
 - type: speechVerb
   id: Moth
+  name: chat-speech-verb-name-moth
   speechVerbStrings:
   - chat-speech-verb-winged-1
   - chat-speech-verb-winged-2
 
 - type: speechVerb
   id: Robotic
+  name: chat-speech-verb-name-robotic
   speechVerbStrings:
   - chat-speech-verb-robotic-1
   - chat-speech-verb-robotic-2
 
 - type: speechVerb
   id: Reptilian
+  name: chat-speech-verb-name-reptilian
   speechVerbStrings:
   - chat-speech-verb-reptilian-1
   - chat-speech-verb-reptilian-2
@@ -62,6 +72,7 @@
 
 - type: speechVerb
   id: Skeleton
+  name: chat-speech-verb-name-skeleton
   speechVerbStrings:
   - chat-speech-verb-skeleton-1
   - chat-speech-verb-skeleton-2
@@ -69,6 +80,7 @@
 
 - type: speechVerb
   id: Slime
+  name: chat-speech-verb-name-slime
   speechVerbStrings:
   - chat-speech-verb-slime-1
   - chat-speech-verb-slime-2
 
 - type: speechVerb
   id: Vox
+  name: chat-speech-verb-name-vox
   speechVerbStrings:
-    - chat-speech-verb-vox-1
-    - chat-speech-verb-vox-2
-    - chat-speech-verb-vox-3
+  - chat-speech-verb-vox-1
+  - chat-speech-verb-vox-2
+  - chat-speech-verb-vox-3
 
 - type: speechVerb
   id: Plant
+  name: chat-speech-verb-name-plant
   speechVerbStrings:
   - chat-speech-verb-plant-1
   - chat-speech-verb-plant-2
 
 - type: speechVerb
   id: Canine
+  name: chat-speech-verb-name-canine
   speechVerbStrings:
   - chat-speech-verb-canine-1
   - chat-speech-verb-canine-2
 
 - type: speechVerb
   id: LargeMob
+  name: chat-speech-verb-name-large-mob
   speechVerbStrings:
   - chat-speech-verb-large-mob-1
   - chat-speech-verb-large-mob-2
 
 - type: speechVerb
   id: SmallMob
+  name: chat-speech-verb-name-small-mob
   speechVerbStrings:
   - chat-speech-verb-small-mob-1
   - chat-speech-verb-small-mob-2
 
 - type: speechVerb
   id: Monkey
+  name: chat-speech-verb-name-monkey
   speechVerbStrings:
   - chat-speech-verb-monkey-1
   - chat-speech-verb-monkey-2
 
 - type: speechVerb
   id: Cluwne
+  name: chat-speech-verb-name-cluwne
   speechVerbStrings:
   - chat-speech-verb-cluwne-1
   - chat-speech-verb-cluwne-2
 
 - type: speechVerb
   id: Ghost
+  name: chat-speech-verb-name-ghost
   speechVerbStrings:
   - chat-speech-verb-ghost-1
   - chat-speech-verb-ghost-2
 
 - type: speechVerb
   id: Electricity
+  name: chat-speech-verb-name-electricity
   speechVerbStrings:
   - chat-speech-verb-electricity-1
   - chat-speech-verb-electricity-2