Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Voice masks can now change your voice sound! #32794

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

beck-thompson
Copy link
Contributor

@beck-thompson beck-thompson commented Oct 13, 2024

About the PR

Title! Same look as the verbs, but now you can also change the sound you make when you speak! This wont work for stuff like emotes, just normal speaking (Chat code 😢).

Why / Balance

Its fun and allows for some more silly antag shenanigans. You can now finally lure the CO to the weird box on bridge that totally doesn't have 5 nukies hidden inside while pretending to be a borg in distress!

Technical details

Because of the similarity to the verb dropdown, I had to refactor a lot of the verb stuff so it would work with both the verbs and the sounds! I added a lot of comments and named stuff better so it should be relatively clear what is going on.
Basic rundown:
When the window is opened VoiceMaskBoundUserInterface.cs:18,
You first load all the verbs and speech noises into their respective lists (ReloadVerbsAndNoises).
You then actually add the the verbs and speech noises to the buttons themselves in (AddVerbsAndSounds).
Whenever the state gets updated, the UpdateSelectedButtonOption gets called on both drop downs and updates the currently selected option.

Media

2024-10-13.13-21-14.mp4
  • UI is now updated so it looks a little better. You might also need to turn your volume up to hear whats going on!

Breaking changes

SpeechSoundsPrototypes are now required to have a (Localized) name field. Example:

- type: speechSounds
  id: Bass
  ...

is now:

- type: speechSounds
  id: Bass
  name: chat-speech-noise-name-bass
  ...

Changelog

🆑 Beck Thompson

  • add: Voice masks now allow you to change the sound you make when speaking!

@github-actions github-actions bot added the Changes: UI Changes: Might require knowledge of UI design or code. label Oct 13, 2024
@SlamBamActionman SlamBamActionman added the S: Untriaged Status: Indicates an item has not been triaged and doesn't have appropriate labels. label Nov 14, 2024
@github-actions github-actions bot added the S: Merge Conflict Status: Needs to resolve merge conflicts before it can be accepted label Nov 15, 2024
Copy link
Contributor

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot added size/L Denotes a PR that changes 1000-4999 lines. and removed S: Merge Conflict Status: Needs to resolve merge conflicts before it can be accepted labels Nov 17, 2024
@ScarKy0 ScarKy0 added P2: Raised Priority: Item has a raised priority, indicating it might get increased maintainer attention. T: New Feature Type: New feature or content, or extending existing content D2: Medium Difficulty: A good amount of codebase knowledge required. S: Needs Review Status: Requires additional reviews before being fully accepted T: Balance Change Type: Balance changes through direct value changes, or changes to mechanics that affect it T: UI / UX Improvement Type: UI and player facing interactive graphical interfaces A: Roundflow/Antag Area: Roundflow - "What happens in the game", including antagonist roles and their capabilities and removed S: Untriaged Status: Indicates an item has not been triaged and doesn't have appropriate labels. labels Nov 18, 2024
Copy link
Contributor

@Aeshus Aeshus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some notes

Content.Shared/Inventory/InventorySystem.Relay.cs Outdated Show resolved Hide resolved
Content.Shared/VoiceMask/SharedVoiceMaskSystem.cs Outdated Show resolved Hide resolved
Resources/Locale/en-US/chat/speech-noise-names.ftl Outdated Show resolved Hide resolved
/// <summary>
/// List of all the loaded speech verbs (name, protoID).
/// </summary>
private List<(string, string)> _speechVerbs = new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason the type is not (string, ProtoId<?>)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately yes :(
It allows me make the PopulateOptionButton function usable for both! I couldn't figure out a way to make a generic protoID but if you know a way I'm all ears.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could do it with something cursed with

private void PopulateOptionButton<T>(OptionButton button, string? selectedOption, List<(string, ProtoId<T>)> values) where T : class, IPrototype

Though it might make more sense to duplicate the function so that you can have a different none string for the speech sounds instead of just reusing the speech verb's for both.

Though, I'm not totally sure the added complexity is worth it.

Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs Outdated Show resolved Hide resolved
@beck-thompson beck-thompson requested a review from Aeshus December 12, 2024 07:41
Copy link
Contributor

@Aeshus Aeshus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making the changes I requested earlier!

As requested by the re-requested review, I've attached more comments and changes. I also got bored and made changes to the XAML layout.

Enjoy!


entity.Comp.VoiceMaskSpeechSound = msg.Sound;

_popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), entity, msg.Actor);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LocId should be moved to VoiceMaskComponent.

RaiseLocalEvent(ent.Owner, evt);

var protoId = evt.OverrideSpeechSound ?? ent.Comp.SpeechSounds;
var prototype = _protoManager.Index<SpeechSoundsPrototype>(protoId);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ProtoId is nullable here (SpeechSounds and OverrideSpeechSounds are nullable). You'll have to handle this or change some type signatures.

{
_speechSounds.Add((Loc.GetString(noise.Name), noise.ID));
}
_speechSounds.Sort((a, b) => a.Item1.CompareTo(b.Item1));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be using StringComparisons, though I'm not sure if Ordinal is the best for this case.

Suggested change
_speechSounds.Sort((a, b) => a.Item1.CompareTo(b.Item1));
_speechSounds.Sort((a, b) => string.Compare(a.Item1, b.Item1, StringComparison.Ordinal));

SpeechVerbSelector.SelectId(id);
// Add the default option that wont do anything when selected.
AddOption(button, selectedOption, Loc.GetString("chat-speech-verb-name-none"), null);
foreach (var (name, id) in values)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
foreach (var (name, id) in values)
foreach (var (name, id) in values)

/// <summary>
/// List of all the loaded speech verbs (name, protoID).
/// </summary>
private List<(string, string)> _speechVerbs = new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could do it with something cursed with

private void PopulateOptionButton<T>(OptionButton button, string? selectedOption, List<(string, ProtoId<T>)> values) where T : class, IPrototype

Though it might make more sense to duplicate the function so that you can have a different none string for the speech sounds instead of just reusing the speech verb's for both.

Though, I'm not totally sure the added complexity is worth it.

Comment on lines +6 to +19
<Label Text="{Loc 'voice-mask-name-change-info'}" Margin="0 0 0 10" />
<GridContainer Columns="2">
<GridContainer Rows="3" HorizontalExpand="True">
<LineEdit Name="NameSelector" MinWidth="175" HorizontalExpand="True" Margin="0 0 10 10" />
<Label Text="{Loc 'voice-mask-name-change-speech-style'}" Margin="0 0 0 5" />
<Label Text="{Loc 'voice-mask-name-change-speech-sound'}" />
</GridContainer>
<GridContainer Rows="3">
<Button Name="NameSelectorSet" Text="{Loc 'voice-mask-name-change-set'}" Margin="0 0 0 10" />
<OptionButton Name="SpeechVerbSelector" /> <!-- Populated in AddVerbsAndSounds -->
<OptionButton Name="SpeechSoundSelector" /> <!-- Populated in AddVerbsAndSounds -->
</GridContainer>
</GridContainer>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had some fun playing about and made some adjustments to move the label to below the text input and make it slightly darker/smaller.

I also removed the extra GridContainer as you're meant to just list them all off (this means you won't have to do the weird hack where you have to copy the margin between the subgrids as this is what the main grid is built to do).

Suggested change
<Label Text="{Loc 'voice-mask-name-change-info'}" Margin="0 0 0 10" />
<GridContainer Columns="2">
<GridContainer Rows="3" HorizontalExpand="True">
<LineEdit Name="NameSelector" MinWidth="175" HorizontalExpand="True" Margin="0 0 10 10" />
<Label Text="{Loc 'voice-mask-name-change-speech-style'}" Margin="0 0 0 5" />
<Label Text="{Loc 'voice-mask-name-change-speech-sound'}" />
</GridContainer>
<GridContainer Rows="3">
<Button Name="NameSelectorSet" Text="{Loc 'voice-mask-name-change-set'}" Margin="0 0 0 10" />
<OptionButton Name="SpeechVerbSelector" /> <!-- Populated in AddVerbsAndSounds -->
<OptionButton Name="SpeechSoundSelector" /> <!-- Populated in AddVerbsAndSounds -->
</GridContainer>
</GridContainer>
<GridContainer Columns="2">
<LineEdit Name="NameSelector" HorizontalExpand="True" />
<Button Name="NameSelectorSet" Text="{Loc 'voice-mask-name-change-set'}" />
<Label StyleClasses="LabelSubText" Text="{Loc 'voice-mask-name-change-info'}" />
<Control /> <!-- GridContainer needs a padding element so it goes to the next row -->
<Label Text="{Loc 'voice-mask-name-change-speech-style'}" />
<OptionButton Name="SpeechVerbSelector" />
<Label Text="{Loc 'voice-mask-name-change-speech-sound'}" />
<OptionButton Name="SpeechSoundSelector" />
</GridContainer>

image

If you don't like the padding introduced by the Label, you can use this to trick the grid into ignoring it's width while still being able to render fine.

            <Label StyleClasses="LabelSubText" Text="{Loc 'voice-mask-name-change-info'}" MaxWidth="1"
                   HorizontalAlignment="Left" />

Comment on lines +128 to +129
if (value is { } metadata)
button.SetItemMetadata(id, metadata);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Equivalent and less confusing:

Suggested change
if (value is { } metadata)
button.SetItemMetadata(id, metadata);
if (value is not null)
button.SetItemMetadata(id, value);

@@ -50,6 +59,18 @@ private void OnChangeVerb(Entity<VoiceMaskComponent> entity, ref VoiceMaskChange
UpdateUI(entity);
}

private void OnChangeSound(Entity<VoiceMaskComponent> entity, ref VoiceMaskChangeSoundMessage msg)
{
if (msg.Sound is { } id && !_proto.HasIndex<SpeechSoundsPrototype>(id))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably just manually check for null for clarity rather than doing the null pattern matching syntax.

Suggested change
if (msg.Sound is { } id && !_proto.HasIndex<SpeechSoundsPrototype>(id))
if (msg.Sound is not null && !_proto.HasIndex<SpeechSoundsPrototype>(msg.Sound))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A: Roundflow/Antag Area: Roundflow - "What happens in the game", including antagonist roles and their capabilities Changes: UI Changes: Might require knowledge of UI design or code. D2: Medium Difficulty: A good amount of codebase knowledge required. P2: Raised Priority: Item has a raised priority, indicating it might get increased maintainer attention. S: Needs Review Status: Requires additional reviews before being fully accepted size/L Denotes a PR that changes 1000-4999 lines. T: Balance Change Type: Balance changes through direct value changes, or changes to mechanics that affect it T: New Feature Type: New feature or content, or extending existing content T: UI / UX Improvement Type: UI and player facing interactive graphical interfaces
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants