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;
{
base.Open();
- _window = new();
+ _window = new(_proto);
_window.OpenCentered();
_window.OnNameChange += OnNameSelected;
+ _window.OnVerbChange += verb => SendMessage(new VoiceMaskChangeVerbMessage(verb));
_window.OnClose += Close;
}
return;
}
- _window.UpdateState(cast.Name);
+ _window.UpdateState(cast.Name, cast.Verb);
}
protected override void Dispose(bool disposing)
-<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>
+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;
+ }
+ }
}
}
var comp = EnsureComp<VoiceMaskComponent>(user);
comp.VoiceName = component.LastSetName;
+ comp.SpeechVerb = component.LastSpeechVerb;
_actions.AddAction(user, ref component.ActionEntity, component.Action, uid);
}
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;
}
}
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;
[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);
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)
}
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));
}
}
+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;
}
/// </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;
}
[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;
+ }
+}
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
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
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.
- 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
- type: speechVerb
id: Arachnid
+ name: chat-speech-verb-name-arachnid
speechVerbStrings:
- chat-speech-verb-insect-1
- chat-speech-verb-insect-2
- 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
- type: speechVerb
id: Skeleton
+ name: chat-speech-verb-name-skeleton
speechVerbStrings:
- chat-speech-verb-skeleton-1
- chat-speech-verb-skeleton-2
- 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