From a452c4fb7d87a7e374a44abb7efe1db8eacf2490 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 31 Mar 2022 22:53:01 -0700 Subject: [PATCH 1/5] Ensure dialogs do not stay open when switching away from PlayingTheGame game state --- EndlessClient/ControlSets/ControlSetFactory.cs | 8 ++++++-- EndlessClient/ControlSets/InGameControlSet.cs | 17 +++++++++++++++-- EndlessClient/Dialogs/ActiveDialogRepository.cs | 14 ++++++++++++-- EndlessClient/GameExecution/GameStateActions.cs | 2 ++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/EndlessClient/ControlSets/ControlSetFactory.cs b/EndlessClient/ControlSets/ControlSetFactory.cs index 8dcd4c74a..941526442 100644 --- a/EndlessClient/ControlSets/ControlSetFactory.cs +++ b/EndlessClient/ControlSets/ControlSetFactory.cs @@ -2,6 +2,7 @@ using AutomaticTypeMapper; using EndlessClient.Content; using EndlessClient.Controllers; +using EndlessClient.Dialogs; using EndlessClient.Dialogs.Factories; using EndlessClient.GameExecution; using EndlessClient.HUD.Controls; @@ -26,6 +27,7 @@ public class ControlSetFactory : IControlSetFactory private readonly ICharacterSelectorProvider _characterSelectorProvider; private readonly IEndlessGameProvider _endlessGameProvider; private readonly IUserInputRepository _userInputRepository; + private readonly IActiveDialogRepository _activeDialogRepository; private IMainButtonController _mainButtonController; private IAccountController _accountController; private ILoginController _loginController; @@ -40,7 +42,8 @@ public class ControlSetFactory : IControlSetFactory ICharacterInfoPanelFactory characterInfoPanelFactory, ICharacterSelectorProvider characterSelectorProvider, IEndlessGameProvider endlessGameProvider, - IUserInputRepository userInputRepository) + IUserInputRepository userInputRepository, + IActiveDialogRepository activeDialogRepository) { _nativeGraphicsManager = nativeGraphicsManager; _messageBoxFactory = messageBoxFactory; @@ -52,6 +55,7 @@ public class ControlSetFactory : IControlSetFactory _characterSelectorProvider = characterSelectorProvider; _endlessGameProvider = endlessGameProvider; _userInputRepository = userInputRepository; + _activeDialogRepository = activeDialogRepository; } public IControlSet CreateControlsForState(GameStates newState, IControlSet currentControlSet) @@ -105,7 +109,7 @@ private IControlSet GetSetBasedOnState(GameStates newState) _endlessGameProvider, _userInputRepository); case GameStates.PlayingTheGame: - return new InGameControlSet(_mainButtonController, _messageBoxFactory, _hudControlsFactory); + return new InGameControlSet(_mainButtonController, _messageBoxFactory, _hudControlsFactory, _activeDialogRepository); default: throw new ArgumentOutOfRangeException(nameof(newState), newState, null); } } diff --git a/EndlessClient/ControlSets/InGameControlSet.cs b/EndlessClient/ControlSets/InGameControlSet.cs index 994376899..e3257d2c2 100644 --- a/EndlessClient/ControlSets/InGameControlSet.cs +++ b/EndlessClient/ControlSets/InGameControlSet.cs @@ -8,6 +8,7 @@ using EndlessClient.HUD.Controls; using EOLib.Localization; using Microsoft.Xna.Framework; +using Optional; using XNAControls; namespace EndlessClient.ControlSets @@ -16,18 +17,20 @@ public class InGameControlSet : BackButtonControlSet { private readonly IEOMessageBoxFactory _messageBoxFactory; private readonly IHudControlsFactory _hudControlsFactory; - + private readonly IActiveDialogRepository _activeDialogRepository; private IReadOnlyDictionary _controls; public override GameStates GameState => GameStates.PlayingTheGame; public InGameControlSet(IMainButtonController mainButtonController, IEOMessageBoxFactory messageBoxFactory, - IHudControlsFactory hudControlsFactory) + IHudControlsFactory hudControlsFactory, + IActiveDialogRepository activeDialogRepository) : base(mainButtonController) { _messageBoxFactory = messageBoxFactory; _hudControlsFactory = hudControlsFactory; + _activeDialogRepository = activeDialogRepository; _controls = new Dictionary(); } @@ -55,5 +58,15 @@ protected override async void DoBackButtonClick(object sender, EventArgs e) if (result == XNADialogResult.OK) _mainButtonController.GoToInitialStateAndDisconnect(); } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _activeDialogRepository.Dispose(); + } + + base.Dispose(disposing); + } } } diff --git a/EndlessClient/Dialogs/ActiveDialogRepository.cs b/EndlessClient/Dialogs/ActiveDialogRepository.cs index f3ea8ef1c..99d81e9d8 100644 --- a/EndlessClient/Dialogs/ActiveDialogRepository.cs +++ b/EndlessClient/Dialogs/ActiveDialogRepository.cs @@ -1,12 +1,13 @@ using AutomaticTypeMapper; using Optional; +using System; using System.Collections.Generic; using System.Linq; using XNAControls; namespace EndlessClient.Dialogs { - public interface IActiveDialogProvider + public interface IActiveDialogProvider : IDisposable { Option FriendIgnoreDialog { get; } @@ -15,7 +16,7 @@ public interface IActiveDialogProvider IReadOnlyList> ActiveDialogs { get; } } - public interface IActiveDialogRepository + public interface IActiveDialogRepository : IDisposable { Option FriendIgnoreDialog { get; set; } @@ -46,5 +47,14 @@ IReadOnlyList> ActiveDialogs IReadOnlyList> IActiveDialogRepository.ActiveDialogs => ActiveDialogs; IReadOnlyList> IActiveDialogProvider.ActiveDialogs => ActiveDialogs; + + public void Dispose() + { + foreach (var dlg in ActiveDialogs) + dlg.MatchSome(d => d.Dispose()); + + FriendIgnoreDialog = Option.None(); + PaperdollDialog = Option.None(); + } } } diff --git a/EndlessClient/GameExecution/GameStateActions.cs b/EndlessClient/GameExecution/GameStateActions.cs index c8b6d299e..ef9b2e1c5 100644 --- a/EndlessClient/GameExecution/GameStateActions.cs +++ b/EndlessClient/GameExecution/GameStateActions.cs @@ -76,6 +76,8 @@ private void RemoveOldComponents(IControlSet currentSet, IControlSet nextSet) component.Dispose(); foreach (var component in componentsToRemove.Where(Game.Components.Contains)) Game.Components.Remove(component); + + currentSet.Dispose(); } private List FindUnusedComponents(IControlSet current, IControlSet next) From 769fa69e763dbecaae0d6bc1c1b8bbcea50a9167 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 31 Mar 2022 23:23:38 -0700 Subject: [PATCH 2/5] Update credit in ChatProcessor --- EOLib/Domain/Chat/ChatProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EOLib/Domain/Chat/ChatProcessor.cs b/EOLib/Domain/Chat/ChatProcessor.cs index aecaf2354..2c7d9576e 100644 --- a/EOLib/Domain/Chat/ChatProcessor.cs +++ b/EOLib/Domain/Chat/ChatProcessor.cs @@ -40,7 +40,7 @@ public string RemoveFirstCharacterIfNeeded(string chat, ChatType chatType, strin public string MakeDrunk(string input) { - // implementation from Phorophor::notepad (thanks Apollo) + // implementation from Phorophor::notepad (thanks Blo) // https://discord.com/channels/723989119503696013/785190349026492437/791376941822246953 var ret = new StringBuilder(); From 14188b3be5bcb47bce235bd54e7008ed02a59588 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 31 Mar 2022 23:23:57 -0700 Subject: [PATCH 3/5] Ensure Paperdoll is not click/dragged when an inventory item is dragged over it --- .../Factories/PaperdollDialogFactory.cs | 5 ++++ EndlessClient/Dialogs/PaperdollDialog.cs | 23 +++++++------------ EndlessClient/EndlessClient.csproj | 2 +- EndlessClient/HUD/Panels/InventoryPanel.cs | 2 +- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/EndlessClient/Dialogs/Factories/PaperdollDialogFactory.cs b/EndlessClient/Dialogs/Factories/PaperdollDialogFactory.cs index 5d1305912..af09b20aa 100644 --- a/EndlessClient/Dialogs/Factories/PaperdollDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/PaperdollDialogFactory.cs @@ -1,5 +1,6 @@ using AutomaticTypeMapper; using EndlessClient.Controllers; +using EndlessClient.ControlSets; using EndlessClient.Dialogs.Services; using EndlessClient.GameExecution; using EndlessClient.HUD; @@ -20,6 +21,7 @@ public class PaperdollDialogFactory : IPaperdollDialogFactory private readonly IStatusLabelSetter _statusLabelSetter; private readonly IPaperdollProvider _paperdollProvider; private readonly IPubFileProvider _pubFileProvider; + private readonly IHudControlProvider _hudControlProvider; private readonly INativeGraphicsManager _nativeGraphicsManager; private IInventoryController _inventoryController; @@ -27,6 +29,7 @@ public class PaperdollDialogFactory : IPaperdollDialogFactory INativeGraphicsManager nativeGraphicsManager, IPaperdollProvider paperdollProvider, IPubFileProvider pubFileProvider, + IHudControlProvider hudControlProvider, IEODialogButtonService eoDialogButtonService, IInventorySpaceValidator inventorySpaceValidator, IEOMessageBoxFactory eoMessageBoxFactory, @@ -34,6 +37,7 @@ public class PaperdollDialogFactory : IPaperdollDialogFactory { _paperdollProvider = paperdollProvider; _pubFileProvider = pubFileProvider; + _hudControlProvider = hudControlProvider; _nativeGraphicsManager = nativeGraphicsManager; _gameStateProvider = gameStateProvider; _eoDialogButtonService = eoDialogButtonService; @@ -49,6 +53,7 @@ public PaperdollDialog Create(ICharacter character, bool isMainCharacter) _inventoryController, _paperdollProvider, _pubFileProvider, + _hudControlProvider, _eoDialogButtonService, _inventorySpaceValidator, _eoMessageBoxFactory, diff --git a/EndlessClient/Dialogs/PaperdollDialog.cs b/EndlessClient/Dialogs/PaperdollDialog.cs index 3ce046937..393d341dc 100644 --- a/EndlessClient/Dialogs/PaperdollDialog.cs +++ b/EndlessClient/Dialogs/PaperdollDialog.cs @@ -1,9 +1,11 @@ using EndlessClient.Controllers; +using EndlessClient.ControlSets; using EndlessClient.Dialogs.Factories; using EndlessClient.Dialogs.Services; using EndlessClient.GameExecution; using EndlessClient.HUD; using EndlessClient.HUD.Inventory; +using EndlessClient.HUD.Panels; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Online; @@ -30,6 +32,7 @@ public class PaperdollDialog : BaseEODialog private readonly IInventoryController _inventoryController; private readonly IPaperdollProvider _paperdollProvider; private readonly IPubFileProvider _pubFileProvider; + private readonly IHudControlProvider _hudControlProvider; private readonly IInventorySpaceValidator _inventorySpaceValidator; private readonly IEOMessageBoxFactory _eoMessageBoxFactory; private readonly IStatusLabelSetter _statusLabelSetter; @@ -55,6 +58,7 @@ public class PaperdollDialog : BaseEODialog IInventoryController inventoryController, IPaperdollProvider paperdollProvider, IPubFileProvider pubFileProvider, + IHudControlProvider hudControlProvider, IEODialogButtonService eoDialogButtonService, IInventorySpaceValidator inventorySpaceValidator, IEOMessageBoxFactory eoMessageBoxFactory, @@ -64,6 +68,7 @@ public class PaperdollDialog : BaseEODialog { _paperdollProvider = paperdollProvider; _pubFileProvider = pubFileProvider; + _hudControlProvider = hudControlProvider; _inventorySpaceValidator = inventorySpaceValidator; _eoMessageBoxFactory = eoMessageBoxFactory; _statusLabelSetter = statusLabelSetter; @@ -125,8 +130,6 @@ public class PaperdollDialog : BaseEODialog protected override void OnUpdateControl(GameTime gameTime) { - base.OnUpdateControl(gameTime); - _paperdollData = _paperdollData.FlatMap(paperdollData => paperdollData.NoneWhen(d => _paperdollProvider.VisibleCharacterPaperdolls.ContainsKey(Character.ID) && !_paperdollProvider.VisibleCharacterPaperdolls[Character.ID].Equals(d))); @@ -141,19 +144,9 @@ protected override void OnUpdateControl(GameTime gameTime) } }); - // todo: dragging to equip/unequip from inventory - /* - if (EOGame.Instance.Hud.IsInventoryDragging()) - { - shouldClickDrag = false; - SuppressParentClickDrag(true); - } - else - { - shouldClickDrag = true; - SuppressParentClickDrag(false); - } - */ + SuppressClickDragEvent(!_hudControlProvider.GetComponent(HUD.Controls.HudControlIdentifier.InventoryPanel).NoItemsDragging()); + + base.OnUpdateControl(gameTime); } protected override void OnDrawControl(GameTime gameTime) diff --git a/EndlessClient/EndlessClient.csproj b/EndlessClient/EndlessClient.csproj index 1bd447a7a..1261ff20f 100644 --- a/EndlessClient/EndlessClient.csproj +++ b/EndlessClient/EndlessClient.csproj @@ -60,6 +60,6 @@ - + diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index aacd99cb7..6fdb9b0b2 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -117,7 +117,7 @@ public class InventoryPanel : XNAPanel, IHudPanel Game.Exiting += SaveInventoryFile; } - public bool NoItemsDragging() => _childItems.All(x => !x.IsDragging); + public bool NoItemsDragging() => !_childItems.Any(x => x.IsDragging); public override void Initialize() { From 86a0cf9a2b3bda8516b7a7355e5610d6ea0fe0dd Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 31 Mar 2022 23:31:15 -0700 Subject: [PATCH 4/5] Implement drag to paperdoll to equip --- EndlessClient/HUD/Panels/HudPanelFactory.cs | 12 ++-- EndlessClient/HUD/Panels/InventoryPanel.cs | 70 +++++++++++---------- 2 files changed, 43 insertions(+), 39 deletions(-) diff --git a/EndlessClient/HUD/Panels/HudPanelFactory.cs b/EndlessClient/HUD/Panels/HudPanelFactory.cs index ede5cf9d3..f7b4767c2 100644 --- a/EndlessClient/HUD/Panels/HudPanelFactory.cs +++ b/EndlessClient/HUD/Panels/HudPanelFactory.cs @@ -2,7 +2,7 @@ using EndlessClient.Content; using EndlessClient.Controllers; using EndlessClient.ControlSets; -using EndlessClient.Dialogs.Actions; +using EndlessClient.Dialogs; using EndlessClient.Dialogs.Factories; using EndlessClient.HUD.Inventory; using EndlessClient.Rendering.Chat; @@ -12,10 +12,8 @@ using EOLib.Domain.Chat; using EOLib.Domain.Item; using EOLib.Domain.Login; -using EOLib.Domain.Map; using EOLib.Graphics; using EOLib.IO.Repositories; -using Microsoft.Xna.Framework.Graphics; namespace EndlessClient.HUD.Panels { @@ -43,6 +41,7 @@ public class HudPanelFactory : IHudPanelFactory private readonly IItemStringService _itemStringService; private readonly IItemNameColorService _itemNameColorService; private readonly IInventoryService _inventoryService; + private readonly IActiveDialogProvider _activeDialogProvider; public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, IInventoryController inventoryController, @@ -62,7 +61,8 @@ public class HudPanelFactory : IHudPanelFactory IStatusLabelSetter statusLabelSetter, IItemStringService itemStringService, IItemNameColorService itemNameColorService, - IInventoryService inventoryService) + IInventoryService inventoryService, + IActiveDialogProvider activeDialogProvider) { _nativeGraphicsManager = nativeGraphicsManager; _inventoryController = inventoryController; @@ -83,6 +83,7 @@ public class HudPanelFactory : IHudPanelFactory _itemStringService = itemStringService; _itemNameColorService = itemNameColorService; _inventoryService = inventoryService; + _activeDialogProvider = activeDialogProvider; } public NewsPanel CreateNewsPanel() @@ -108,7 +109,8 @@ public InventoryPanel CreateInventoryPanel() _characterProvider, _characterInventoryProvider, _pubFileProvider, - _hudControlProvider) { DrawOrder = HUD_CONTROL_LAYER }; + _hudControlProvider, + _activeDialogProvider) { DrawOrder = HUD_CONTROL_LAYER }; } public ActiveSpellsPanel CreateActiveSpellsPanel() diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index 6fdb9b0b2..1a5193d03 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -1,5 +1,6 @@ using EndlessClient.Controllers; using EndlessClient.ControlSets; +using EndlessClient.Dialogs; using EndlessClient.HUD.Controls; using EndlessClient.HUD.Inventory; using EndlessClient.Rendering.Map; @@ -44,6 +45,7 @@ public class InventoryPanel : XNAPanel, IHudPanel private readonly ICharacterInventoryProvider _characterInventoryProvider; private readonly IPubFileProvider _pubFileProvider; // todo: this can probably become EIFFileProvider private readonly IHudControlProvider _hudControlProvider; + private readonly IActiveDialogProvider _activeDialogProvider; private readonly Dictionary _itemSlotMap; private readonly List _childItems = new List(); @@ -67,7 +69,8 @@ public class InventoryPanel : XNAPanel, IHudPanel ICharacterProvider characterProvider, ICharacterInventoryProvider characterInventoryProvider, IPubFileProvider pubFileProvider, - IHudControlProvider hudControlProvider) + IHudControlProvider hudControlProvider, + IActiveDialogProvider activeDialogProvider) { NativeGraphicsManager = nativeGraphicsManager; _inventoryController = inventoryController; @@ -81,6 +84,7 @@ public class InventoryPanel : XNAPanel, IHudPanel _characterInventoryProvider = characterInventoryProvider; _pubFileProvider = pubFileProvider; _hudControlProvider = hudControlProvider; + _activeDialogProvider = activeDialogProvider; _weightLabel = new XNALabel(Constants.FontSize08pt5) { DrawArea = new Rectangle(385, 37, 88, 18), @@ -349,20 +353,40 @@ private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCo var oldSlot = item.Slot; - var mapRenderer = _hudControlProvider.GetComponent(HudControlIdentifier.MapRenderer); - - // todo: if this is a chained drag, restoring the original slot could overlap with another item - if (_drop.MouseOver || mapRenderer.MouseOver) + if (_activeDialogProvider.ActiveDialogs.All(x => !x.HasValue)) { - e.RestoreOriginalSlot = true; - _inventoryController.DropItem(item.Data, item.InventoryItem); - return; + var mapRenderer = _hudControlProvider.GetComponent(HudControlIdentifier.MapRenderer); + // todo: if this is a chained drag, restoring the original slot could overlap with another item + if (_drop.MouseOver || mapRenderer.MouseOver) + { + e.RestoreOriginalSlot = true; + _inventoryController.DropItem(item.Data, item.InventoryItem); + return; + } + else if (_junk.MouseOver) + { + e.RestoreOriginalSlot = true; + _inventoryController.JunkItem(item.Data, item.InventoryItem); + return; + } } - else if (_junk.MouseOver) + else { - e.RestoreOriginalSlot = true; - _inventoryController.JunkItem(item.Data, item.InventoryItem); - return; + var dialogDrop = false; + _activeDialogProvider.PaperdollDialog.MatchSome(x => + { + if (x.MouseOver && x.MouseOverPreviously && item.Data.GetEquipLocation() != EquipLocation.PAPERDOLL_MAX) + { + dialogDrop = true; + _inventoryController.EquipItem(item.Data); + } + }); + + if (dialogDrop) + { + e.RestoreOriginalSlot = true; + return; + } } var fitsInOldSlot = _inventoryService.FitsInSlot(_inventorySlotRepository.FilledSlots, oldSlot, e.Data.Size); @@ -433,28 +457,6 @@ private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCo EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); } } - else if (EOPaperdollDialog.Instance != null && EOPaperdollDialog.Instance.MouseOver && EOPaperdollDialog.Instance.MouseOverPreviously) - { - //equipable items should be equipped - //other item types should do nothing - switch (m_itemData.Type) - { - case ItemType.Accessory: - case ItemType.Armlet: - case ItemType.Armor: - case ItemType.Belt: - case ItemType.Boots: - case ItemType.Bracer: - case ItemType.Gloves: - case ItemType.Hat: - case ItemType.Necklace: - case ItemType.Ring: - case ItemType.Shield: - case ItemType.Weapon: - _handleDoubleClick(); - break; - } - } else if (LockerDialog.Instance != null && LockerDialog.Instance.MouseOver && LockerDialog.Instance.MouseOverPreviously) { byte x = LockerDialog.Instance.X; From 2162c7d7087c4ad12002420dc128f219398d8ebb Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 1 Apr 2022 15:41:58 -0700 Subject: [PATCH 5/5] Drag to/from inventory panel to equip/unequip. Follows semantics of original client. Fix inventory name labels to always render over everything else in the inventory --- .../Extensions/EquipLocationExtensions.cs | 32 +++++++++ EndlessClient/Dialogs/PaperdollDialog.cs | 49 +++++-------- EndlessClient/Dialogs/PaperdollDialogItem.cs | 69 +++++++++++++++++-- .../HUD/Inventory/InventoryPanelItem.cs | 44 ++++++++++-- EndlessClient/HUD/Panels/InventoryPanel.cs | 2 +- 5 files changed, 151 insertions(+), 45 deletions(-) create mode 100644 EndlessClient/Dialogs/Extensions/EquipLocationExtensions.cs diff --git a/EndlessClient/Dialogs/Extensions/EquipLocationExtensions.cs b/EndlessClient/Dialogs/Extensions/EquipLocationExtensions.cs new file mode 100644 index 000000000..b9e269763 --- /dev/null +++ b/EndlessClient/Dialogs/Extensions/EquipLocationExtensions.cs @@ -0,0 +1,32 @@ +using EOLib.IO; +using Microsoft.Xna.Framework; +using System; + +namespace EndlessClient.Dialogs.Extensions +{ + public static class EquipLocationExtensions + { + public static Rectangle GetEquipLocationRectangle(this EquipLocation loc) + { + switch (loc) + { + case EquipLocation.Boots: return new Rectangle(87, 220, 56, 54); + case EquipLocation.Accessory: return new Rectangle(55, 250, 23, 23); + case EquipLocation.Gloves: return new Rectangle(22, 188, 56, 54); + case EquipLocation.Belt: return new Rectangle(87, 188, 56, 23); + case EquipLocation.Armor: return new Rectangle(86, 82, 56, 98); + case EquipLocation.Necklace: return new Rectangle(152, 51, 56, 23); + case EquipLocation.Hat: return new Rectangle(87, 21, 56, 54); + case EquipLocation.Shield: return new Rectangle(152, 82, 56, 98); + case EquipLocation.Weapon: return new Rectangle(22, 82, 56, 98); + case EquipLocation.Ring1: return new Rectangle(152, 190, 23, 23); + case EquipLocation.Ring2: return new Rectangle(185, 190, 23, 23); + case EquipLocation.Armlet1: return new Rectangle(152, 220, 23, 23); + case EquipLocation.Armlet2: return new Rectangle(185, 220, 23, 23); + case EquipLocation.Bracer1: return new Rectangle(152, 250, 23, 23); + case EquipLocation.Bracer2: return new Rectangle(185, 250, 23, 23); + default: throw new ArgumentOutOfRangeException(nameof(loc), "That is not a valid equipment location"); + } + } + } +} diff --git a/EndlessClient/Dialogs/PaperdollDialog.cs b/EndlessClient/Dialogs/PaperdollDialog.cs index 393d341dc..b9ef8ea6f 100644 --- a/EndlessClient/Dialogs/PaperdollDialog.cs +++ b/EndlessClient/Dialogs/PaperdollDialog.cs @@ -1,9 +1,11 @@ using EndlessClient.Controllers; using EndlessClient.ControlSets; +using EndlessClient.Dialogs.Extensions; using EndlessClient.Dialogs.Factories; using EndlessClient.Dialogs.Services; using EndlessClient.GameExecution; using EndlessClient.HUD; +using EndlessClient.HUD.Controls; using EndlessClient.HUD.Inventory; using EndlessClient.HUD.Panels; using EOLib; @@ -19,6 +21,7 @@ using Optional; using Optional.Unsafe; using System; +using System.Collections.Generic; using System.Linq; using XNAControls; @@ -32,7 +35,6 @@ public class PaperdollDialog : BaseEODialog private readonly IInventoryController _inventoryController; private readonly IPaperdollProvider _paperdollProvider; private readonly IPubFileProvider _pubFileProvider; - private readonly IHudControlProvider _hudControlProvider; private readonly IInventorySpaceValidator _inventorySpaceValidator; private readonly IEOMessageBoxFactory _eoMessageBoxFactory; private readonly IStatusLabelSetter _statusLabelSetter; @@ -40,9 +42,12 @@ public class PaperdollDialog : BaseEODialog private readonly Texture2D _characterIconSheet; private readonly Texture2D _background; private Option _characterIconSourceRect; + private readonly InventoryPanel _inventoryPanel; private Option _paperdollData; + private readonly List _childItems; + private readonly IXNALabel _name, _home, _class, @@ -68,7 +73,6 @@ public class PaperdollDialog : BaseEODialog { _paperdollProvider = paperdollProvider; _pubFileProvider = pubFileProvider; - _hudControlProvider = hudControlProvider; _inventorySpaceValidator = inventorySpaceValidator; _eoMessageBoxFactory = eoMessageBoxFactory; _statusLabelSetter = statusLabelSetter; @@ -79,6 +83,10 @@ public class PaperdollDialog : BaseEODialog _characterIconSheet = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 32, true); _characterIconSourceRect = Option.None(); + _inventoryPanel = hudControlProvider.GetComponent(HudControlIdentifier.InventoryPanel); + + _childItems = new List(); + _background = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 49); SetSize(_background.Width, _background.Height / 2); @@ -128,6 +136,8 @@ public class PaperdollDialog : BaseEODialog _paperdollData = Option.None(); } + public bool NoItemsDragging() => !_childItems.Any(x => x.IsBeingDragged); + protected override void OnUpdateControl(GameTime gameTime) { _paperdollData = _paperdollData.FlatMap(paperdollData => @@ -144,7 +154,7 @@ protected override void OnUpdateControl(GameTime gameTime) } }); - SuppressClickDragEvent(!_hudControlProvider.GetComponent(HUD.Controls.HudControlIdentifier.InventoryPanel).NoItemsDragging()); + SuppressClickDragEvent(!NoItemsDragging() || !_inventoryPanel.NoItemsDragging()); base.OnUpdateControl(gameTime); } @@ -191,9 +201,7 @@ private void UpdateDisplayedData(IPaperdollData paperdollData) _guild.Text = Capitalize(paperdollData.Guild); _rank.Text = Capitalize(paperdollData.Rank); - var paperdollDialogItems = ChildControls.OfType().ToList(); - - foreach (var control in paperdollDialogItems) + foreach (var control in _childItems) { control.SetControlUnparented(); control.Dispose(); @@ -206,9 +214,9 @@ private void UpdateDisplayedData(IPaperdollData paperdollData) var id = paperdollData.Paperdoll[equipLocation]; var eifRecord = id.SomeWhen(i => i > 0).Map(i => _pubFileProvider.EIFFile[i]); - var paperdollItem = new PaperdollDialogItem(_nativeGraphicsManager, _isMainCharacter, equipLocation, eifRecord) + var paperdollItem = new PaperdollDialogItem(_nativeGraphicsManager, _inventoryPanel, this, _isMainCharacter, equipLocation, eifRecord) { - DrawArea = GetEquipLocationRectangle(equipLocation) + DrawArea = equipLocation.GetEquipLocationRectangle() }; paperdollItem.OnMouseEnter += (_, _) => @@ -264,6 +272,8 @@ private void UpdateDisplayedData(IPaperdollData paperdollData) paperdollItem.SetParentControl(this); paperdollItem.Initialize(); + + _childItems.Add(paperdollItem); } _characterIconSourceRect = Option.Some(GetOnlineIconSourceRectangle(paperdollData.Icon)); @@ -277,28 +287,5 @@ private static Rectangle GetOnlineIconSourceRectangle(OnlineIcon icon) var (x, y, width, height) = icon.ToChatIcon().GetChatIconRectangleBounds().ValueOrDefault(); return new Rectangle(x, y, width, height); } - - private static Rectangle GetEquipLocationRectangle(EquipLocation loc) - { - switch (loc) - { - case EquipLocation.Boots: return new Rectangle(87, 220, 56, 54); - case EquipLocation.Accessory: return new Rectangle(55, 250, 23, 23); - case EquipLocation.Gloves: return new Rectangle(22, 188, 56, 54); - case EquipLocation.Belt: return new Rectangle(87, 188, 56, 23); - case EquipLocation.Armor: return new Rectangle(86, 82, 56, 98); - case EquipLocation.Necklace: return new Rectangle(152, 51, 56, 23); - case EquipLocation.Hat: return new Rectangle(87, 21, 56, 54); - case EquipLocation.Shield: return new Rectangle(152, 82, 56, 98); - case EquipLocation.Weapon: return new Rectangle(22, 82, 56, 98); - case EquipLocation.Ring1: return new Rectangle(152, 190, 23, 23); - case EquipLocation.Ring2: return new Rectangle(185, 190, 23, 23); - case EquipLocation.Armlet1: return new Rectangle(152, 220, 23, 23); - case EquipLocation.Armlet2: return new Rectangle(185, 220, 23, 23); - case EquipLocation.Bracer1: return new Rectangle(152, 250, 23, 23); - case EquipLocation.Bracer2: return new Rectangle(185, 250, 23, 23); - default: throw new ArgumentOutOfRangeException(nameof(loc), "That is not a valid equipment location"); - } - } } } diff --git a/EndlessClient/Dialogs/PaperdollDialogItem.cs b/EndlessClient/Dialogs/PaperdollDialogItem.cs index b1c52382e..9c0f8a08d 100644 --- a/EndlessClient/Dialogs/PaperdollDialogItem.cs +++ b/EndlessClient/Dialogs/PaperdollDialogItem.cs @@ -1,30 +1,48 @@ -using System; +using EndlessClient.Dialogs.Extensions; +using EndlessClient.HUD.Panels; using EOLib.Graphics; using EOLib.IO; using EOLib.IO.Pub; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Optional; +using System; using XNAControls; namespace EndlessClient.Dialogs { public class PaperdollDialogItem : XNAPictureBox { + private readonly InventoryPanel _inventoryPanel; + private readonly PaperdollDialog _paperdollDialog; private readonly bool _isMainCharacter; private readonly Option _itemInfo; + private bool _beingDragged; + public EquipLocation EquipLocation { get; } public short ItemID => (short)_itemInfo.Match(r => r.ID, () => 0); public event EventHandler RightClick; + public bool IsBeingDragged => _beingDragged; + + private bool LeftButtonReleased => CurrentMouseState.LeftButton == ButtonState.Released && PreviousMouseState.LeftButton == ButtonState.Pressed; + + private bool RightButtonReleased => CurrentMouseState.RightButton == ButtonState.Released && PreviousMouseState.RightButton == ButtonState.Pressed; + + private bool LeftButtonHeld => CurrentMouseState.LeftButton == ButtonState.Pressed && PreviousMouseState.LeftButton == ButtonState.Pressed; + public PaperdollDialogItem(INativeGraphicsManager nativeGraphicsManager, + InventoryPanel inventoryPanel, + PaperdollDialog paperdollDialog, bool isMainCharacter, EquipLocation location, Option itemInfo) { + _inventoryPanel = inventoryPanel; + _paperdollDialog = paperdollDialog; _isMainCharacter = isMainCharacter; EquipLocation = location; _itemInfo = itemInfo; @@ -33,23 +51,60 @@ public class PaperdollDialogItem : XNAPictureBox StretchMode = StretchMode.CenterInFrame; } - protected override void OnUpdateControl(GameTime gameTime) + public void StartDragging() { - base.OnUpdateControl(gameTime); + _beingDragged = true; + SetControlUnparented(); + Game.Components.Add(this); - if (!_isMainCharacter) - return; + DrawOrder = 1000; + } - if (MouseOver && CurrentMouseState.RightButton == ButtonState.Released && PreviousMouseState.RightButton == ButtonState.Pressed) + protected override void OnUpdateControl(GameTime gameTime) + { + if (_isMainCharacter) { _itemInfo.MatchSome(itemInfo => { - if (_isMainCharacter) + if (!_beingDragged && MouseOver && MouseOverPreviously && LeftButtonHeld) + { + if (_inventoryPanel.NoItemsDragging() && _paperdollDialog.NoItemsDragging()) + { + StartDragging(); + } + } + else if (_beingDragged) + { + DrawPosition = new Vector2(CurrentMouseState.X - (DrawArea.Width / 2), CurrentMouseState.Y - (DrawArea.Height / 2)); + + if (LeftButtonReleased) + { + if (_inventoryPanel.MouseOver && _inventoryPanel.MouseOverPreviously) + { + StopDragging(); + RightClick?.Invoke(this, itemInfo); + } + } + else if (RightButtonReleased) + { + StopDragging(); + } + } + else if (!_beingDragged && MouseOver && RightButtonReleased) { RightClick?.Invoke(this, itemInfo); } }); } + + base.OnUpdateControl(gameTime); + } + + private void StopDragging() + { + _beingDragged = false; + SetParentControl(_paperdollDialog); + DrawArea = EquipLocation.GetEquipLocationRectangle(); } } } diff --git a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs index f91bdc04a..73c04645a 100644 --- a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs +++ b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs @@ -1,4 +1,5 @@ -using EndlessClient.HUD.Panels; +using EndlessClient.Dialogs; +using EndlessClient.HUD.Panels; using EOLib; using EOLib.Domain.Character; using EOLib.Graphics; @@ -30,6 +31,7 @@ public class ItemDragCompletedEventArgs private static readonly Rectangle InventoryGridArea = new Rectangle(114, 338, 363, 102); private readonly InventoryPanel _inventoryPanel; + private readonly IActiveDialogProvider _activeDialogProvider; private readonly Texture2D _itemGraphic; private readonly Texture2D _highlightBackground; private readonly XNALabel _nameLabel; @@ -58,7 +60,7 @@ public int Slot { _slot = value; DrawPosition = GetPosition(_slot); - DrawOrder = 102 - (_slot % InventoryPanel.InventoryRowSlots) * 2; + UpdateNameLabelPosition(); } } @@ -71,6 +73,7 @@ public string Text { _nameLabel.Text = value; _nameLabel.ResizeBasedOnText(16, 9); + UpdateNameLabelPosition(); } } @@ -81,9 +84,15 @@ public string Text public event EventHandler DoubleClick; public event EventHandler DoneDragging; - public InventoryPanelItem(IItemNameColorService itemNameColorService, InventoryPanel inventoryPanel, int slot, IInventoryItem inventoryItem, EIFRecord data) + public InventoryPanelItem(IItemNameColorService itemNameColorService, + InventoryPanel inventoryPanel, + IActiveDialogProvider activeDialogProvider, + int slot, + IInventoryItem inventoryItem, + EIFRecord data) { _inventoryPanel = inventoryPanel; + _activeDialogProvider = activeDialogProvider; Slot = slot; InventoryItem = inventoryItem; Data = data; @@ -102,7 +111,7 @@ public InventoryPanelItem(IItemNameColorService itemNameColorService, InventoryP Text = string.Empty }; - OnMouseEnter += (_, _) => _nameLabel.Visible = !_beingDragged; + OnMouseEnter += (_, _) => _nameLabel.Visible = _inventoryPanel.NoItemsDragging() && _activeDialogProvider.PaperdollDialog.Match(d => d.NoItemsDragging(), () => true); OnMouseLeave += (_, _) => _nameLabel.Visible = false; var (slotWidth, slotHeight) = Data.Size.GetDimensions(); @@ -136,7 +145,7 @@ public void StartDragging() public override void Initialize() { _nameLabel.Initialize(); - _nameLabel.SetParentControl(this); + _nameLabel.SetParentControl(_inventoryPanel); _nameLabel.ResizeBasedOnText(16, 9); base.Initialize(); @@ -173,7 +182,8 @@ protected override void OnUpdateControl(GameTime gameTime) } else if (++_updateTick % 8 == 0 && !_beingDragged && MouseOver && MouseOverPreviously && MouseHeld) { - if (_inventoryPanel.NoItemsDragging()) + if (_inventoryPanel.NoItemsDragging() && + _activeDialogProvider.PaperdollDialog.Match(dlg => dlg.NoItemsDragging(), () => true)) { StartDragging(); } @@ -245,6 +255,28 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } + private void UpdateNameLabelPosition() + { + if (_nameLabel == null) + return; + + // the name label is parented to the inventory panel so that all name labels draw over all items (see draw orders below) + // the actual position of the name label needs to be set to this control's draw position + var actualPosition = DrawPosition; + + if (actualPosition.X + _nameLabel.DrawAreaWithParentOffset.Width + DrawArea.Width > InventoryGridArea.Width) + { + _nameLabel.DrawPosition = new Vector2(actualPosition.X -_nameLabel.DrawArea.Width, actualPosition.Y); + } + else + { + _nameLabel.DrawPosition = new Vector2(actualPosition.X + DrawArea.Width, actualPosition.Y); + } + + DrawOrder = 110; + _nameLabel.DrawOrder = 200; + } + private static Vector2 GetPosition(int slot) { return new Vector2(13 + 26 * (slot % InventoryPanel.InventoryRowSlots), 9 + 26 * (slot / InventoryPanel.InventoryRowSlots)); diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index 1a5193d03..188a38c8d 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -204,7 +204,7 @@ protected override void OnUpdateControl(GameTime gameTime) { _inventoryService.SetSlots(_inventorySlotRepository.FilledSlots, slot, itemData.Size); - var newItem = new InventoryPanelItem(_itemNameColorService, this, slot, item, itemData); + var newItem = new InventoryPanelItem(_itemNameColorService, this, _activeDialogProvider, slot, item, itemData); newItem.Initialize(); newItem.SetParentControl(this); newItem.Text = _itemStringService.GetStringForInventoryDisplay(itemData, item.Amount);