Skip to content

Commit

Permalink
feature: simplified escape menu (#2395)
Browse files Browse the repository at this point in the history
* feature: simplified escape menu

+ In game interface setting to toggle this feature.
+ Fix: "InvalidOperationException: Collection was modified (during iteration);" client crash was happening upon selecting 'yes' on Combat Warning prompt when logging out/exiting.

* fix: ♻️ Apply review changes (I)

* fix: ♻️ Apply review changes (II)
  • Loading branch information
Arufonsu authored Nov 26, 2024
1 parent a3e84ab commit 9f8b51d
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 4 deletions.
4 changes: 4 additions & 0 deletions Intersect.Client.Framework/Database/GameDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public abstract partial class GameDatabase
public bool ShowHealthAsPercentage { get; set; }

public bool ShowManaAsPercentage { get; set; }

public bool SimplifiedEscapeMenu { get; set; }

public TypewriterBehavior TypewriterBehavior { get; set; }

Expand Down Expand Up @@ -130,6 +132,7 @@ public virtual void LoadPreferences()
ShowExperienceAsPercentage = LoadPreference(nameof(ShowExperienceAsPercentage), true);
ShowHealthAsPercentage = LoadPreference(nameof(ShowHealthAsPercentage), false);
ShowManaAsPercentage = LoadPreference(nameof(ShowManaAsPercentage), false);
SimplifiedEscapeMenu = LoadPreference(nameof(SimplifiedEscapeMenu), false);
TypewriterBehavior = LoadPreference(nameof(TypewriterBehavior), TypewriterBehavior.Word);
UIScale = LoadPreference(nameof(UIScale), 1.0f);
WorldZoom = LoadPreference(nameof(WorldZoom), 1.0f);
Expand Down Expand Up @@ -166,6 +169,7 @@ public virtual void SavePreferences()
SavePreference(nameof(ShowExperienceAsPercentage), ShowExperienceAsPercentage);
SavePreference(nameof(ShowHealthAsPercentage), ShowHealthAsPercentage);
SavePreference(nameof(ShowManaAsPercentage), ShowManaAsPercentage);
SavePreference(nameof(SimplifiedEscapeMenu), SimplifiedEscapeMenu);
SavePreference(nameof(TypewriterBehavior), TypewriterBehavior);
SavePreference(nameof(UIScale), UIScale);
SavePreference(nameof(WorldZoom), WorldZoom);
Expand Down
9 changes: 8 additions & 1 deletion Intersect.Client.Framework/Gwen/Control/Base.cs
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,14 @@ public virtual void Dispose()
Gwen.ToolTip.ControlDeleted(this);
Animation.Cancel(this);

mChildren?.ForEach(child => child?.Dispose());
// [Fix]: "InvalidOperationException: Collection was modified (during iteration); enumeration operation may not execute".
// (Creates an array copy of the children to avoid modifying the collection during iteration).
var children = mChildren.ToArray();
foreach (var child in children)
{
child.Dispose();
}

mChildren?.Clear();

mInnerPanel?.Dispose();
Expand Down
11 changes: 10 additions & 1 deletion Intersect.Client/Core/Input.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,16 @@ public static void OnKeyPressed(Keys modifier, Keys key)
}
else
{
Interface.Interface.GameUi?.EscapeMenu?.ToggleHidden();
var simplifiedEscapeMenuSetting = Globals.Database.SimplifiedEscapeMenu;

if (simplifiedEscapeMenuSetting)
{
Interface.Interface.GameUi?.SimplifiedEscapeMenu?.ToggleHidden();
}
else
{
Interface.Interface.GameUi?.EscapeMenu?.ToggleHidden();
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions Intersect.Client/Interface/Game/GameInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public GameInterface(Canvas canvas) : base(canvas)
{
GameCanvas = canvas;
EscapeMenu = new EscapeMenu(GameCanvas) {IsHidden = true};
SimplifiedEscapeMenu = new SimplifiedEscapeMenu(GameCanvas) {IsHidden = true};
AnnouncementWindow = new AnnouncementWindow(GameCanvas) { IsHidden = true };

InitGameGui();
Expand All @@ -101,6 +102,8 @@ public GameInterface(Canvas canvas) : base(canvas)
public Canvas GameCanvas { get; }

public EscapeMenu EscapeMenu { get; }

public SimplifiedEscapeMenu SimplifiedEscapeMenu { get; }

public AnnouncementWindow AnnouncementWindow { get; }

Expand Down
13 changes: 11 additions & 2 deletions Intersect.Client/Interface/Game/Menu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -355,9 +355,18 @@ public bool HasWindowsOpen()
}

//Input Handlers
private static void MenuButtonClicked(Base sender, ClickedEventArgs arguments)
private void MenuButtonClicked(Base sender, ClickedEventArgs arguments)
{
Interface.GameUi?.EscapeMenu?.ToggleHidden();
var simplifiedEscapeMenuSetting = Globals.Database.SimplifiedEscapeMenu;

if (simplifiedEscapeMenuSetting)
{
Interface.GameUi?.SimplifiedEscapeMenu?.ToggleHidden(mMenuButton);
}
else
{
Interface.GameUi?.EscapeMenu?.ToggleHidden();
}
}

private void PartyBtn_Clicked(Base sender, ClickedEventArgs arguments)
Expand Down
167 changes: 167 additions & 0 deletions Intersect.Client/Interface/Game/SimplifiedEscapeMenu.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
using Intersect.Client.Core;
using Intersect.Client.Framework.File_Management;
using Intersect.Client.Framework.Gwen;
using Intersect.Client.Framework.Gwen.Control;
using Intersect.Client.Framework.Gwen.Control.EventArguments;
using Intersect.Client.General;
using Intersect.Client.Interface.Shared;
using Intersect.Client.Localization;
using Intersect.Utilities;

namespace Intersect.Client.Interface.Game;

public sealed partial class SimplifiedEscapeMenu : Framework.Gwen.Control.Menu
{
private readonly SettingsWindow _settingsWindow;
private readonly MenuItem _settings;
private readonly MenuItem _character;
private readonly MenuItem _logout;
private readonly MenuItem _exit;

public SimplifiedEscapeMenu(Canvas gameCanvas) : base(gameCanvas, nameof(SimplifiedEscapeMenu))
{
IsHidden = true;
IconMarginDisabled = true;
_settingsWindow = new SettingsWindow(gameCanvas, null, null);

Children.Clear();

_settings = AddItem(Strings.EscapeMenu.Settings);
_character = AddItem(Strings.EscapeMenu.CharacterSelect);
_logout = AddItem(Strings.EscapeMenu.Logout);
_exit = AddItem(Strings.EscapeMenu.ExitToDesktop);

_settings.Clicked += OpenSettingsWindow;
_character.Clicked += LogoutToCharacterSelectSelectClicked;
_logout.Clicked += LogoutToMainToMainMenuClicked;
_exit.Clicked += ExitToDesktopToDesktopClicked;

LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer?.GetResolutionString());
}

public void ToggleHidden(Button? target)
{
if (!_settingsWindow.IsHidden || target == null)
{
return;
}

if (this.IsHidden)
{
// Position the context menu within the game canvas if near borders.
var menuPosX = target.LocalPosToCanvas(new Point(0, 0)).X;
var menuPosY = target.LocalPosToCanvas(new Point(0, 0)).Y;
var newX = menuPosX;
var newY = menuPosY + target.Height + 6;

if (newX + Width >= Canvas?.Width)
{
newX = menuPosX - Width + target.Width;
}

if (newY + Height >= Canvas?.Height)
{
newY = menuPosY - Height - 6;
}

SizeToChildren();
Open(Pos.None);
SetPosition(newX, newY);
}
else
{
Close();
}
}

private void LogoutToCharacterSelectSelectClicked(Base sender, ClickedEventArgs arguments)
{
if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds)
{
_ = new InputBox(
title: Strings.Combat.WarningTitle,
prompt: Strings.Combat.WarningCharacterSelect,
inputType: InputBox.InputType.YesNo,
onSuccess: LogoutToCharacterSelect
);
}
else
{
LogoutToCharacterSelect(null, null);
}
}

private void LogoutToMainToMainMenuClicked(Base sender, ClickedEventArgs arguments)
{
if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds)
{
_ = new InputBox(
title: Strings.Combat.WarningTitle,
prompt: Strings.Combat.WarningLogout,
inputType: InputBox.InputType.YesNo,
onSuccess: LogoutToMainMenu
);
}
else
{
LogoutToMainMenu(null, null);
}
}

private void ExitToDesktopToDesktopClicked(Base sender, ClickedEventArgs arguments)
{
if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds)
{
_ = new InputBox(
title: Strings.Combat.WarningTitle,
prompt: Strings.Combat.WarningExitDesktop,
inputType: InputBox.InputType.YesNo,
onSuccess: ExitToDesktop
);
}
else
{
ExitToDesktop(null, null);
}
}

private void OpenSettingsWindow(object? sender, EventArgs? e)
{
if (!_settingsWindow.IsHidden)
{
return;
}

_settingsWindow.Show();
}

private static void LogoutToCharacterSelect(object? sender, EventArgs? e)
{
if (Globals.Me != null)
{
Globals.Me.CombatTimer = 0;
}

Main.Logout(true);
}

private static void LogoutToMainMenu(object? sender, EventArgs? e)
{
if (Globals.Me != null)
{
Globals.Me.CombatTimer = 0;
}

Main.Logout(false);
}

private static void ExitToDesktop(object? sender, EventArgs? e)
{
if (Globals.Me != null)
{
Globals.Me.CombatTimer = 0;
}

Globals.IsRunning = false;
}
}
9 changes: 9 additions & 0 deletions Intersect.Client/Interface/Shared/SettingsWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public partial class SettingsWindow : ImagePanel
private readonly LabeledCheckBox _showExperienceAsPercentageCheckbox;
private readonly LabeledCheckBox _showHealthAsPercentageCheckbox;
private readonly LabeledCheckBox _showManaAsPercentageCheckbox;
private readonly LabeledCheckBox _simplifiedEscapeMenu;

// Game Settings - Information.
private readonly ScrollControl _informationSettings;
Expand Down Expand Up @@ -180,6 +181,12 @@ public SettingsWindow(Base parent, MainMenu? mainMenu, EscapeMenu? escapeMenu) :
{
Text = Strings.Settings.ShowManaAsPercentage
};

// Game Settings - Interface: simplified escape menu.
_simplifiedEscapeMenu = new LabeledCheckBox(_interfaceSettings, "SimplifiedEscapeMenu")
{
Text = Strings.Settings.SimplifiedEscapeMenu
};

// Game Settings - Information.
_informationSettings = new ScrollControl(_gameSettingsContainer, "InformationSettings");
Expand Down Expand Up @@ -730,6 +737,7 @@ public void Show(bool returnToMenu = false)
_showHealthAsPercentageCheckbox.IsChecked = Globals.Database.ShowHealthAsPercentage;
_showManaAsPercentageCheckbox.IsChecked = Globals.Database.ShowManaAsPercentage;
_showExperienceAsPercentageCheckbox.IsChecked = Globals.Database.ShowExperienceAsPercentage;
_simplifiedEscapeMenu.IsChecked = Globals.Database.SimplifiedEscapeMenu;
_friendOverheadInfoCheckbox.IsChecked = Globals.Database.FriendOverheadInfo;
_guildMemberOverheadInfoCheckbox.IsChecked = Globals.Database.GuildMemberOverheadInfo;
_myOverheadInfoCheckbox.IsChecked = Globals.Database.MyOverheadInfo;
Expand Down Expand Up @@ -910,6 +918,7 @@ private void SettingsApplyBtn_Clicked(Base sender, ClickedEventArgs arguments)
Globals.Database.ShowExperienceAsPercentage = _showExperienceAsPercentageCheckbox.IsChecked;
Globals.Database.ShowHealthAsPercentage = _showHealthAsPercentageCheckbox.IsChecked;
Globals.Database.ShowManaAsPercentage = _showManaAsPercentageCheckbox.IsChecked;
Globals.Database.SimplifiedEscapeMenu = _simplifiedEscapeMenu.IsChecked;
Globals.Database.FriendOverheadInfo = _friendOverheadInfoCheckbox.IsChecked;
Globals.Database.GuildMemberOverheadInfo = _guildMemberOverheadInfoCheckbox.IsChecked;
Globals.Database.MyOverheadInfo = _myOverheadInfoCheckbox.IsChecked;
Expand Down
3 changes: 3 additions & 0 deletions Intersect.Client/Localization/Strings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1932,6 +1932,9 @@ public partial struct Settings

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public static LocalizedString ShowPlayerOverheadInformation = @"Show players overhead information";

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public static LocalizedString SimplifiedEscapeMenu = @"Simplified escape menu";

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public static LocalizedString StickyTarget = @"Sticky Target";
Expand Down

0 comments on commit 9f8b51d

Please sign in to comment.