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

[Feature] Emotes Menu Type #215

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Content.Client/Chat/UI/EmotesMenu.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Linq;
using System.Numerics;
using Content.Client._White.UI.Emotes;
using Content.Client.UserInterface.Controls;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Speech;
Expand All @@ -14,7 +15,7 @@
namespace Content.Client.Chat.UI;

[GenerateTypedNameReferences]
public sealed partial class EmotesMenu : RadialMenu
public sealed partial class EmotesMenu : RadialMenu, IBaseEmoteMenu // WD EDIT
{
[Dependency] private readonly EntityManager _entManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
Expand Down
7 changes: 7 additions & 0 deletions Content.Client/Options/UI/Tabs/MiscTab.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
<Control MinSize="4 0" />
<OptionButton Name="HudLayoutOption" />
</BoxContainer>
<!--WD EDIT START-->
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'ui-options-emotes-menu'}" />
<Control MinSize="4 0" />
<OptionButton Name="EmotesMenuType" />
</BoxContainer>
<!--WD EDIT END-->
<Label Text="{Loc 'ui-options-general-accessibility'}"
FontColorOverride="{xNamespace:Static s:StyleNano.NanoGold}"
StyleClasses="LabelKeyText"/>
Expand Down
31 changes: 31 additions & 0 deletions Content.Client/Options/UI/Tabs/MiscTab.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Linq;
using Content.Client.UserInterface.Screens;
using Content.Shared._White;
using Content.Shared._White.UI.Emotes;
using Content.Shared.CCVar;
using Content.Shared.HUD;
using Robust.Client.AutoGenerated;
Expand Down Expand Up @@ -60,6 +61,29 @@ public MiscTab()
UpdateApplyButton();
};

// WD EDIT START
id = 0;
var emotesMenuStyle = _cfg.GetCVar(WhiteCVars.EmotesMenuStyle);
foreach (var type in Enum.GetValues(typeof(EmotesMenuType)))
{
var name = type.ToString()!;
EmotesMenuType.AddItem(name, id);

if (name == emotesMenuStyle)
EmotesMenuType.SelectId(id);

EmotesMenuType.SetItemMetadata(id, name);

id++;
}

EmotesMenuType.OnItemSelected += args =>
{
EmotesMenuType.SelectId(args.Id);
UpdateApplyButton();
};
// WD EDIT END

// Channel can be null in replays so.
// ReSharper disable once ConditionalAccessQualifierIsNonNullableAccordingToAPIContract
ShowOocPatronColor.Visible = _playerManager.LocalSession?.Channel?.UserData.PatronTier is { };
Expand Down Expand Up @@ -169,6 +193,11 @@ private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
_cfg.SetCVar(CCVars.UILayout, opt);
}

// WD EDIT START
if (EmotesMenuType.SelectedMetadata is string emotesMenuType)
_cfg.SetCVar(WhiteCVars.EmotesMenuStyle, emotesMenuType);
// WD EDIT END

_cfg.SaveToFile();
UpdateApplyButton();
}
Expand All @@ -177,6 +206,7 @@ private void UpdateApplyButton()
{
var isHudThemeSame = HudThemeOption.SelectedId == _hudThemeIdToIndex.GetValueOrDefault(_cfg.GetCVar(CVars.InterfaceTheme), 0);
var isLayoutSame = HudLayoutOption.SelectedMetadata is string opt && opt == _cfg.GetCVar(CCVars.UILayout);
var isEmotesMenuTypeSame = EmotesMenuType.SelectedMetadata is string emotesMenuType && emotesMenuType == _cfg.GetCVar(WhiteCVars.EmotesMenuStyle); // WD EDIT
var isDiscordSame = DiscordRich.Pressed == _cfg.GetCVar(CVars.DiscordEnabled);
var isShowHeldItemSame = ShowHeldItemCheckBox.Pressed == _cfg.GetCVar(CCVars.HudHeldItemShow);
var isCombatModeIndicatorsSame = ShowCombatModeIndicatorsCheckBox.Pressed == _cfg.GetCVar(CCVars.CombatModeIndicatorsPointShow);
Expand All @@ -200,6 +230,7 @@ private void UpdateApplyButton()

ApplyButton.Disabled = isHudThemeSame &&
isLayoutSame &&
isEmotesMenuTypeSame && // WD EDIT
isDiscordSame &&
isShowHeldItemSame &&
isCombatModeIndicatorsSame &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Content.Client._White.UI.Emotes;
using Content.Client.UserInterface.Systems.Actions;
using Content.Client.UserInterface.Systems.Admin;
using Content.Client.UserInterface.Systems.Bwoink;
using Content.Client.UserInterface.Systems.Character;
using Content.Client.UserInterface.Systems.Crafting;
using Content.Client.UserInterface.Systems.Emotes;
using Content.Client.UserInterface.Systems.EscapeMenu;
using Content.Client.UserInterface.Systems.Gameplay;
using Content.Client.UserInterface.Systems.Guidebook;
Expand All @@ -24,8 +24,8 @@ public sealed class GameTopMenuBarUIController : UIController
[Dependency] private readonly ActionUIController _action = default!;
[Dependency] private readonly SandboxUIController _sandbox = default!;
[Dependency] private readonly GuidebookUIController _guidebook = default!;
[Dependency] private readonly EmotesUIController _emotes = default!;
[Dependency] private readonly LanguageMenuUIController _language = default!;
[Dependency] private readonly WhiteEmotesUIController _whiteEmotes = default!; // WD EDIT

private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull<GameTopMenuBar>();

Expand All @@ -48,8 +48,8 @@ public void UnloadButtons()
_ahelp.UnloadButton();
_action.UnloadButton();
_sandbox.UnloadButton();
_emotes.UnloadButton();
_language.UnloadButton();
_whiteEmotes.UnloadButton(); // WD EDIT
}

public void LoadButtons()
Expand All @@ -62,7 +62,7 @@ public void LoadButtons()
_ahelp.LoadButton();
_action.LoadButton();
_sandbox.LoadButton();
_emotes.LoadButton();
_language.LoadButton();
_whiteEmotes.LoadButton(); // WD EDIT
}
}
14 changes: 14 additions & 0 deletions Content.Client/_White/UI/Emotes/EmotesMenuType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Content.Shared._White.UI.Emotes;


public enum EmotesMenuType
{
/// <summary>
/// The classic White Dream emotes menu
/// </summary>
Window,
/// <summary>
/// The temporary SS14 emotes menu
/// </summary>
Radial,
}
12 changes: 12 additions & 0 deletions Content.Client/_White/UI/Emotes/WhiteEmotesMenu.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<windows:WhiteEmotesMenu
xmlns="https://spacestation14.io"
xmlns:windows="clr-namespace:Content.Client._White.UI.Emotes"
Title="{Loc 'emotions-menu-title'}"
VerticalExpand="True"
HorizontalExpand="True"
MinHeight="250"
MinWidth="300">
<GridContainer Name="EmotionsContainer" Access="Public" Columns="3">

</GridContainer>
</windows:WhiteEmotesMenu>
69 changes: 69 additions & 0 deletions Content.Client/_White/UI/Emotes/WhiteEmotesMenu.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Linq;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Speech;
using Content.Shared.Whitelist;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;


namespace Content.Client._White.UI.Emotes;

[GenerateTypedNameReferences]
public sealed partial class WhiteEmotesMenu : DefaultWindow, IBaseEmoteMenu
{
[Dependency] private readonly EntityManager _entManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ISharedPlayerManager _playerManager = default!;

public event Action<ProtoId<EmotePrototype>>? OnPlayEmote;

public WhiteEmotesMenu()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);

var whitelistSystem = _entManager.System<EntityWhitelistSystem>();

var emotes = _prototypeManager.EnumeratePrototypes<EmotePrototype>().ToList();
emotes.Sort((a,b) => string.Compare(a.Name, b.Name, StringComparison.Ordinal));
foreach (var emote in emotes)
{
var player = _playerManager.LocalSession?.AttachedEntity;
if (emote.Category == EmoteCategory.Invalid ||
emote.ChatTriggers.Count == 0 ||
!(player.HasValue && whitelistSystem.IsWhitelistPassOrNull(emote.Whitelist, player.Value)) ||
whitelistSystem.IsBlacklistPass(emote.Blacklist, player.Value))
continue;

if (!emote.Available &&
_entManager.TryGetComponent<SpeechComponent>(player.Value, out var speech) &&
!speech.AllowedEmotes.Contains(emote.ID))
continue;

var button = new EmoteMenuButton
{
ClipText = true,
HorizontalExpand = true,
VerticalExpand = true,
MinWidth = 120,
MaxWidth = 250,
MaxHeight = 35,
TextAlign = Label.AlignMode.Left,
Text = Loc.GetString(emote.Name),
ProtoId = emote,
};

button.OnPressed += _ => OnPlayEmote?.Invoke(emote);
EmotionsContainer.AddChild(button);
}
}
}

public sealed class EmoteMenuButton : Button
{
public ProtoId<EmotePrototype> ProtoId { get; set; }
}
158 changes: 158 additions & 0 deletions Content.Client/_White/UI/Emotes/WhiteEmotesUIController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
using System.Numerics;
using Content.Client.Chat.UI;
using Content.Client.Gameplay;
using Content.Client.UserInterface.Controls;
using Content.Shared._White;
using Content.Shared._White.UI.Emotes;
using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Input;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.UserInterface.Controllers;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
using Robust.Shared.Input.Binding;
using Robust.Shared.Prototypes;

namespace Content.Client._White.UI.Emotes;

public sealed class WhiteEmotesUIController : UIController, IOnStateChanged<GameplayState>
{
[Dependency] private readonly IClyde _displayManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;

private IBaseEmoteMenu? _window;
private MenuButton? EmotesButton => UIManager.GetActiveUIWidgetOrNull<UserInterface.Systems.MenuBar.Widgets.GameTopMenuBar>()?.EmotesButton;

private DateTime _lastEmotionTimeUse = DateTime.Now;
private const float EmoteCooldown = 1.5f;

public void OnStateEntered(GameplayState state) =>
CommandBinds.Builder
.Bind(ContentKeyFunctions.OpenEmotesMenu, InputCmdHandler.FromDelegate(_ => ToggleWindow(false)))
.Register<WhiteEmotesUIController>();

public void OnStateExited(GameplayState state) =>
CommandBinds.Unregister<WhiteEmotesUIController>();

public void LoadButton()
{
if (EmotesButton == null)
return;

EmotesButton.OnPressed += EmotionsButtonPressed;
}

public void UnloadButton()
{
if (EmotesButton == null)
return;

EmotesButton.OnPressed -= EmotionsButtonPressed;
}

private void OnWindowOpened()
{
if (EmotesButton != null)
EmotesButton.Pressed = true;
}

private void OnWindowClosed()
{
if (EmotesButton != null)
EmotesButton.Pressed = false;

CloseWindow();
}

private void CloseWindow()
{
if (_window == null)
return;

_window.Dispose();
_window = null;
}

private void EmotionsButtonPressed(BaseButton.ButtonEventArgs args)
{
ToggleWindow(true);
}

private void ToggleWindow(bool centered)
{
if (_window == null)
{
if (!Enum.TryParse(_configurationManager.GetCVar(WhiteCVars.EmotesMenuStyle), out EmotesMenuType emotesMenuStyle))
emotesMenuStyle = EmotesMenuType.Window;

// setup window
switch (emotesMenuStyle)
{
case EmotesMenuType.Window:
_window = UIManager.CreateWindow<WhiteEmotesMenu>();
break;
case EmotesMenuType.Radial:
_window = UIManager.CreateWindow<EmotesMenu>();
break;
default:
_window = UIManager.CreateWindow<WhiteEmotesMenu>();
break;
}

_window.OnClose += OnWindowClosed;
_window.OnOpen += OnWindowOpened;
_window.OnPlayEmote += OnPlayEmote;

if (EmotesButton != null)
EmotesButton.SetClickPressed(true);

if (centered)
{
_window.OpenCentered();
}
else
{
// Open the menu, centered on the mouse
var vpSize = _displayManager.ScreenSize;
_window.OpenCenteredAt(_inputManager.MouseScreenPosition.Position / vpSize);
}
}
else
{
_window.OnClose -= OnWindowClosed;
_window.OnOpen -= OnWindowOpened;
_window.OnPlayEmote -= OnPlayEmote;

if (EmotesButton != null)
EmotesButton.SetClickPressed(false);

CloseWindow();
}
}

private void OnPlayEmote(ProtoId<EmotePrototype> protoId)
{
var timeSpan = DateTime.Now - _lastEmotionTimeUse;
var seconds = timeSpan.TotalSeconds;
if (seconds < EmoteCooldown)
return;

_lastEmotionTimeUse = DateTime.Now;

_entityManager.RaisePredictiveEvent(new PlayEmoteMessage(protoId));
}
}

public interface IBaseEmoteMenu
{
public event Action<ProtoId<EmotePrototype>>? OnPlayEmote;
public event Action? OnClose;
public event Action? OnOpen;
public void OpenCenteredAt(Vector2 relativePosition);
public void OpenCentered();
public void Dispose();
}
Loading
Loading