Skip to content

Commit 9f8b51d

Browse files
authored
feature: simplified escape menu (AscensionGameDev#2395)
* 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)
1 parent a3e84ab commit 9f8b51d

File tree

8 files changed

+215
-4
lines changed

8 files changed

+215
-4
lines changed

Intersect.Client.Framework/Database/GameDatabase.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public abstract partial class GameDatabase
5858
public bool ShowHealthAsPercentage { get; set; }
5959

6060
public bool ShowManaAsPercentage { get; set; }
61+
62+
public bool SimplifiedEscapeMenu { get; set; }
6163

6264
public TypewriterBehavior TypewriterBehavior { get; set; }
6365

@@ -130,6 +132,7 @@ public virtual void LoadPreferences()
130132
ShowExperienceAsPercentage = LoadPreference(nameof(ShowExperienceAsPercentage), true);
131133
ShowHealthAsPercentage = LoadPreference(nameof(ShowHealthAsPercentage), false);
132134
ShowManaAsPercentage = LoadPreference(nameof(ShowManaAsPercentage), false);
135+
SimplifiedEscapeMenu = LoadPreference(nameof(SimplifiedEscapeMenu), false);
133136
TypewriterBehavior = LoadPreference(nameof(TypewriterBehavior), TypewriterBehavior.Word);
134137
UIScale = LoadPreference(nameof(UIScale), 1.0f);
135138
WorldZoom = LoadPreference(nameof(WorldZoom), 1.0f);
@@ -166,6 +169,7 @@ public virtual void SavePreferences()
166169
SavePreference(nameof(ShowExperienceAsPercentage), ShowExperienceAsPercentage);
167170
SavePreference(nameof(ShowHealthAsPercentage), ShowHealthAsPercentage);
168171
SavePreference(nameof(ShowManaAsPercentage), ShowManaAsPercentage);
172+
SavePreference(nameof(SimplifiedEscapeMenu), SimplifiedEscapeMenu);
169173
SavePreference(nameof(TypewriterBehavior), TypewriterBehavior);
170174
SavePreference(nameof(UIScale), UIScale);
171175
SavePreference(nameof(WorldZoom), WorldZoom);

Intersect.Client.Framework/Gwen/Control/Base.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,14 @@ public virtual void Dispose()
765765
Gwen.ToolTip.ControlDeleted(this);
766766
Animation.Cancel(this);
767767

768-
mChildren?.ForEach(child => child?.Dispose());
768+
// [Fix]: "InvalidOperationException: Collection was modified (during iteration); enumeration operation may not execute".
769+
// (Creates an array copy of the children to avoid modifying the collection during iteration).
770+
var children = mChildren.ToArray();
771+
foreach (var child in children)
772+
{
773+
child.Dispose();
774+
}
775+
769776
mChildren?.Clear();
770777

771778
mInnerPanel?.Dispose();

Intersect.Client/Core/Input.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,16 @@ public static void OnKeyPressed(Keys modifier, Keys key)
133133
}
134134
else
135135
{
136-
Interface.Interface.GameUi?.EscapeMenu?.ToggleHidden();
136+
var simplifiedEscapeMenuSetting = Globals.Database.SimplifiedEscapeMenu;
137+
138+
if (simplifiedEscapeMenuSetting)
139+
{
140+
Interface.Interface.GameUi?.SimplifiedEscapeMenu?.ToggleHidden();
141+
}
142+
else
143+
{
144+
Interface.Interface.GameUi?.EscapeMenu?.ToggleHidden();
145+
}
137146
}
138147
}
139148

Intersect.Client/Interface/Game/GameInterface.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public GameInterface(Canvas canvas) : base(canvas)
9393
{
9494
GameCanvas = canvas;
9595
EscapeMenu = new EscapeMenu(GameCanvas) {IsHidden = true};
96+
SimplifiedEscapeMenu = new SimplifiedEscapeMenu(GameCanvas) {IsHidden = true};
9697
AnnouncementWindow = new AnnouncementWindow(GameCanvas) { IsHidden = true };
9798

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

103104
public EscapeMenu EscapeMenu { get; }
105+
106+
public SimplifiedEscapeMenu SimplifiedEscapeMenu { get; }
104107

105108
public AnnouncementWindow AnnouncementWindow { get; }
106109

Intersect.Client/Interface/Game/Menu.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,9 +355,18 @@ public bool HasWindowsOpen()
355355
}
356356

357357
//Input Handlers
358-
private static void MenuButtonClicked(Base sender, ClickedEventArgs arguments)
358+
private void MenuButtonClicked(Base sender, ClickedEventArgs arguments)
359359
{
360-
Interface.GameUi?.EscapeMenu?.ToggleHidden();
360+
var simplifiedEscapeMenuSetting = Globals.Database.SimplifiedEscapeMenu;
361+
362+
if (simplifiedEscapeMenuSetting)
363+
{
364+
Interface.GameUi?.SimplifiedEscapeMenu?.ToggleHidden(mMenuButton);
365+
}
366+
else
367+
{
368+
Interface.GameUi?.EscapeMenu?.ToggleHidden();
369+
}
361370
}
362371

363372
private void PartyBtn_Clicked(Base sender, ClickedEventArgs arguments)
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
using Intersect.Client.Core;
2+
using Intersect.Client.Framework.File_Management;
3+
using Intersect.Client.Framework.Gwen;
4+
using Intersect.Client.Framework.Gwen.Control;
5+
using Intersect.Client.Framework.Gwen.Control.EventArguments;
6+
using Intersect.Client.General;
7+
using Intersect.Client.Interface.Shared;
8+
using Intersect.Client.Localization;
9+
using Intersect.Utilities;
10+
11+
namespace Intersect.Client.Interface.Game;
12+
13+
public sealed partial class SimplifiedEscapeMenu : Framework.Gwen.Control.Menu
14+
{
15+
private readonly SettingsWindow _settingsWindow;
16+
private readonly MenuItem _settings;
17+
private readonly MenuItem _character;
18+
private readonly MenuItem _logout;
19+
private readonly MenuItem _exit;
20+
21+
public SimplifiedEscapeMenu(Canvas gameCanvas) : base(gameCanvas, nameof(SimplifiedEscapeMenu))
22+
{
23+
IsHidden = true;
24+
IconMarginDisabled = true;
25+
_settingsWindow = new SettingsWindow(gameCanvas, null, null);
26+
27+
Children.Clear();
28+
29+
_settings = AddItem(Strings.EscapeMenu.Settings);
30+
_character = AddItem(Strings.EscapeMenu.CharacterSelect);
31+
_logout = AddItem(Strings.EscapeMenu.Logout);
32+
_exit = AddItem(Strings.EscapeMenu.ExitToDesktop);
33+
34+
_settings.Clicked += OpenSettingsWindow;
35+
_character.Clicked += LogoutToCharacterSelectSelectClicked;
36+
_logout.Clicked += LogoutToMainToMainMenuClicked;
37+
_exit.Clicked += ExitToDesktopToDesktopClicked;
38+
39+
LoadJsonUi(GameContentManager.UI.InGame, Graphics.Renderer?.GetResolutionString());
40+
}
41+
42+
public void ToggleHidden(Button? target)
43+
{
44+
if (!_settingsWindow.IsHidden || target == null)
45+
{
46+
return;
47+
}
48+
49+
if (this.IsHidden)
50+
{
51+
// Position the context menu within the game canvas if near borders.
52+
var menuPosX = target.LocalPosToCanvas(new Point(0, 0)).X;
53+
var menuPosY = target.LocalPosToCanvas(new Point(0, 0)).Y;
54+
var newX = menuPosX;
55+
var newY = menuPosY + target.Height + 6;
56+
57+
if (newX + Width >= Canvas?.Width)
58+
{
59+
newX = menuPosX - Width + target.Width;
60+
}
61+
62+
if (newY + Height >= Canvas?.Height)
63+
{
64+
newY = menuPosY - Height - 6;
65+
}
66+
67+
SizeToChildren();
68+
Open(Pos.None);
69+
SetPosition(newX, newY);
70+
}
71+
else
72+
{
73+
Close();
74+
}
75+
}
76+
77+
private void LogoutToCharacterSelectSelectClicked(Base sender, ClickedEventArgs arguments)
78+
{
79+
if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds)
80+
{
81+
_ = new InputBox(
82+
title: Strings.Combat.WarningTitle,
83+
prompt: Strings.Combat.WarningCharacterSelect,
84+
inputType: InputBox.InputType.YesNo,
85+
onSuccess: LogoutToCharacterSelect
86+
);
87+
}
88+
else
89+
{
90+
LogoutToCharacterSelect(null, null);
91+
}
92+
}
93+
94+
private void LogoutToMainToMainMenuClicked(Base sender, ClickedEventArgs arguments)
95+
{
96+
if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds)
97+
{
98+
_ = new InputBox(
99+
title: Strings.Combat.WarningTitle,
100+
prompt: Strings.Combat.WarningLogout,
101+
inputType: InputBox.InputType.YesNo,
102+
onSuccess: LogoutToMainMenu
103+
);
104+
}
105+
else
106+
{
107+
LogoutToMainMenu(null, null);
108+
}
109+
}
110+
111+
private void ExitToDesktopToDesktopClicked(Base sender, ClickedEventArgs arguments)
112+
{
113+
if (Globals.Me?.CombatTimer > Timing.Global.Milliseconds)
114+
{
115+
_ = new InputBox(
116+
title: Strings.Combat.WarningTitle,
117+
prompt: Strings.Combat.WarningExitDesktop,
118+
inputType: InputBox.InputType.YesNo,
119+
onSuccess: ExitToDesktop
120+
);
121+
}
122+
else
123+
{
124+
ExitToDesktop(null, null);
125+
}
126+
}
127+
128+
private void OpenSettingsWindow(object? sender, EventArgs? e)
129+
{
130+
if (!_settingsWindow.IsHidden)
131+
{
132+
return;
133+
}
134+
135+
_settingsWindow.Show();
136+
}
137+
138+
private static void LogoutToCharacterSelect(object? sender, EventArgs? e)
139+
{
140+
if (Globals.Me != null)
141+
{
142+
Globals.Me.CombatTimer = 0;
143+
}
144+
145+
Main.Logout(true);
146+
}
147+
148+
private static void LogoutToMainMenu(object? sender, EventArgs? e)
149+
{
150+
if (Globals.Me != null)
151+
{
152+
Globals.Me.CombatTimer = 0;
153+
}
154+
155+
Main.Logout(false);
156+
}
157+
158+
private static void ExitToDesktop(object? sender, EventArgs? e)
159+
{
160+
if (Globals.Me != null)
161+
{
162+
Globals.Me.CombatTimer = 0;
163+
}
164+
165+
Globals.IsRunning = false;
166+
}
167+
}

Intersect.Client/Interface/Shared/SettingsWindow.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public partial class SettingsWindow : ImagePanel
4545
private readonly LabeledCheckBox _showExperienceAsPercentageCheckbox;
4646
private readonly LabeledCheckBox _showHealthAsPercentageCheckbox;
4747
private readonly LabeledCheckBox _showManaAsPercentageCheckbox;
48+
private readonly LabeledCheckBox _simplifiedEscapeMenu;
4849

4950
// Game Settings - Information.
5051
private readonly ScrollControl _informationSettings;
@@ -180,6 +181,12 @@ public SettingsWindow(Base parent, MainMenu? mainMenu, EscapeMenu? escapeMenu) :
180181
{
181182
Text = Strings.Settings.ShowManaAsPercentage
182183
};
184+
185+
// Game Settings - Interface: simplified escape menu.
186+
_simplifiedEscapeMenu = new LabeledCheckBox(_interfaceSettings, "SimplifiedEscapeMenu")
187+
{
188+
Text = Strings.Settings.SimplifiedEscapeMenu
189+
};
183190

184191
// Game Settings - Information.
185192
_informationSettings = new ScrollControl(_gameSettingsContainer, "InformationSettings");
@@ -730,6 +737,7 @@ public void Show(bool returnToMenu = false)
730737
_showHealthAsPercentageCheckbox.IsChecked = Globals.Database.ShowHealthAsPercentage;
731738
_showManaAsPercentageCheckbox.IsChecked = Globals.Database.ShowManaAsPercentage;
732739
_showExperienceAsPercentageCheckbox.IsChecked = Globals.Database.ShowExperienceAsPercentage;
740+
_simplifiedEscapeMenu.IsChecked = Globals.Database.SimplifiedEscapeMenu;
733741
_friendOverheadInfoCheckbox.IsChecked = Globals.Database.FriendOverheadInfo;
734742
_guildMemberOverheadInfoCheckbox.IsChecked = Globals.Database.GuildMemberOverheadInfo;
735743
_myOverheadInfoCheckbox.IsChecked = Globals.Database.MyOverheadInfo;
@@ -910,6 +918,7 @@ private void SettingsApplyBtn_Clicked(Base sender, ClickedEventArgs arguments)
910918
Globals.Database.ShowExperienceAsPercentage = _showExperienceAsPercentageCheckbox.IsChecked;
911919
Globals.Database.ShowHealthAsPercentage = _showHealthAsPercentageCheckbox.IsChecked;
912920
Globals.Database.ShowManaAsPercentage = _showManaAsPercentageCheckbox.IsChecked;
921+
Globals.Database.SimplifiedEscapeMenu = _simplifiedEscapeMenu.IsChecked;
913922
Globals.Database.FriendOverheadInfo = _friendOverheadInfoCheckbox.IsChecked;
914923
Globals.Database.GuildMemberOverheadInfo = _guildMemberOverheadInfoCheckbox.IsChecked;
915924
Globals.Database.MyOverheadInfo = _myOverheadInfoCheckbox.IsChecked;

Intersect.Client/Localization/Strings.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,9 @@ public partial struct Settings
19321932

19331933
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
19341934
public static LocalizedString ShowPlayerOverheadInformation = @"Show players overhead information";
1935+
1936+
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
1937+
public static LocalizedString SimplifiedEscapeMenu = @"Simplified escape menu";
19351938

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

0 commit comments

Comments
 (0)