Voice mask effects are toggleable and hide your accent (#41965)

* apply negate accents system

* add toggle to voice mask ui

* roll negateaccents into voice mask system, delete negate accents comp&system, update yml entries

* convert button to ToggleButton and some cleanup

* retry for heisenfail

* accent toggle

* update names and add mask active check for accent hiding
This commit is contained in:
alexalexmax
2025-12-25 18:47:05 -08:00
committed by GitHub
parent 2182c7be70
commit 4ff7411fb7
12 changed files with 118 additions and 9 deletions

View File

@@ -26,6 +26,8 @@ public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
_window.OnNameChange += OnNameSelected;
_window.OnVerbChange += verb => SendMessage(new VoiceMaskChangeVerbMessage(verb));
_window.OnToggle += OnToggle;
_window.OnAccentToggle += OnAccentToggle;
}
private void OnNameSelected(string name)
@@ -33,6 +35,16 @@ public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
SendMessage(new VoiceMaskChangeNameMessage(name));
}
private void OnToggle()
{
SendMessage(new VoiceMaskToggleMessage());
}
private void OnAccentToggle()
{
SendMessage(new VoiceMaskAccentToggleMessage());
}
protected override void UpdateState(BoundUserInterfaceState state)
{
if (state is not VoiceMaskBuiState cast || _window == null)
@@ -40,7 +52,7 @@ public sealed class VoiceMaskBoundUserInterface : BoundUserInterface
return;
}
_window.UpdateState(cast.Name, cast.Verb);
_window.UpdateState(cast.Name, cast.Verb, cast.Active, cast.AccentHide);
}
protected override void Dispose(bool disposing)

View File

@@ -12,5 +12,7 @@
<Label Text="{Loc 'voice-mask-name-change-speech-style'}" />
<OptionButton Name="SpeechVerbSelector" /> <!-- Populated in LoadVerbs -->
</BoxContainer>
<Button Name="ToggleAccentButton" Text="{Loc 'voice-mask-name-change-accent-toggle'}" HorizontalExpand="True" ToggleMode="True" Margin="5"/>
<Button Name="ToggleButton" Text="{Loc 'voice-mask-name-change-toggle'}" HorizontalExpand="True" ToggleMode="True" Margin="5"/>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -12,6 +12,8 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow
{
public Action<string>? OnNameChange;
public Action<string?>? OnVerbChange;
public Action? OnToggle;
public Action? OnAccentToggle;
private List<(string, string)> _verbs = new();
@@ -31,6 +33,9 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow
OnVerbChange?.Invoke((string?) args.Button.GetItemMetadata(args.Id));
SpeechVerbSelector.SelectId(args.Id);
};
ToggleButton.OnPressed += args => OnToggle?.Invoke();
ToggleAccentButton.OnPressed += args => OnAccentToggle?.Invoke();
}
public void ReloadVerbs(IPrototypeManager proto)
@@ -64,10 +69,12 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow
SpeechVerbSelector.SelectId(id);
}
public void UpdateState(string name, string? verb)
public void UpdateState(string name, string? verb, bool active, bool accentHide)
{
NameSelector.Text = name;
_verb = verb;
ToggleButton.Pressed = active;
ToggleAccentButton.Pressed = accentHide;
for (int id = 0; id < SpeechVerbSelector.ItemCount; id++)
{

View File

@@ -736,7 +736,7 @@ public sealed partial class ChatSystem : SharedChatSystem
public string TransformSpeech(EntityUid sender, string message)
{
var ev = new TransformSpeechEvent(sender, message);
RaiseLocalEvent(ev);
RaiseLocalEvent(sender, ev, true);
return ev.Message;
}

View File

@@ -15,6 +15,9 @@ public sealed class AccentSystem : EntitySystem
private void AccentHandler(TransformSpeechEvent args)
{
if (args.Cancelled)
return;
var accentEvent = new AccentGetEvent(args.Sender, args.Message);
RaiseLocalEvent(args.Sender, accentEvent, true);

View File

@@ -43,5 +43,17 @@ public sealed partial class VoiceMaskComponent : Component
/// </summary>
[DataField]
public EntityUid? ActionEntity;
/// <summary>
/// If user's voice is getting changed when they speak.
/// </summary>
[DataField]
public bool Active = true;
/// <summary>
/// If user's accent is getting hidden when they speak.
/// </summary>
[DataField]
public bool AccentHide = true;
}

View File

@@ -1,3 +1,4 @@
using Content.Server.Speech;
using Content.Shared.Actions;
using Content.Shared.Administration.Logs;
using Content.Shared.CCVar;
@@ -10,7 +11,6 @@ using Content.Shared.Implants;
using Content.Shared.Inventory;
using Content.Shared.Lock;
using Content.Shared.Popups;
using Content.Shared.Preferences;
using Content.Shared.Speech;
using Content.Shared.VoiceMask;
using Robust.Shared.Configuration;
@@ -45,12 +45,41 @@ public sealed partial class VoiceMaskSystem : EntitySystem
SubscribeLocalEvent<VoiceMaskComponent, LockToggledEvent>(OnLockToggled);
SubscribeLocalEvent<VoiceMaskComponent, VoiceMaskChangeNameMessage>(OnChangeName);
SubscribeLocalEvent<VoiceMaskComponent, VoiceMaskChangeVerbMessage>(OnChangeVerb);
SubscribeLocalEvent<VoiceMaskComponent, VoiceMaskToggleMessage>(OnToggle);
SubscribeLocalEvent<VoiceMaskComponent, VoiceMaskAccentToggleMessage>(OnAccentToggle);
SubscribeLocalEvent<VoiceMaskComponent, ClothingGotEquippedEvent>(OnEquip);
SubscribeLocalEvent<VoiceMaskSetNameEvent>(OpenUI);
SubscribeLocalEvent<VoiceMaskComponent, TransformSpeechEvent>(OnTransformSpeech, before: [typeof(AccentSystem)]);
SubscribeLocalEvent<VoiceMaskComponent, InventoryRelayedEvent<TransformSpeechEvent>>(OnTransformSpeechInventory, before: [typeof(AccentSystem)]);
SubscribeLocalEvent<VoiceMaskComponent, ImplantRelayEvent<TransformSpeechEvent>>(OnTransformSpeechImplant, before: [typeof(AccentSystem)]);
Subs.CVar(_cfgManager, CCVars.MaxNameLength, value => _maxNameLength = value, true);
}
/// <summary>
/// Hides accent if the voice mask is on and the option to block accents is on
/// </summary>
private void TransformSpeech(Entity<VoiceMaskComponent> entity, TransformSpeechEvent args)
{
if (entity.Comp.AccentHide && entity.Comp.Active)
args.Cancel();
}
private void OnTransformSpeech(Entity<VoiceMaskComponent> entity, ref TransformSpeechEvent args)
{
TransformSpeech(entity, args);
}
private void OnTransformSpeechInventory(Entity<VoiceMaskComponent> entity, ref InventoryRelayedEvent<TransformSpeechEvent> args)
{
TransformSpeech(entity, args.Args);
}
private void OnTransformSpeechImplant(Entity<VoiceMaskComponent> entity, ref ImplantRelayEvent<TransformSpeechEvent> args)
{
TransformSpeech(entity, args.Event);
}
private void OnTransformSpeakerNameInventory(Entity<VoiceMaskComponent> entity, ref InventoryRelayedEvent<TransformSpeakerNameEvent> args)
{
TransformVoice(entity, args.Args);
@@ -63,8 +92,10 @@ public sealed partial class VoiceMaskSystem : EntitySystem
private void OnSeeIdentityAttemptEvent(Entity<VoiceMaskComponent> entity, ref ImplantRelayEvent<SeeIdentityAttemptEvent> args)
{
if (entity.Comp.OverrideIdentity)
args.Event.NameOverride = GetCurrentVoiceName(entity);
if (!entity.Comp.OverrideIdentity || !entity.Comp.Active)
return;
args.Event.NameOverride = GetCurrentVoiceName(entity);
}
private void OnImplantImplantedEvent(Entity<VoiceMaskComponent> entity, ref ImplantImplantedEvent ev)
@@ -117,6 +148,21 @@ public sealed partial class VoiceMaskSystem : EntitySystem
UpdateUI(entity);
}
private void OnToggle(Entity<VoiceMaskComponent> entity, ref VoiceMaskToggleMessage args)
{
_popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-toggle"), entity, args.Actor);
entity.Comp.Active = !entity.Comp.Active;
// Update identity because of possible name override
_identity.QueueIdentityUpdate(args.Actor);
}
private void OnAccentToggle(Entity<VoiceMaskComponent> entity, ref VoiceMaskAccentToggleMessage args)
{
_popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-accent-toggle"), entity, args.Actor);
entity.Comp.AccentHide = !entity.Comp.AccentHide;
}
#endregion
#region UI
@@ -145,7 +191,7 @@ public sealed partial class VoiceMaskSystem : EntitySystem
private void UpdateUI(Entity<VoiceMaskComponent> entity)
{
if (_uiSystem.HasUi(entity, VoiceMaskUIKey.Key))
_uiSystem.SetUiState(entity.Owner, VoiceMaskUIKey.Key, new VoiceMaskBuiState(GetCurrentVoiceName(entity), entity.Comp.VoiceMaskSpeechVerb));
_uiSystem.SetUiState(entity.Owner, VoiceMaskUIKey.Key, new VoiceMaskBuiState(GetCurrentVoiceName(entity), entity.Comp.VoiceMaskSpeechVerb, entity.Comp.Active, entity.Comp.AccentHide));
}
#endregion
@@ -157,6 +203,9 @@ public sealed partial class VoiceMaskSystem : EntitySystem
private void TransformVoice(Entity<VoiceMaskComponent> entity, TransformSpeakerNameEvent args)
{
if (!entity.Comp.Active)
return;
args.VoiceName = GetCurrentVoiceName(entity);
args.SpeechVerb = entity.Comp.VoiceMaskSpeechVerb ?? args.SpeechVerb;
}

View File

@@ -27,8 +27,9 @@ public sealed class TransformSpeakerNameEvent : EntityEventArgs, IInventoryRelay
/// <summary>
/// Raised broadcast in order to transform speech.transmit
/// </summary>
public sealed class TransformSpeechEvent : EntityEventArgs
public sealed class TransformSpeechEvent : CancellableEntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
public EntityUid Sender;
public string Message;

View File

@@ -15,6 +15,7 @@ public abstract partial class SharedSubdermalImplantSystem
SubscribeLocalEvent<ImplantedComponent, AfterInteractUsingEvent>(RelayToImplantEvent);
SubscribeLocalEvent<ImplantedComponent, SuicideEvent>(RelayToImplantEvent);
SubscribeLocalEvent<ImplantedComponent, TransformSpeakerNameEvent>(RelayToImplantEvent);
SubscribeLocalEvent<ImplantedComponent, TransformSpeechEvent>(RelayToImplantEvent);
SubscribeLocalEvent<ImplantedComponent, SeeIdentityAttemptEvent>(RelayToImplantEvent);
}

View File

@@ -47,6 +47,7 @@ public partial class InventorySystem
SubscribeLocalEvent<InventoryComponent, GetDefaultRadioChannelEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, RefreshNameModifiersEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, TransformSpeakerNameEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, TransformSpeechEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, SelfBeforeInjectEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, BeforeInjectTargetEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, SelfBeforeGunShotEvent>(RelayInventoryEvent);

View File

@@ -13,11 +13,15 @@ public sealed class VoiceMaskBuiState : BoundUserInterfaceState
{
public readonly string Name;
public readonly string? Verb;
public readonly bool Active;
public readonly bool AccentHide;
public VoiceMaskBuiState(string name, string? verb)
public VoiceMaskBuiState(string name, string? verb, bool active, bool accentHide)
{
Name = name;
Verb = verb;
Active = active;
AccentHide = accentHide;
}
}
@@ -45,3 +49,15 @@ public sealed class VoiceMaskChangeVerbMessage : BoundUserInterfaceMessage
Verb = verb;
}
}
/// <summary>
/// Toggle the effects of the voice mask.
/// </summary>
[Serializable, NetSerializable]
public sealed class VoiceMaskToggleMessage : BoundUserInterfaceMessage;
/// <summary>
/// Toggle the effects of accent negation.
/// </summary>
[Serializable, NetSerializable]
public sealed class VoiceMaskAccentToggleMessage : BoundUserInterfaceMessage;

View File

@@ -5,6 +5,11 @@ 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.
voice-mask-name-change-toggle = Toggle voice mask
voice-mask-name-change-accent-toggle = Block accent
voice-mask-popup-toggle = Toggled voice mask.
voice-mask-popup-accent-toggle = Toggled accent.
voice-mask-popup-success = Name set successfully.
voice-mask-popup-failure = Name could not be set.