From 04d7450713a064a6f77acf12f1313d3b5b960db7 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 25 Mar 2022 12:38:15 -0700 Subject: [PATCH 01/17] Implement inventory panel skeleton. No inventory items are rendered yet. --- .../Character/CharacterInventoryRepository.cs | 20 +- EOLib/Domain/Character/InventoryItem.cs | 15 ++ EOLib/Domain/Character/InventorySpell.cs | 15 ++ EOLib/Domain/Login/LoginActions.cs | 4 +- .../LoginRequestCompletedPacketTranslator.cs | 3 + EOLib/PacketHandlers/ItemEquipHandler.cs | 2 +- EOLib/misc.cs | 2 + EndlessClient/HUD/Panels/HudPanelFactory.cs | 19 +- EndlessClient/HUD/Panels/InventoryPanel.cs | 209 +++++++++++++++++- 9 files changed, 272 insertions(+), 17 deletions(-) diff --git a/EOLib/Domain/Character/CharacterInventoryRepository.cs b/EOLib/Domain/Character/CharacterInventoryRepository.cs index c5783edcd..8fd40cade 100644 --- a/EOLib/Domain/Character/CharacterInventoryRepository.cs +++ b/EOLib/Domain/Character/CharacterInventoryRepository.cs @@ -5,31 +5,31 @@ namespace EOLib.Domain.Character { public interface ICharacterInventoryRepository { - List ItemInventory { get; set; } + HashSet ItemInventory { get; set; } - List SpellInventory { get; set; } + HashSet SpellInventory { get; set; } } public interface ICharacterInventoryProvider { - IReadOnlyList ItemInventory { get; } + IReadOnlyCollection ItemInventory { get; } - IReadOnlyList SpellInventory { get; } + IReadOnlyCollection SpellInventory { get; } } [AutoMappedType(IsSingleton = true)] public class CharacterInventoryRepository : ICharacterInventoryRepository, ICharacterInventoryProvider { - public List ItemInventory { get; set; } - public List SpellInventory { get; set; } + public HashSet ItemInventory { get; set; } + public HashSet SpellInventory { get; set; } - IReadOnlyList ICharacterInventoryProvider.ItemInventory => ItemInventory; - IReadOnlyList ICharacterInventoryProvider.SpellInventory => SpellInventory; + IReadOnlyCollection ICharacterInventoryProvider.ItemInventory => ItemInventory; + IReadOnlyCollection ICharacterInventoryProvider.SpellInventory => SpellInventory; public CharacterInventoryRepository() { - ItemInventory = new List(32); - SpellInventory = new List(32); + ItemInventory = new HashSet(); + SpellInventory = new HashSet(); } } } diff --git a/EOLib/Domain/Character/InventoryItem.cs b/EOLib/Domain/Character/InventoryItem.cs index 46494bf10..4cbcdcbd1 100644 --- a/EOLib/Domain/Character/InventoryItem.cs +++ b/EOLib/Domain/Character/InventoryItem.cs @@ -16,6 +16,21 @@ public IInventoryItem WithAmount(int newAmount) { return new InventoryItem(ItemID, newAmount); } + + public override bool Equals(object obj) + { + var other = obj as InventoryItem; + if (other == null) return false; + return other.ItemID == ItemID && other.Amount == Amount; + } + + public override int GetHashCode() + { + int hashCode = 1754760722; + hashCode = hashCode * -1521134295 + ItemID.GetHashCode(); + hashCode = hashCode * -1521134295 + Amount.GetHashCode(); + return hashCode; + } } public interface IInventoryItem diff --git a/EOLib/Domain/Character/InventorySpell.cs b/EOLib/Domain/Character/InventorySpell.cs index 4682e133a..cbc3af8d3 100644 --- a/EOLib/Domain/Character/InventorySpell.cs +++ b/EOLib/Domain/Character/InventorySpell.cs @@ -16,6 +16,21 @@ public IInventorySpell WithLevel(short newLevel) { return new InventorySpell(ID, newLevel); } + + public override bool Equals(object obj) + { + var other = obj as InventorySpell; + if (other == null) return false; + return other.ID == ID && other.Level == Level; + } + + public override int GetHashCode() + { + int hashCode = 1754760722; + hashCode = hashCode * -1521134295 + ID.GetHashCode(); + hashCode = hashCode * -1521134295 + Level.GetHashCode(); + return hashCode; + } } public interface IInventorySpell diff --git a/EOLib/Domain/Login/LoginActions.cs b/EOLib/Domain/Login/LoginActions.cs index 4a9572939..af11dc03d 100644 --- a/EOLib/Domain/Login/LoginActions.cs +++ b/EOLib/Domain/Login/LoginActions.cs @@ -171,8 +171,8 @@ public async Task CompleteCharacterLogin() .WithStats(stats) .WithRenderProperties(mainCharacter.RenderProperties); - _characterInventoryRepository.ItemInventory = data.CharacterItemInventory.ToList(); - _characterInventoryRepository.SpellInventory = data.CharacterSpellInventory.ToList(); + _characterInventoryRepository.ItemInventory = new HashSet(data.CharacterItemInventory); + _characterInventoryRepository.SpellInventory = new HashSet(data.CharacterSpellInventory); _currentMapStateRepository.Characters = data.MapCharacters.Except(new[] { mainCharacter }).ToDictionary(k => k.ID, v => v); _currentMapStateRepository.NPCs = new HashSet(data.MapNPCs); diff --git a/EOLib/Net/Translators/LoginRequestCompletedPacketTranslator.cs b/EOLib/Net/Translators/LoginRequestCompletedPacketTranslator.cs index 332d9171e..f5907de6f 100644 --- a/EOLib/Net/Translators/LoginRequestCompletedPacketTranslator.cs +++ b/EOLib/Net/Translators/LoginRequestCompletedPacketTranslator.cs @@ -39,6 +39,9 @@ public override ILoginRequestCompletedData TranslatePacket(IPacket packet) var maxWeight = packet.ReadChar(); var inventoryItems = GetInventoryItems(packet).ToList(); + if (!inventoryItems.Any(x => x.ItemID == 1)) + inventoryItems.Insert(0, new InventoryItem(1, 0)); + var inventorySpells = GetInventorySpells(packet).ToList(); if (inventoryItems.All(x => x.ItemID != 1)) diff --git a/EOLib/PacketHandlers/ItemEquipHandler.cs b/EOLib/PacketHandlers/ItemEquipHandler.cs index abdd49227..748dfecff 100644 --- a/EOLib/PacketHandlers/ItemEquipHandler.cs +++ b/EOLib/PacketHandlers/ItemEquipHandler.cs @@ -98,7 +98,7 @@ protected bool HandlePaperdollPacket(IPacket packet, bool itemUnequipped) .Match(some: invItem => invItem.WithAmount(itemUnequipped ? invItem.Amount + amount : amount), none: () => new InventoryItem(itemId, amount)); - _characterInventoryRepository.ItemInventory.RemoveAll(x => x.ItemID == itemId); + _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == itemId); _characterInventoryRepository.ItemInventory.Add(updatedItem); } else diff --git a/EOLib/misc.cs b/EOLib/misc.cs index 9ed5fb536..442169185 100644 --- a/EOLib/misc.cs +++ b/EOLib/misc.cs @@ -45,6 +45,8 @@ public static class Constants public const string FriendListFile = "config/friends.ini"; public const string IgnoreListFile = "config/ignore.ini"; + public const string InventoryFile = "config/inventory.ini"; + //Should be easily customizable between different clients (based on graphics) //not a config option because this shouldn't be exposed at the user level public static readonly int[] TrapSpikeGFXObjectIDs = {449, 450, 451, 452}; diff --git a/EndlessClient/HUD/Panels/HudPanelFactory.cs b/EndlessClient/HUD/Panels/HudPanelFactory.cs index 07755e770..c05cc3d81 100644 --- a/EndlessClient/HUD/Panels/HudPanelFactory.cs +++ b/EndlessClient/HUD/Panels/HudPanelFactory.cs @@ -2,6 +2,7 @@ using EndlessClient.Content; using EndlessClient.Controllers; using EndlessClient.ControlSets; +using EndlessClient.Dialogs.Actions; using EndlessClient.Dialogs.Factories; using EndlessClient.Rendering.Chat; using EndlessClient.Services; @@ -20,40 +21,49 @@ public class HudPanelFactory : IHudPanelFactory private const int HUD_CONTROL_LAYER = 130; private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly IInGameDialogActions _inGameDialogActions; private readonly IContentProvider _contentProvider; private readonly IHudControlProvider _hudControlProvider; private readonly INewsProvider _newsProvider; private readonly IChatProvider _chatProvider; + private readonly IPlayerInfoProvider _playerInfoProvider; private readonly ICharacterProvider _characterProvider; private readonly ICharacterInventoryProvider _characterInventoryProvider; private readonly IExperienceTableProvider _experienceTableProvider; private readonly IEOMessageBoxFactory _messageBoxFactory; private readonly ITrainingController _trainingController; private readonly IFriendIgnoreListService _friendIgnoreListService; + private readonly IStatusLabelSetter _statusLabelSetter; public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, + IInGameDialogActions inGameDialogActions, IContentProvider contentProvider, IHudControlProvider hudControlProvider, INewsProvider newsProvider, IChatProvider chatProvider, + IPlayerInfoProvider playerInfoProvider, ICharacterProvider characterProvider, ICharacterInventoryProvider characterInventoryProvider, IExperienceTableProvider experienceTableProvider, IEOMessageBoxFactory messageBoxFactory, ITrainingController trainingController, - IFriendIgnoreListService friendIgnoreListService) + IFriendIgnoreListService friendIgnoreListService, + IStatusLabelSetter statusLabelSetter) { _nativeGraphicsManager = nativeGraphicsManager; + _inGameDialogActions = inGameDialogActions; _contentProvider = contentProvider; _hudControlProvider = hudControlProvider; _newsProvider = newsProvider; _chatProvider = chatProvider; + _playerInfoProvider = playerInfoProvider; _characterProvider = characterProvider; _characterInventoryProvider = characterInventoryProvider; _experienceTableProvider = experienceTableProvider; _messageBoxFactory = messageBoxFactory; _trainingController = trainingController; _friendIgnoreListService = friendIgnoreListService; + _statusLabelSetter = statusLabelSetter; } public NewsPanel CreateNewsPanel() @@ -68,7 +78,12 @@ public NewsPanel CreateNewsPanel() public InventoryPanel CreateInventoryPanel() { - return new InventoryPanel(_nativeGraphicsManager) { DrawOrder = HUD_CONTROL_LAYER }; + return new InventoryPanel(_nativeGraphicsManager, + _inGameDialogActions, + _statusLabelSetter, + _playerInfoProvider, + _characterProvider, + _characterInventoryProvider) { DrawOrder = HUD_CONTROL_LAYER }; } public ActiveSpellsPanel CreateActiveSpellsPanel() diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index c31cc1da5..d5b045d0c 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -1,19 +1,224 @@ -using EOLib.Graphics; +using EndlessClient.Dialogs.Actions; +using EndlessClient.UIControls; +using EOLib; +using EOLib.Config; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Graphics; +using EOLib.Localization; +using Microsoft.Win32; using Microsoft.Xna.Framework; +using Optional; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; using XNAControls; namespace EndlessClient.HUD.Panels { public class InventoryPanel : XNAPanel, IHudPanel { + public const int InventoryRowSlots = 14; + + // uses absolute coordinates + private static readonly Rectangle InventoryGridArea = new Rectangle(110, 334, 377, 116); + private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly IStatusLabelSetter _statusLabelSetter; + private readonly IPlayerInfoProvider _playerInfoProvider; + private readonly ICharacterProvider _characterProvider; + private readonly ICharacterInventoryProvider _characterInventoryProvider; + + private readonly bool[,] _usedSlots = new bool[4, InventoryRowSlots]; + private readonly Dictionary _itemSlotMap; + //private readonly List _childItems = new List(); - public InventoryPanel(INativeGraphicsManager nativeGraphicsManager) + private readonly IXNALabel _weightLabel; + private readonly IXNAButton _drop, _junk, _paperdoll; + //private readonly ScrollBar _scrollBar; + + private Option _cachedStats; + private HashSet _cachedInventory; + + public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, + IInGameDialogActions inGameDialogActions, + IStatusLabelSetter statusLabelSetter, + IPlayerInfoProvider playerInfoProvider, + ICharacterProvider characterProvider, + ICharacterInventoryProvider characterInventoryProvider) { _nativeGraphicsManager = nativeGraphicsManager; + _statusLabelSetter = statusLabelSetter; + _playerInfoProvider = playerInfoProvider; + _characterProvider = characterProvider; + _characterInventoryProvider = characterInventoryProvider; + + _weightLabel = new XNALabel(Constants.FontSize08pt5) + { + DrawArea = new Rectangle(385, 37, 88, 18), + ForeColor = ColorConstants.LightGrayText, + TextAlign = LabelAlignment.MiddleCenter, + Visible = true, + AutoSize = false + }; + + _itemSlotMap = GetItemSlotMap(_playerInfoProvider.LoggedInAccountName, _characterProvider.MainCharacter.Name); + + var weirdOffsetSheet = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 27); + + _paperdoll = new XNAButton(weirdOffsetSheet, new Vector2(385, 9), new Rectangle(39, 385, 88, 19), new Rectangle(126, 385, 88, 19)); + _paperdoll.OnMouseEnter += MouseOverButton; + _paperdoll.OnClick += (_, _) => inGameDialogActions.ShowPaperdollDialog(characterProvider.MainCharacter, isMainCharacter: true); + _drop = new XNAButton(weirdOffsetSheet, new Vector2(389, 68), new Rectangle(0, 15, 38, 37), new Rectangle(0, 52, 38, 37)); + _drop.OnMouseEnter += MouseOverButton; + _junk = new XNAButton(weirdOffsetSheet, new Vector2(431, 68), new Rectangle(0, 89, 38, 37), new Rectangle(0, 126, 38, 37)); + _junk.OnMouseEnter += MouseOverButton; + + _cachedStats = Option.None(); + _cachedInventory = new HashSet(); BackgroundImage = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 44); DrawArea = new Rectangle(102, 330, BackgroundImage.Width, BackgroundImage.Height); } + + public override void Initialize() + { + _weightLabel.Initialize(); + _weightLabel.SetParentControl(this); + + _paperdoll.Initialize(); + _paperdoll.SetParentControl(this); + + _drop.Initialize(); + _drop.SetParentControl(this); + + _junk.Initialize(); + _junk.SetParentControl(this); + + base.Initialize(); + } + + protected override void OnUpdateControl(GameTime gameTime) + { + _cachedStats.Match( + some: stats => + { + stats.SomeWhen(s => s != _characterProvider.MainCharacter.Stats) + .MatchSome(s => + { + _cachedStats = Option.Some(_characterProvider.MainCharacter.Stats); + _weightLabel.Text = $"{stats[CharacterStat.Weight]} / {stats[CharacterStat.MaxWeight]}"; + }); + }, + none: () => + { + var stats = _characterProvider.MainCharacter.Stats; + _cachedStats = Option.Some(stats); + _weightLabel.Text = $"{stats[CharacterStat.Weight]} / {stats[CharacterStat.MaxWeight]}"; + }); + + if (!_cachedInventory.SetEquals(_characterInventoryProvider.ItemInventory)) + { + var added = _characterInventoryProvider.ItemInventory.Where(i => !_cachedInventory.Any(j => i.ItemID == j.ItemID)); + var removed = _cachedInventory.Where(i => !_characterInventoryProvider.ItemInventory.Any(j => i.ItemID == j.ItemID)); + + _cachedInventory = _characterInventoryProvider.ItemInventory.ToHashSet(); + var updated = _cachedInventory.Except(added); + + // todo: update child inventory items + } + + base.OnUpdateControl(gameTime); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + var inventory = new IniReader(Constants.InventoryFile); + if (inventory.Load() && inventory.Sections.ContainsKey(_playerInfoProvider.LoggedInAccountName)) + { + var section = inventory.Sections[_playerInfoProvider.LoggedInAccountName]; + // todo: write out item inventory slots to file + } + + _paperdoll.OnMouseEnter -= MouseOverButton; + _drop.OnMouseEnter -= MouseOverButton; + _junk.OnMouseEnter -= MouseOverButton; + } + + base.Dispose(disposing); + } + + private void MouseOverButton(object sender, EventArgs e) + { + var id = sender == _paperdoll + ? EOResourceID.STATUS_LABEL_INVENTORY_SHOW_YOUR_PAPERDOLL + : sender == _drop + ? EOResourceID.STATUS_LABEL_INVENTORY_DROP_BUTTON + : EOResourceID.STATUS_LABEL_INVENTORY_JUNK_BUTTON; + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_BUTTON, id); + } + + private static Dictionary GetItemSlotMap(string accountName, string characterName) + { + var map = new Dictionary(); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && !File.Exists(Constants.InventoryFile)) + { + using var inventoryKey = TryGetCharacterRegistryKey(accountName, characterName); + if (inventoryKey != null) + { + for (int i = 0; i < InventoryRowSlots * 4; ++i) + { + if (int.TryParse(inventoryKey.GetValue($"item{i}")?.ToString() ?? string.Empty, out var id)) + map[i] = id; + } + } + } + + var inventory = new IniReader(Constants.InventoryFile); + if (inventory.Load() && inventory.Sections.ContainsKey(accountName)) + { + var section = inventory.Sections[accountName]; + foreach (var key in section.Keys.Where(x => x.Contains(characterName, StringComparison.OrdinalIgnoreCase))) + { + if (!key.Contains(".")) + continue; + + var slot = key.Split(".")[1]; + if (!int.TryParse(slot, out var slotIndex)) + continue; + + if (int.TryParse(section[key], out var id)) + map[slotIndex] = id; + } + } + + return map; + } + + [SupportedOSPlatform("Windows")] + private static RegistryKey TryGetCharacterRegistryKey(string accountName, string characterName) + { + using RegistryKey currentUser = Registry.CurrentUser; + + var pathSegments = $"Software\\EndlessClient\\{accountName}\\{characterName}\\inventory".Split('\\'); + var currentPath = string.Empty; + + RegistryKey retKey = null; + foreach (var segment in pathSegments) + { + retKey?.Dispose(); + + currentPath = Path.Combine(currentPath, segment); + retKey = currentUser.CreateSubKey(currentPath, RegistryKeyPermissionCheck.ReadSubTree); + } + + return retKey; + } } } \ No newline at end of file From 7336c976b076433ecbfc31526fcda42ecca490d1 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sat, 26 Mar 2022 01:00:13 -0700 Subject: [PATCH 02/17] Display of items in inventory panel Display only, no clickdrag or doubleclick actions yet --- EOLib.IO/Extensions/ItemSizeExtensions.cs | 21 +++ EndlessClient/EndlessClient.csproj | 2 +- EndlessClient/HUD/IStatusLabelSetter.cs | 2 + .../HUD/Inventory/InventoryPanelItem.cs | 134 ++++++++++++++++++ .../HUD/Inventory/InventoryService.cs | 89 ++++++++++++ .../HUD/Inventory/InventorySpaceValidator.cs | 2 + EndlessClient/HUD/Panels/HudPanelFactory.cs | 19 ++- EndlessClient/HUD/Panels/InventoryPanel.cs | 72 ++++++++-- EndlessClient/HUD/StatusLabelSetter.cs | 6 + 9 files changed, 335 insertions(+), 12 deletions(-) create mode 100644 EOLib.IO/Extensions/ItemSizeExtensions.cs create mode 100644 EndlessClient/HUD/Inventory/InventoryPanelItem.cs create mode 100644 EndlessClient/HUD/Inventory/InventoryService.cs diff --git a/EOLib.IO/Extensions/ItemSizeExtensions.cs b/EOLib.IO/Extensions/ItemSizeExtensions.cs new file mode 100644 index 000000000..56a14d1aa --- /dev/null +++ b/EOLib.IO/Extensions/ItemSizeExtensions.cs @@ -0,0 +1,21 @@ +using System; + +namespace EOLib.IO.Extensions +{ + public static class ItemSizeExtensions + { + public static (int Width, int Height) GetDimensions(this ItemSize itemSize) + { + var sizeStr = Enum.GetName(typeof(ItemSize), itemSize); + if (sizeStr == null || sizeStr.Length != 7) + { + return (0, 0); + } + + var width = Convert.ToInt32(sizeStr.Substring(4, 1)); + var height = Convert.ToInt32(sizeStr.Substring(6, 1)); + + return (width, height); + } + } +} diff --git a/EndlessClient/EndlessClient.csproj b/EndlessClient/EndlessClient.csproj index 19d7294ef..1bd447a7a 100644 --- a/EndlessClient/EndlessClient.csproj +++ b/EndlessClient/EndlessClient.csproj @@ -60,6 +60,6 @@ - + diff --git a/EndlessClient/HUD/IStatusLabelSetter.cs b/EndlessClient/HUD/IStatusLabelSetter.cs index 4b247d1f8..bae49c721 100644 --- a/EndlessClient/HUD/IStatusLabelSetter.cs +++ b/EndlessClient/HUD/IStatusLabelSetter.cs @@ -7,5 +7,7 @@ public interface IStatusLabelSetter void SetStatusLabel(EOResourceID type, EOResourceID text, string appended = ""); void SetStatusLabel(EOResourceID type, string prepended, EOResourceID text); + + void SetStatusLabel(EOResourceID type, string text); } } diff --git a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs new file mode 100644 index 000000000..21a26cb3e --- /dev/null +++ b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs @@ -0,0 +1,134 @@ +using EndlessClient.HUD.Panels; +using EOLib; +using EOLib.Domain.Character; +using EOLib.Domain.Item; +using EOLib.Graphics; +using EOLib.IO.Extensions; +using EOLib.IO.Pub; +using EOLib.Localization; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using XNAControls; + +namespace EndlessClient.HUD.Inventory +{ + public class InventoryPanelItem : XNAControl + { + private readonly IItemStringService _itemStringService; + private readonly IStatusLabelSetter _statusLabelSetter; + private readonly InventoryPanel _inventoryPanel; + private readonly EIFRecord _data; + + private readonly Texture2D _itemGraphic; + private readonly Texture2D _highlightBackground; + private readonly XNALabel _nameLabel; + + private int _slot; + private IInventoryItem _item; + + public int Slot + { + get => _slot; + set + { + _slot = value; + DrawPosition = GetPosition(_slot); + } + } + + public IInventoryItem InventoryItem + { + get => _item; + set + { + _item = value; + _nameLabel.Text = _itemStringService.GetStringForMapDisplay(_data, _item.Amount); + _nameLabel.ResizeBasedOnText(16, 9); + } + } + + public InventoryPanelItem( + INativeGraphicsManager nativeGraphicsManager, + IItemStringService itemStringService, + IStatusLabelSetter statusLabelSetter, + InventoryPanel inventoryPanel, int slot, IInventoryItem inventoryItem, EIFRecord data) + { + _itemStringService = itemStringService; + _statusLabelSetter = statusLabelSetter; + _inventoryPanel = inventoryPanel; + _data = data; + Slot = slot; + _item = inventoryItem; + + _itemGraphic = nativeGraphicsManager.TextureFromResource(GFXTypes.Items, 2 * data.Graphic, transparent: true); + _highlightBackground = new Texture2D(Game.GraphicsDevice, 1, 1); + _highlightBackground.SetData(new[] { Color.FromNonPremultiplied(200, 200, 200, 60) }); + + _nameLabel = new XNALabel(Constants.FontSize08) + { + Visible = false, + AutoSize = false, + TextAlign = LabelAlignment.MiddleCenter, + ForeColor = ColorConstants.LightGrayText, + BackColor = Color.FromNonPremultiplied(30, 30, 30, 160), + Text = _itemStringService.GetStringForMapDisplay(data, inventoryItem.Amount) + }; + + OnMouseEnter += (_, _) => + { + _nameLabel.Visible = true; + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ITEM, _nameLabel.Text); + }; + OnMouseLeave += (_, _) => _nameLabel.Visible = false; + + var (slotWidth, slotHeight) = _data.Size.GetDimensions(); + SetSize(slotWidth * 26, slotHeight * 26); + } + + public override void Initialize() + { + _nameLabel.Initialize(); + _nameLabel.SetParentControl(this); + _nameLabel.ResizeBasedOnText(16, 9); + + base.Initialize(); + } + + protected override void OnUpdateControl(GameTime gameTime) + { + base.OnUpdateControl(gameTime); + } + + protected override void OnDrawControl(GameTime gameTime) + { + _spriteBatch.Begin(); + + if (MouseOver) + { + _spriteBatch.Draw(_highlightBackground, DrawAreaWithParentOffset.WithSize(DrawArea.Width - 3, DrawArea.Height - 3), Color.White); + } + + _spriteBatch.Draw(_itemGraphic, DrawPositionWithParentOffset, Color.White); + + _spriteBatch.End(); + + base.OnDrawControl(gameTime); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + _nameLabel.Dispose(); + _highlightBackground.Dispose(); + } + + base.Dispose(disposing); + } + + private static Vector2 GetPosition(int slot) + { + return new Vector2(13 + 26 * (slot % InventoryPanel.InventoryRowSlots), 9 + 26 * (slot / InventoryPanel.InventoryRowSlots)); + } + } +} diff --git a/EndlessClient/HUD/Inventory/InventoryService.cs b/EndlessClient/HUD/Inventory/InventoryService.cs new file mode 100644 index 000000000..1fc1a2405 --- /dev/null +++ b/EndlessClient/HUD/Inventory/InventoryService.cs @@ -0,0 +1,89 @@ +using AutomaticTypeMapper; +using EndlessClient.HUD.Panels; +using EOLib.IO; +using EOLib.IO.Extensions; +using Optional; + +namespace EndlessClient.HUD.Inventory +{ + [AutoMappedType] + public class InventoryService : IInventoryService + { + public Option GetNextOpenSlot(bool[,] usedSlots, ItemSize size, Option preferredSlot) + { + var (sizeWidth, sizeHeight) = size.GetDimensions(); + + var preferredSlotIsValid = preferredSlot.Match( + some: slot => IsSlotOpen(usedSlots, slot, size), + none: () => false); + + if (preferredSlotIsValid) + return preferredSlot; + + for (int r = 0; r < usedSlots.GetLength(0); r++) + { + for (int c = 0; c < usedSlots.GetLength(1); c++) + { + var slot = r * InventoryPanel.InventoryRowSlots + c; + if (!usedSlots[r, c] && IsSlotOpen(usedSlots, slot, size)) + return Option.Some(slot); + } + } + + return Option.None(); + } + + public void SetSlots(bool[,] usedSlots, int slot, ItemSize size) + { + SetSlotValue(usedSlots, slot, size, value: true); + } + + public void ClearSlots(bool[,] usedSlots, int slot, ItemSize size) + { + SetSlotValue(usedSlots, slot, size, value: false); + } + + private bool IsSlotOpen(bool[,] usedSlots, int slot, ItemSize size) + { + var (sizeWidth, sizeHeight) = size.GetDimensions(); + + var col = slot % InventoryPanel.InventoryRowSlots; + var row = slot / InventoryPanel.InventoryRowSlots; + for (int r = row; r < row + sizeHeight; r++) + { + for (int c = col; c < col + sizeWidth; c++) + { + if (r >= usedSlots.GetLength(0) || c >= usedSlots.GetLength(1) || usedSlots[r, c]) + return false; + } + } + + return true; + } + + private void SetSlotValue(bool[,] usedSlots, int slot, ItemSize size, bool value) + { + var (sizeWidth, sizeHeight) = size.GetDimensions(); + + var slotCol = slot % InventoryPanel.InventoryRowSlots; + var slotRow = slot / InventoryPanel.InventoryRowSlots; + + for (int r = slotRow; r < slotRow + sizeHeight; r++) + { + for (int c = slotCol; c < slotCol + sizeWidth; c++) + { + if (r < usedSlots.GetLength(0) && c < usedSlots.GetLength(1)) + usedSlots[r, c] = value; + } + } + } + } + + public interface IInventoryService + { + Option GetNextOpenSlot(bool[,] usedSlots, ItemSize size, Option preferredSlot); + void SetSlots(bool[,] usedSlots, int slot, ItemSize size); + + void ClearSlots(bool[,] usedSlots, int slot, ItemSize size); + } +} diff --git a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs index 6dcfd18c5..d0f16b279 100644 --- a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs +++ b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs @@ -32,5 +32,7 @@ public interface IInventorySpaceValidator bool ItemFits(IItem item); bool ItemFits(ItemSize itemSize); + + // need "ItemsFit" method for trading } } diff --git a/EndlessClient/HUD/Panels/HudPanelFactory.cs b/EndlessClient/HUD/Panels/HudPanelFactory.cs index c05cc3d81..74956482a 100644 --- a/EndlessClient/HUD/Panels/HudPanelFactory.cs +++ b/EndlessClient/HUD/Panels/HudPanelFactory.cs @@ -4,13 +4,16 @@ using EndlessClient.ControlSets; using EndlessClient.Dialogs.Actions; using EndlessClient.Dialogs.Factories; +using EndlessClient.HUD.Inventory; using EndlessClient.Rendering.Chat; using EndlessClient.Services; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Chat; +using EOLib.Domain.Item; using EOLib.Domain.Login; using EOLib.Graphics; +using EOLib.IO.Repositories; using Microsoft.Xna.Framework.Graphics; namespace EndlessClient.HUD.Panels @@ -30,10 +33,13 @@ public class HudPanelFactory : IHudPanelFactory private readonly ICharacterProvider _characterProvider; private readonly ICharacterInventoryProvider _characterInventoryProvider; private readonly IExperienceTableProvider _experienceTableProvider; + private readonly IEIFFileProvider _eifFileProvider; private readonly IEOMessageBoxFactory _messageBoxFactory; private readonly ITrainingController _trainingController; private readonly IFriendIgnoreListService _friendIgnoreListService; private readonly IStatusLabelSetter _statusLabelSetter; + private readonly IItemStringService _itemStringService; + private readonly IInventoryService _inventoryService; public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, IInGameDialogActions inGameDialogActions, @@ -45,10 +51,13 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, ICharacterProvider characterProvider, ICharacterInventoryProvider characterInventoryProvider, IExperienceTableProvider experienceTableProvider, + IEIFFileProvider eifFileProvider, IEOMessageBoxFactory messageBoxFactory, ITrainingController trainingController, IFriendIgnoreListService friendIgnoreListService, - IStatusLabelSetter statusLabelSetter) + IStatusLabelSetter statusLabelSetter, + IItemStringService itemStringService, + IInventoryService inventoryService) { _nativeGraphicsManager = nativeGraphicsManager; _inGameDialogActions = inGameDialogActions; @@ -60,10 +69,13 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, _characterProvider = characterProvider; _characterInventoryProvider = characterInventoryProvider; _experienceTableProvider = experienceTableProvider; + _eifFileProvider = eifFileProvider; _messageBoxFactory = messageBoxFactory; _trainingController = trainingController; _friendIgnoreListService = friendIgnoreListService; _statusLabelSetter = statusLabelSetter; + _itemStringService = itemStringService; + _inventoryService = inventoryService; } public NewsPanel CreateNewsPanel() @@ -81,9 +93,12 @@ public InventoryPanel CreateInventoryPanel() return new InventoryPanel(_nativeGraphicsManager, _inGameDialogActions, _statusLabelSetter, + _itemStringService, + _inventoryService, _playerInfoProvider, _characterProvider, - _characterInventoryProvider) { DrawOrder = HUD_CONTROL_LAYER }; + _characterInventoryProvider, + _eifFileProvider) { DrawOrder = HUD_CONTROL_LAYER }; } public ActiveSpellsPanel CreateActiveSpellsPanel() diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index d5b045d0c..dab0f944e 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -1,14 +1,17 @@ using EndlessClient.Dialogs.Actions; -using EndlessClient.UIControls; +using EndlessClient.HUD.Inventory; using EOLib; using EOLib.Config; using EOLib.Domain.Character; +using EOLib.Domain.Item; using EOLib.Domain.Login; using EOLib.Graphics; +using EOLib.IO.Repositories; using EOLib.Localization; using Microsoft.Win32; using Microsoft.Xna.Framework; using Optional; +using Optional.Collections; using System; using System.Collections.Generic; using System.IO; @@ -28,13 +31,16 @@ public class InventoryPanel : XNAPanel, IHudPanel private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IStatusLabelSetter _statusLabelSetter; + private readonly IItemStringService _itemStringService; + private readonly IInventoryService _inventoryService; private readonly IPlayerInfoProvider _playerInfoProvider; private readonly ICharacterProvider _characterProvider; private readonly ICharacterInventoryProvider _characterInventoryProvider; + private readonly IEIFFileProvider _eifFileProvider; private readonly bool[,] _usedSlots = new bool[4, InventoryRowSlots]; private readonly Dictionary _itemSlotMap; - //private readonly List _childItems = new List(); + private readonly List _childItems = new List(); private readonly IXNALabel _weightLabel; private readonly IXNAButton _drop, _junk, _paperdoll; @@ -46,16 +52,21 @@ public class InventoryPanel : XNAPanel, IHudPanel public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, IInGameDialogActions inGameDialogActions, IStatusLabelSetter statusLabelSetter, + IItemStringService itemStringService, + IInventoryService inventoryService, IPlayerInfoProvider playerInfoProvider, ICharacterProvider characterProvider, - ICharacterInventoryProvider characterInventoryProvider) + ICharacterInventoryProvider characterInventoryProvider, + IEIFFileProvider eifFileProvider) { _nativeGraphicsManager = nativeGraphicsManager; _statusLabelSetter = statusLabelSetter; + _itemStringService = itemStringService; + _inventoryService = inventoryService; _playerInfoProvider = playerInfoProvider; _characterProvider = characterProvider; _characterInventoryProvider = characterInventoryProvider; - + _eifFileProvider = eifFileProvider; _weightLabel = new XNALabel(Constants.FontSize08pt5) { DrawArea = new Rectangle(385, 37, 88, 18), @@ -124,11 +135,52 @@ protected override void OnUpdateControl(GameTime gameTime) { var added = _characterInventoryProvider.ItemInventory.Where(i => !_cachedInventory.Any(j => i.ItemID == j.ItemID)); var removed = _cachedInventory.Where(i => !_characterInventoryProvider.ItemInventory.Any(j => i.ItemID == j.ItemID)); - - _cachedInventory = _characterInventoryProvider.ItemInventory.ToHashSet(); - var updated = _cachedInventory.Except(added); + var updated = _characterInventoryProvider.ItemInventory.Except(added); + + foreach (var item in removed) + { + var matchedItem = _childItems.SingleOrNone(x => x.InventoryItem.ItemID == item.ItemID); + matchedItem.MatchSome(childItem => + { + childItem.SetControlUnparented(); + childItem.Dispose(); + _childItems.Remove(childItem); + + var itemData = _eifFileProvider.EIFFile[item.ItemID]; + _inventoryService.ClearSlots(_usedSlots, childItem.Slot, itemData.Size); + }); + } + + foreach (var item in updated) + { + var matchedItem = _childItems.SingleOrNone(x => x.InventoryItem.ItemID == item.ItemID); + matchedItem.MatchSome(childItem => + { + childItem.InventoryItem = item; + }); + } - // todo: update child inventory items + foreach (var item in added) + { + var itemData = _eifFileProvider.EIFFile[item.ItemID]; + + var preferredSlot = _itemSlotMap.SingleOrNone(x => x.Value == item.ItemID).Map(x => x.Key); + var actualSlot = _inventoryService.GetNextOpenSlot(_usedSlots, itemData.Size, preferredSlot); + + actualSlot.MatchSome(slot => + { + _inventoryService.SetSlots(_usedSlots, slot, itemData.Size); + + var newItem = new InventoryPanelItem(_nativeGraphicsManager, _itemStringService, _statusLabelSetter, this, slot, item, itemData); + newItem.Initialize(); + newItem.SetParentControl(this); + newItem.DrawOrder = 102 - (slot % InventoryRowSlots) * 2; + + _childItems.Add(newItem); + }); + } + + _cachedInventory = _characterInventoryProvider.ItemInventory.ToHashSet(); } base.OnUpdateControl(gameTime); @@ -142,7 +194,9 @@ protected override void Dispose(bool disposing) if (inventory.Load() && inventory.Sections.ContainsKey(_playerInfoProvider.LoggedInAccountName)) { var section = inventory.Sections[_playerInfoProvider.LoggedInAccountName]; - // todo: write out item inventory slots to file + + foreach (var item in _childItems) + section[$"{_characterProvider.MainCharacter.Name}.{item.Slot}"] = $"{item.InventoryItem.ItemID}"; } _paperdoll.OnMouseEnter -= MouseOverButton; diff --git a/EndlessClient/HUD/StatusLabelSetter.cs b/EndlessClient/HUD/StatusLabelSetter.cs index d66f81ce5..6506a5925 100644 --- a/EndlessClient/HUD/StatusLabelSetter.cs +++ b/EndlessClient/HUD/StatusLabelSetter.cs @@ -34,6 +34,12 @@ public void SetStatusLabel(EOResourceID type, string prepended, EOResourceID tex _localizedStringFinder.GetString(text)); } + public void SetStatusLabel(EOResourceID type, string text) + { + CheckStatusLabelType(type); + SetStatusLabelText(_localizedStringFinder.GetString(type), text); + } + private void SetStatusLabelText(string type, string text, string extra = "") { _statusLabelTextRepository.StatusText = $"[ {type} ] {text}{extra}"; From 4a544047176918d1488857dde51d111773734bbc Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sat, 26 Mar 2022 14:53:52 -0700 Subject: [PATCH 03/17] Remove unused paperdoll repository from LoginActions --- EOLib/Domain/Login/LoginActions.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/EOLib/Domain/Login/LoginActions.cs b/EOLib/Domain/Login/LoginActions.cs index af11dc03d..7d8511125 100644 --- a/EOLib/Domain/Login/LoginActions.cs +++ b/EOLib/Domain/Login/LoginActions.cs @@ -29,7 +29,6 @@ public class LoginActions : ILoginActions private readonly ILoginFileChecksumRepository _loginFileChecksumRepository; private readonly INewsRepository _newsRepository; private readonly ICharacterInventoryRepository _characterInventoryRepository; - private readonly IPaperdollRepository _paperdollRepository; public LoginActions(IPacketSendService packetSendService, IPacketTranslator loginPacketTranslator, @@ -43,8 +42,7 @@ public LoginActions(IPacketSendService packetSendService, ILoginFileChecksumRepository loginFileChecksumRepository, INewsRepository newsRepository, IChatRepository chatRepository, - ICharacterInventoryRepository characterInventoryRepository, - IPaperdollRepository paperdollRepository) + ICharacterInventoryRepository characterInventoryRepository) { _packetSendService = packetSendService; _loginPacketTranslator = loginPacketTranslator; @@ -57,7 +55,6 @@ public LoginActions(IPacketSendService packetSendService, _loginFileChecksumRepository = loginFileChecksumRepository; _newsRepository = newsRepository; _characterInventoryRepository = characterInventoryRepository; - _paperdollRepository = paperdollRepository; } public bool LoginParametersAreValid(ILoginParameters parameters) From 02c0245170d80df910c4ba5e5a39cdbef928e011 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sat, 26 Mar 2022 14:55:21 -0700 Subject: [PATCH 04/17] Remove unused dependencies from LoginActions --- EOLib/Domain/Login/LoginActions.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/EOLib/Domain/Login/LoginActions.cs b/EOLib/Domain/Login/LoginActions.cs index 7d8511125..d2d90fcd2 100644 --- a/EOLib/Domain/Login/LoginActions.cs +++ b/EOLib/Domain/Login/LoginActions.cs @@ -3,11 +3,9 @@ using System.Threading.Tasks; using AutomaticTypeMapper; using EOLib.Domain.Character; -using EOLib.Domain.Chat; using EOLib.Domain.Map; using EOLib.Domain.NPC; using EOLib.Domain.Protocol; -using EOLib.Localization; using EOLib.Net; using EOLib.Net.Communication; using EOLib.Net.FileTransfer; @@ -34,14 +32,12 @@ public LoginActions(IPacketSendService packetSendService, IPacketTranslator loginPacketTranslator, IPacketTranslator loginRequestGrantedPacketTranslator, IPacketTranslator loginRequestCompletedPacketTranslator, - ILocalizedStringFinder localizedStringFinder, ICharacterSelectorRepository characterSelectorRepository, IPlayerInfoRepository playerInfoRepository, ICharacterRepository characterRepository, ICurrentMapStateRepository currentMapStateRepository, ILoginFileChecksumRepository loginFileChecksumRepository, INewsRepository newsRepository, - IChatRepository chatRepository, ICharacterInventoryRepository characterInventoryRepository) { _packetSendService = packetSendService; From bacb8b22ba73691521442e1484fdcbcc1c52734e Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sat, 26 Mar 2022 17:01:10 -0700 Subject: [PATCH 05/17] Set paperdoll info for main player on login --- EOLib/Domain/Login/ILoginRequestGrantedData.cs | 5 +++-- EOLib/Domain/Login/LoginActions.cs | 14 +++++++++++++- EOLib/Domain/Login/LoginRequestGrantedData.cs | 8 ++++---- .../LoginRequestGrantedPacketTranslator.cs | 9 +++++---- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/EOLib/Domain/Login/ILoginRequestGrantedData.cs b/EOLib/Domain/Login/ILoginRequestGrantedData.cs index c93735f07..cd629b008 100644 --- a/EOLib/Domain/Login/ILoginRequestGrantedData.cs +++ b/EOLib/Domain/Login/ILoginRequestGrantedData.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using EOLib.Domain.Character; +using EOLib.IO; using EOLib.Net.Translators; namespace EOLib.Domain.Login @@ -32,7 +33,7 @@ public interface ILoginRequestGrantedData : ITranslatedData ICharacterStats CharacterStats { get; } - IReadOnlyList Paperdoll { get; } + IReadOnlyDictionary Paperdoll { get; } byte GuildRankNum { get; } short JailMap { get; } @@ -59,7 +60,7 @@ public interface ILoginRequestGrantedData : ITranslatedData ILoginRequestGrantedData WithGuildTag(string guildTag); ILoginRequestGrantedData WithAdminLevel(AdminLevel adminLevel); ILoginRequestGrantedData WithCharacterStats(ICharacterStats stats); - ILoginRequestGrantedData WithPaperdoll(IEnumerable paperdollItemIDs); + ILoginRequestGrantedData WithPaperdoll(IReadOnlyDictionary paperdoll); ILoginRequestGrantedData WithGuildRankNum(byte rankNum); ILoginRequestGrantedData WithJailMap(short jailMapID); ILoginRequestGrantedData WithFirstTimePlayer(bool isFirstTimePlayer); diff --git a/EOLib/Domain/Login/LoginActions.cs b/EOLib/Domain/Login/LoginActions.cs index d2d90fcd2..51b143cac 100644 --- a/EOLib/Domain/Login/LoginActions.cs +++ b/EOLib/Domain/Login/LoginActions.cs @@ -27,6 +27,7 @@ public class LoginActions : ILoginActions private readonly ILoginFileChecksumRepository _loginFileChecksumRepository; private readonly INewsRepository _newsRepository; private readonly ICharacterInventoryRepository _characterInventoryRepository; + private readonly IPaperdollRepository _paperdollRepository; public LoginActions(IPacketSendService packetSendService, IPacketTranslator loginPacketTranslator, @@ -38,7 +39,8 @@ public LoginActions(IPacketSendService packetSendService, ICurrentMapStateRepository currentMapStateRepository, ILoginFileChecksumRepository loginFileChecksumRepository, INewsRepository newsRepository, - ICharacterInventoryRepository characterInventoryRepository) + ICharacterInventoryRepository characterInventoryRepository, + IPaperdollRepository paperdollRepository) { _packetSendService = packetSendService; _loginPacketTranslator = loginPacketTranslator; @@ -51,6 +53,7 @@ public LoginActions(IPacketSendService packetSendService, _loginFileChecksumRepository = loginFileChecksumRepository; _newsRepository = newsRepository; _characterInventoryRepository = characterInventoryRepository; + _paperdollRepository = paperdollRepository; } public bool LoginParametersAreValid(ILoginParameters parameters) @@ -110,6 +113,15 @@ public async Task RequestCharacterLogin(ICharacter character) _playerInfoRepository.IsFirstTimePlayer = data.FirstTimePlayer; _currentMapStateRepository.CurrentMapID = data.MapID; + _paperdollRepository.VisibleCharacterPaperdolls[data.PlayerID] = new PaperdollData() + .WithName(data.Name) + .WithTitle(data.Title) + .WithGuild(data.GuildName) + .WithRank(data.GuildRank) + .WithClass(data.ClassID) + .WithPlayerID(data.PlayerID) + .WithPaperdoll(data.Paperdoll); + _loginFileChecksumRepository.MapChecksum = data.MapRID.ToArray(); _loginFileChecksumRepository.MapLength = data.MapLen; diff --git a/EOLib/Domain/Login/LoginRequestGrantedData.cs b/EOLib/Domain/Login/LoginRequestGrantedData.cs index a7926fa7a..854dbb27b 100644 --- a/EOLib/Domain/Login/LoginRequestGrantedData.cs +++ b/EOLib/Domain/Login/LoginRequestGrantedData.cs @@ -33,8 +33,8 @@ public class LoginRequestGrantedData : ILoginRequestGrantedData public ICharacterStats CharacterStats { get; private set; } - private List _paperdoll = new List((int)EquipLocation.PAPERDOLL_MAX); - public IReadOnlyList Paperdoll => _paperdoll; + private IReadOnlyDictionary _paperdoll = new Dictionary(); + public IReadOnlyDictionary Paperdoll => _paperdoll; public byte GuildRankNum { get; private set; } public short JailMap { get; private set; } @@ -187,10 +187,10 @@ public ILoginRequestGrantedData WithCharacterStats(ICharacterStats stats) return copy; } - public ILoginRequestGrantedData WithPaperdoll(IEnumerable paperdollItemIDs) + public ILoginRequestGrantedData WithPaperdoll(IReadOnlyDictionary paperdoll) { var copy = MakeCopy(this); - copy._paperdoll = paperdollItemIDs.ToList(); + copy._paperdoll = paperdoll; return copy; } diff --git a/EOLib/Net/Translators/LoginRequestGrantedPacketTranslator.cs b/EOLib/Net/Translators/LoginRequestGrantedPacketTranslator.cs index fb6a87365..ff5fc9c46 100644 --- a/EOLib/Net/Translators/LoginRequestGrantedPacketTranslator.cs +++ b/EOLib/Net/Translators/LoginRequestGrantedPacketTranslator.cs @@ -1,4 +1,5 @@ -using System.IO; +using System.Collections.Generic; +using System.IO; using System.Linq; using AutomaticTypeMapper; using EOLib.Domain.Character; @@ -93,10 +94,10 @@ public ILoginRequestGrantedData TranslatePacket(IPacket packet) .WithNewStat(CharacterStat.Constituion, dispCon) .WithNewStat(CharacterStat.Charisma, dispCha); - var paperDoll = new short[(int)EquipLocation.PAPERDOLL_MAX]; - for (int i = 0; i < (int)EquipLocation.PAPERDOLL_MAX; ++i) + var paperDoll = new Dictionary(); + for (var equipLocation = (EquipLocation)0; equipLocation < EquipLocation.PAPERDOLL_MAX; ++equipLocation) { - paperDoll[i] = packet.ReadShort(); + paperDoll[equipLocation] = packet.ReadShort(); } var guildRankNum = packet.ReadChar(); From 8701325d31d723dc0b81e32d0c0da2a75b333ce0 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sat, 26 Mar 2022 17:01:58 -0700 Subject: [PATCH 06/17] Handle item equip from inventory via double-click --- EOLib/PacketHandlers/ItemEquipHandler.cs | 4 +- .../HUD/Inventory/InventoryPanelItem.cs | 64 ++++--- EndlessClient/HUD/Panels/HudPanelFactory.cs | 16 +- EndlessClient/HUD/Panels/InventoryPanel.cs | 166 ++++++++++++++++-- 4 files changed, 212 insertions(+), 38 deletions(-) diff --git a/EOLib/PacketHandlers/ItemEquipHandler.cs b/EOLib/PacketHandlers/ItemEquipHandler.cs index 748dfecff..3a48743ec 100644 --- a/EOLib/PacketHandlers/ItemEquipHandler.cs +++ b/EOLib/PacketHandlers/ItemEquipHandler.cs @@ -99,7 +99,9 @@ protected bool HandlePaperdollPacket(IPacket packet, bool itemUnequipped) none: () => new InventoryItem(itemId, amount)); _characterInventoryRepository.ItemInventory.RemoveWhere(x => x.ItemID == itemId); - _characterInventoryRepository.ItemInventory.Add(updatedItem); + + if (updatedItem.Amount > 0) + _characterInventoryRepository.ItemInventory.Add(updatedItem); } else { diff --git a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs index 21a26cb3e..c47cca217 100644 --- a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs +++ b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs @@ -8,13 +8,15 @@ using EOLib.Localization; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using System; +using System.Diagnostics; using XNAControls; namespace EndlessClient.HUD.Inventory { public class InventoryPanelItem : XNAControl { - private readonly IItemStringService _itemStringService; private readonly IStatusLabelSetter _statusLabelSetter; private readonly InventoryPanel _inventoryPanel; private readonly EIFRecord _data; @@ -24,7 +26,9 @@ public class InventoryPanelItem : XNAControl private readonly XNALabel _nameLabel; private int _slot; - private IInventoryItem _item; + + private readonly Stopwatch _clickTimer; + private int _recentClicks; public int Slot { @@ -36,31 +40,28 @@ public int Slot } } - public IInventoryItem InventoryItem + public IInventoryItem InventoryItem { get; set; } + + public string Text { - get => _item; + get => _nameLabel.Text; set { - _item = value; - _nameLabel.Text = _itemStringService.GetStringForMapDisplay(_data, _item.Amount); + _nameLabel.Text = value; _nameLabel.ResizeBasedOnText(16, 9); } } - public InventoryPanelItem( - INativeGraphicsManager nativeGraphicsManager, - IItemStringService itemStringService, - IStatusLabelSetter statusLabelSetter, - InventoryPanel inventoryPanel, int slot, IInventoryItem inventoryItem, EIFRecord data) + public event EventHandler DoubleClick; + + public InventoryPanelItem(InventoryPanel inventoryPanel, int slot, IInventoryItem inventoryItem, EIFRecord data) { - _itemStringService = itemStringService; - _statusLabelSetter = statusLabelSetter; _inventoryPanel = inventoryPanel; - _data = data; Slot = slot; - _item = inventoryItem; + InventoryItem = inventoryItem; + _data = data; - _itemGraphic = nativeGraphicsManager.TextureFromResource(GFXTypes.Items, 2 * data.Graphic, transparent: true); + _itemGraphic = inventoryPanel.NativeGraphicsManager.TextureFromResource(GFXTypes.Items, 2 * data.Graphic, transparent: true); _highlightBackground = new Texture2D(Game.GraphicsDevice, 1, 1); _highlightBackground.SetData(new[] { Color.FromNonPremultiplied(200, 200, 200, 60) }); @@ -71,18 +72,16 @@ public InventoryPanelItem( TextAlign = LabelAlignment.MiddleCenter, ForeColor = ColorConstants.LightGrayText, BackColor = Color.FromNonPremultiplied(30, 30, 30, 160), - Text = _itemStringService.GetStringForMapDisplay(data, inventoryItem.Amount) + Text = string.Empty }; - OnMouseEnter += (_, _) => - { - _nameLabel.Visible = true; - _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ITEM, _nameLabel.Text); - }; + OnMouseEnter += (_, _) => _nameLabel.Visible = true; OnMouseLeave += (_, _) => _nameLabel.Visible = false; var (slotWidth, slotHeight) = _data.Size.GetDimensions(); SetSize(slotWidth * 26, slotHeight * 26); + + _clickTimer = new Stopwatch(); } public override void Initialize() @@ -96,6 +95,27 @@ public override void Initialize() protected override void OnUpdateControl(GameTime gameTime) { + if (_recentClicks > 0 && _clickTimer.Elapsed.TotalSeconds > 1) + { + _clickTimer.Restart(); + _recentClicks--; + } + + if (MouseOver && MouseOverPreviously) + { + if (CurrentMouseState.LeftButton == ButtonState.Released && PreviousMouseState.LeftButton == ButtonState.Pressed) + { + _clickTimer.Restart(); + _recentClicks++; + + if (_recentClicks == 2) + { + DoubleClick?.Invoke(this, _data); + _recentClicks = 0; + } + } + } + base.OnUpdateControl(gameTime); } diff --git a/EndlessClient/HUD/Panels/HudPanelFactory.cs b/EndlessClient/HUD/Panels/HudPanelFactory.cs index 74956482a..6c14ed107 100644 --- a/EndlessClient/HUD/Panels/HudPanelFactory.cs +++ b/EndlessClient/HUD/Panels/HudPanelFactory.cs @@ -25,6 +25,7 @@ public class HudPanelFactory : IHudPanelFactory private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IInGameDialogActions _inGameDialogActions; + private readonly ICharacterActions _characterActions; private readonly IContentProvider _contentProvider; private readonly IHudControlProvider _hudControlProvider; private readonly INewsProvider _newsProvider; @@ -33,7 +34,8 @@ public class HudPanelFactory : IHudPanelFactory private readonly ICharacterProvider _characterProvider; private readonly ICharacterInventoryProvider _characterInventoryProvider; private readonly IExperienceTableProvider _experienceTableProvider; - private readonly IEIFFileProvider _eifFileProvider; + private readonly IPubFileProvider _pubFileProvider; + private readonly IPaperdollProvider _paperdollProvider; private readonly IEOMessageBoxFactory _messageBoxFactory; private readonly ITrainingController _trainingController; private readonly IFriendIgnoreListService _friendIgnoreListService; @@ -43,6 +45,7 @@ public class HudPanelFactory : IHudPanelFactory public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, IInGameDialogActions inGameDialogActions, + ICharacterActions characterActions, IContentProvider contentProvider, IHudControlProvider hudControlProvider, INewsProvider newsProvider, @@ -51,7 +54,8 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, ICharacterProvider characterProvider, ICharacterInventoryProvider characterInventoryProvider, IExperienceTableProvider experienceTableProvider, - IEIFFileProvider eifFileProvider, + IPubFileProvider pubFileProvider, + IPaperdollProvider paperdollProvider, IEOMessageBoxFactory messageBoxFactory, ITrainingController trainingController, IFriendIgnoreListService friendIgnoreListService, @@ -61,6 +65,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, { _nativeGraphicsManager = nativeGraphicsManager; _inGameDialogActions = inGameDialogActions; + _characterActions = characterActions; _contentProvider = contentProvider; _hudControlProvider = hudControlProvider; _newsProvider = newsProvider; @@ -69,7 +74,8 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, _characterProvider = characterProvider; _characterInventoryProvider = characterInventoryProvider; _experienceTableProvider = experienceTableProvider; - _eifFileProvider = eifFileProvider; + _pubFileProvider = pubFileProvider; + _paperdollProvider = paperdollProvider; _messageBoxFactory = messageBoxFactory; _trainingController = trainingController; _friendIgnoreListService = friendIgnoreListService; @@ -92,13 +98,15 @@ public InventoryPanel CreateInventoryPanel() { return new InventoryPanel(_nativeGraphicsManager, _inGameDialogActions, + _characterActions, _statusLabelSetter, _itemStringService, _inventoryService, _playerInfoProvider, _characterProvider, + _paperdollProvider, _characterInventoryProvider, - _eifFileProvider) { DrawOrder = HUD_CONTROL_LAYER }; + _pubFileProvider) { DrawOrder = HUD_CONTROL_LAYER }; } public ActiveSpellsPanel CreateActiveSpellsPanel() diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index dab0f944e..ac56589c6 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -6,6 +6,9 @@ using EOLib.Domain.Item; using EOLib.Domain.Login; using EOLib.Graphics; +using EOLib.IO; +using EOLib.IO.Extensions; +using EOLib.IO.Pub; using EOLib.IO.Repositories; using EOLib.Localization; using Microsoft.Win32; @@ -28,15 +31,15 @@ public class InventoryPanel : XNAPanel, IHudPanel // uses absolute coordinates private static readonly Rectangle InventoryGridArea = new Rectangle(110, 334, 377, 116); - - private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly ICharacterActions _characterActions; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IItemStringService _itemStringService; private readonly IInventoryService _inventoryService; private readonly IPlayerInfoProvider _playerInfoProvider; private readonly ICharacterProvider _characterProvider; + private readonly IPaperdollProvider _paperdollProvider; private readonly ICharacterInventoryProvider _characterInventoryProvider; - private readonly IEIFFileProvider _eifFileProvider; + private readonly IPubFileProvider _pubFileProvider; private readonly bool[,] _usedSlots = new bool[4, InventoryRowSlots]; private readonly Dictionary _itemSlotMap; @@ -49,24 +52,30 @@ public class InventoryPanel : XNAPanel, IHudPanel private Option _cachedStats; private HashSet _cachedInventory; + public INativeGraphicsManager NativeGraphicsManager { get; } + public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, IInGameDialogActions inGameDialogActions, + ICharacterActions characterActions, IStatusLabelSetter statusLabelSetter, IItemStringService itemStringService, IInventoryService inventoryService, IPlayerInfoProvider playerInfoProvider, ICharacterProvider characterProvider, + IPaperdollProvider paperdollProvider, ICharacterInventoryProvider characterInventoryProvider, - IEIFFileProvider eifFileProvider) + IPubFileProvider pubFileProvider) { - _nativeGraphicsManager = nativeGraphicsManager; + NativeGraphicsManager = nativeGraphicsManager; + _characterActions = characterActions; _statusLabelSetter = statusLabelSetter; _itemStringService = itemStringService; _inventoryService = inventoryService; _playerInfoProvider = playerInfoProvider; _characterProvider = characterProvider; + _paperdollProvider = paperdollProvider; _characterInventoryProvider = characterInventoryProvider; - _eifFileProvider = eifFileProvider; + _pubFileProvider = pubFileProvider; _weightLabel = new XNALabel(Constants.FontSize08pt5) { DrawArea = new Rectangle(385, 37, 88, 18), @@ -78,7 +87,7 @@ public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, _itemSlotMap = GetItemSlotMap(_playerInfoProvider.LoggedInAccountName, _characterProvider.MainCharacter.Name); - var weirdOffsetSheet = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 27); + var weirdOffsetSheet = NativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 27); _paperdoll = new XNAButton(weirdOffsetSheet, new Vector2(385, 9), new Rectangle(39, 385, 88, 19), new Rectangle(126, 385, 88, 19)); _paperdoll.OnMouseEnter += MouseOverButton; @@ -91,7 +100,7 @@ public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, _cachedStats = Option.None(); _cachedInventory = new HashSet(); - BackgroundImage = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 44); + BackgroundImage = NativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 44); DrawArea = new Rectangle(102, 330, BackgroundImage.Width, BackgroundImage.Height); } @@ -146,23 +155,26 @@ protected override void OnUpdateControl(GameTime gameTime) childItem.Dispose(); _childItems.Remove(childItem); - var itemData = _eifFileProvider.EIFFile[item.ItemID]; + var itemData = _pubFileProvider.EIFFile[item.ItemID]; _inventoryService.ClearSlots(_usedSlots, childItem.Slot, itemData.Size); }); } foreach (var item in updated) { + var itemData = _pubFileProvider.EIFFile[item.ItemID]; + var matchedItem = _childItems.SingleOrNone(x => x.InventoryItem.ItemID == item.ItemID); matchedItem.MatchSome(childItem => { childItem.InventoryItem = item; + childItem.Text = _itemStringService.GetStringForMapDisplay(itemData, item.Amount); }); } foreach (var item in added) { - var itemData = _eifFileProvider.EIFFile[item.ItemID]; + var itemData = _pubFileProvider.EIFFile[item.ItemID]; var preferredSlot = _itemSlotMap.SingleOrNone(x => x.Value == item.ItemID).Map(x => x.Key); var actualSlot = _inventoryService.GetNextOpenSlot(_usedSlots, itemData.Size, preferredSlot); @@ -171,10 +183,14 @@ protected override void OnUpdateControl(GameTime gameTime) { _inventoryService.SetSlots(_usedSlots, slot, itemData.Size); - var newItem = new InventoryPanelItem(_nativeGraphicsManager, _itemStringService, _statusLabelSetter, this, slot, item, itemData); + var newItem = new InventoryPanelItem(this, slot, item, itemData); newItem.Initialize(); newItem.SetParentControl(this); newItem.DrawOrder = 102 - (slot % InventoryRowSlots) * 2; + newItem.Text = _itemStringService.GetStringForMapDisplay(itemData, item.Amount); + + newItem.OnMouseEnter += (_, _) => _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ITEM, newItem.Text); + newItem.DoubleClick += HandleItemDoubleClick; _childItems.Add(newItem); }); @@ -274,5 +290,133 @@ private static RegistryKey TryGetCharacterRegistryKey(string accountName, string return retKey; } + + private void HandleItemDoubleClick(object sender, EIFRecord itemData) + { + var c = _characterProvider.MainCharacter; + if (!_paperdollProvider.VisibleCharacterPaperdolls.ContainsKey(c.ID)) + return; + + var isAlternateEquipLocation = false; + + switch (itemData.Type) + { + case ItemType.Armlet: + case ItemType.Bracer: + case ItemType.Ring: + var paperdoll = _paperdollProvider.VisibleCharacterPaperdolls[c.ID].Paperdoll; + + var equipLocation = itemData.GetEquipLocation(); + if (paperdoll[equipLocation] != 0) + { + isAlternateEquipLocation = true; + if (paperdoll[equipLocation + 1] != 0) + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, EOResourceID.STATUS_LABEL_ITEM_EQUIP_TYPE_ALREADY_EQUIPPED); + return; + } + } + + goto case ItemType.Weapon; + case ItemType.Armor: + if (c.RenderProperties.Gender != itemData.Gender) + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, EOResourceID.STATUS_LABEL_ITEM_EQUIP_DOES_NOT_FIT_GENDER); + return; + } + + goto case ItemType.Weapon; + case ItemType.Accessory: + case ItemType.Belt: + case ItemType.Boots: + case ItemType.Gloves: + case ItemType.Hat: + case ItemType.Necklace: + case ItemType.Shield: + case ItemType.Weapon: + var reqs = new int[6]; + var reqNames = new[] { "STR", "INT", "WIS", "AGI", "CON", "CHA" }; + if ((reqs[0] = itemData.StrReq) > c.Stats[CharacterStat.Strength] || (reqs[1] = itemData.IntReq) > c.Stats[CharacterStat.Intelligence] + || (reqs[2] = itemData.WisReq) > c.Stats[CharacterStat.Wisdom] || (reqs[3] = itemData.AgiReq) > c.Stats[CharacterStat.Agility] + || (reqs[4] = itemData.ConReq) > c.Stats[CharacterStat.Constituion] || (reqs[5] = itemData.ChaReq) > c.Stats[CharacterStat.Charisma]) + { + var req = reqs.Select((i, n) => new { Req = n, Ndx = i }).First(x => x.Req > 0); + + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, + EOResourceID.STATUS_LABEL_ITEM_EQUIP_THIS_ITEM_REQUIRES, + $" {reqs[req.Ndx]} {reqNames[req.Ndx]}"); + return; + } + + if (itemData.ClassReq > 0 && itemData.ClassReq != c.ClassID) + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, + EOResourceID.STATUS_LABEL_ITEM_EQUIP_CAN_ONLY_BE_USED_BY, + _pubFileProvider.ECFFile[itemData.ClassReq].Name); + return; + } + + paperdoll = _paperdollProvider.VisibleCharacterPaperdolls[c.ID].Paperdoll; + equipLocation = itemData.GetEquipLocation(); + + if (paperdoll[equipLocation] != 0 && !isAlternateEquipLocation) + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, EOResourceID.STATUS_LABEL_ITEM_EQUIP_TYPE_ALREADY_EQUIPPED); + return; + } + + _characterActions.EquipItem((short)itemData.ID, isAlternateEquipLocation); + + break; + //usable items + case ItemType.Teleport: + //if (!OldWorld.Instance.ActiveMapRenderer.MapRef.Properties.CanScroll) + //{ + // EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_NOTHING_HAPPENED); + // break; + //} + //if (m_itemData.ScrollMap == OldWorld.Instance.MainPlayer.ActiveCharacter.CurrentMap && + // m_itemData.ScrollX == OldWorld.Instance.MainPlayer.ActiveCharacter.X && + // m_itemData.ScrollY == OldWorld.Instance.MainPlayer.ActiveCharacter.Y) + break; //already there - no need to scroll! + //useItem = true; + break; + case ItemType.Heal: + case ItemType.HairDye: + case ItemType.Beer: + //useItem = true; + break; + case ItemType.CureCurse: + //note: don't actually set the useItem bool here. Call API.UseItem if the dialog result is OK. + //if (c.PaperDoll.Select(id => OldWorld.Instance.EIF[id]) + // .Any(rec => rec.Special == ItemSpecial.Cursed)) + //{ + // EOMessageBox.Show(DialogResourceID.ITEM_CURSE_REMOVE_PROMPT, EODialogButtons.OkCancel, EOMessageBoxStyle.SmallDialogSmallHeader, + // (o, e) => + // { + // //if (e.Result == XNADialogResult.OK && !m_api.UseItem((short)m_itemData.ID)) + // //{ + // // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + // //} + // }); + //} + break; + case ItemType.EXPReward: + //useItem = true; + break; + case ItemType.EffectPotion: + //useItem = true; + break; + //Not implemented server-side + //case ItemType.SkillReward: + // break; + //case ItemType.StatReward: + // break; + } + + //if (useItem && !m_api.UseItem((short)m_itemData.ID)) + // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + + } } } \ No newline at end of file From fa9898db1b94e25e9509efe4681d7607bfdf1e2c Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 27 Mar 2022 17:31:16 -0700 Subject: [PATCH 07/17] Add Save to IniReader --- EOLib.Config/IniReader.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/EOLib.Config/IniReader.cs b/EOLib.Config/IniReader.cs index 0bd14c6b7..33d87eb76 100644 --- a/EOLib.Config/IniReader.cs +++ b/EOLib.Config/IniReader.cs @@ -68,6 +68,30 @@ public bool Load() return true; } + public void Save() + { + try + { + using (var sw = new StreamWriter(_filename)) + { + foreach (var section in _sections) + { + sw.WriteLine($"[{section.Key}]"); + + foreach (var kvp in section.Value) + { + sw.WriteLine($"{kvp.Key}={kvp.Value}"); + } + + sw.WriteLine(); + } + } + } + catch (IOException) + { + } + } + public bool GetValue(string section, string key, out string value) { value = null; From e5b6c1b35fb6c65d4ca6fb270e58913408fc5c04 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 27 Mar 2022 17:33:15 -0700 Subject: [PATCH 08/17] First-pass implementation of drag+drop in inventory 1. Single-click to start dragging 2. Click+hold to start dragging 3. Double-click to equip still works 4. Dragging one item over multiple will reset it to it's original spot (or continue dragging if it no longer fits) 5. Dragging one item over another will start dragging that other item --- .../HUD/Inventory/InventoryPanelItem.cs | 138 +++++++++++++++--- .../HUD/Inventory/InventoryService.cs | 32 +++- EndlessClient/HUD/Panels/InventoryPanel.cs | 129 ++++++++++++++-- 3 files changed, 261 insertions(+), 38 deletions(-) diff --git a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs index c47cca217..148333569 100644 --- a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs +++ b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs @@ -1,11 +1,9 @@ using EndlessClient.HUD.Panels; using EOLib; using EOLib.Domain.Character; -using EOLib.Domain.Item; using EOLib.Graphics; using EOLib.IO.Extensions; using EOLib.IO.Pub; -using EOLib.Localization; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -17,10 +15,21 @@ namespace EndlessClient.HUD.Inventory { public class InventoryPanelItem : XNAControl { - private readonly IStatusLabelSetter _statusLabelSetter; - private readonly InventoryPanel _inventoryPanel; - private readonly EIFRecord _data; + public class ItemDragCompletedEventArgs + { + public bool ContinueDrag { get; set; } = false; + + public bool RestoreOriginalSlot { get; set; } = false; + + public EIFRecord Data { get; } + + public ItemDragCompletedEventArgs(EIFRecord data) => Data = data; + } + + // uses absolute coordinates + private static readonly Rectangle InventoryGridArea = new Rectangle(110, 334, 377, 116); + private readonly InventoryPanel _inventoryPanel; private readonly Texture2D _itemGraphic; private readonly Texture2D _highlightBackground; private readonly XNALabel _nameLabel; @@ -30,6 +39,18 @@ public class InventoryPanelItem : XNAControl private readonly Stopwatch _clickTimer; private int _recentClicks; + private ulong _updateTick; + + // Ru Paul's drag properties + private bool _beingDragged; + private Vector2 _oldOffset; + + private bool MousePressed => CurrentMouseState.LeftButton == ButtonState.Pressed && PreviousMouseState.LeftButton == ButtonState.Released; + + private bool MouseReleased => CurrentMouseState.LeftButton == ButtonState.Released && PreviousMouseState.LeftButton == ButtonState.Pressed; + + private bool MouseHeld => CurrentMouseState.LeftButton == ButtonState.Pressed && PreviousMouseState.LeftButton == ButtonState.Pressed; + public int Slot { get => _slot; @@ -37,6 +58,7 @@ public int Slot { _slot = value; DrawPosition = GetPosition(_slot); + DrawOrder = 102 - (_slot % InventoryPanel.InventoryRowSlots) * 2; } } @@ -52,14 +74,19 @@ public string Text } } + public bool IsDragging => _beingDragged; + + public EIFRecord Data { get; } + public event EventHandler DoubleClick; + public event EventHandler DoneDragging; public InventoryPanelItem(InventoryPanel inventoryPanel, int slot, IInventoryItem inventoryItem, EIFRecord data) { _inventoryPanel = inventoryPanel; Slot = slot; InventoryItem = inventoryItem; - _data = data; + Data = data; _itemGraphic = inventoryPanel.NativeGraphicsManager.TextureFromResource(GFXTypes.Items, 2 * data.Graphic, transparent: true); _highlightBackground = new Texture2D(Game.GraphicsDevice, 1, 1); @@ -75,15 +102,37 @@ public InventoryPanelItem(InventoryPanel inventoryPanel, int slot, IInventoryIte Text = string.Empty }; - OnMouseEnter += (_, _) => _nameLabel.Visible = true; + OnMouseEnter += (_, _) => _nameLabel.Visible = !_beingDragged; OnMouseLeave += (_, _) => _nameLabel.Visible = false; - var (slotWidth, slotHeight) = _data.Size.GetDimensions(); - SetSize(slotWidth * 26, slotHeight * 26); + var (slotWidth, slotHeight) = Data.Size.GetDimensions(); + SetSize(slotWidth * 26 - 3, slotHeight * 26 - 3); _clickTimer = new Stopwatch(); } + public int GetCurrentSlotBasedOnPosition() + { + if (!_beingDragged) + return Slot; + + return (int)((DrawPosition.X - _oldOffset.X) / 26) + InventoryPanel.InventoryRowSlots * (int)((DrawPosition.Y - _oldOffset.Y) / 26); + } + + public void StartDragging() + { + _beingDragged = true; + _nameLabel.Visible = false; + + _oldOffset = DrawPositionWithParentOffset - DrawPosition; + + // todo: drag without unparenting this control + SetControlUnparented(); + AddControlToDefaultGame(); + + DrawOrder = 1000; + } + public override void Initialize() { _nameLabel.Initialize(); @@ -95,23 +144,63 @@ public override void Initialize() protected override void OnUpdateControl(GameTime gameTime) { - if (_recentClicks > 0 && _clickTimer.Elapsed.TotalSeconds > 1) + if (_recentClicks > 0) { - _clickTimer.Restart(); - _recentClicks--; + if (_clickTimer.Elapsed.TotalMilliseconds > 500) + { + _clickTimer.Restart(); + _recentClicks--; + } + else if (_clickTimer.Elapsed.TotalMilliseconds > 200 && _inventoryPanel.NoItemsDragging()) + { + StartDragging(); + } } - if (MouseOver && MouseOverPreviously) + if (MousePressed) + _updateTick = 0; + + if (!_beingDragged && MouseOver && MouseOverPreviously && MouseReleased) { - if (CurrentMouseState.LeftButton == ButtonState.Released && PreviousMouseState.LeftButton == ButtonState.Pressed) + _clickTimer.Restart(); + _recentClicks++; + + if (_recentClicks == 2) { - _clickTimer.Restart(); - _recentClicks++; + DoubleClick?.Invoke(this, Data); + _recentClicks = 0; + } + } + else if (++_updateTick % 8 == 0 && !_beingDragged && MouseOver && MouseOverPreviously && MouseHeld) + { + if (_inventoryPanel.NoItemsDragging()) + { + StartDragging(); + } + } + else if (_beingDragged) + { + DrawPosition = new Vector2(CurrentMouseState.X - (DrawArea.Width / 2), CurrentMouseState.Y - (DrawArea.Height / 2)); + + if (MouseReleased) + { + var args = new ItemDragCompletedEventArgs(Data); + DoneDragging?.Invoke(this, args); - if (_recentClicks == 2) + if (!args.ContinueDrag) { - DoubleClick?.Invoke(this, _data); - _recentClicks = 0; + if (Game.Components.Contains(this)) + Game.Components.Remove(this); + + SetParentControl(_inventoryPanel); + + if (!args.RestoreOriginalSlot) + Slot = GetCurrentSlotBasedOnPosition(); + else + DrawPosition = GetPosition(Slot); + + _beingDragged = false; + _nameLabel.Visible = false; } } } @@ -125,10 +214,17 @@ protected override void OnDrawControl(GameTime gameTime) if (MouseOver) { - _spriteBatch.Draw(_highlightBackground, DrawAreaWithParentOffset.WithSize(DrawArea.Width - 3, DrawArea.Height - 3), Color.White); + // slot based on current mouse position if being dragged + var currentSlot = GetCurrentSlotBasedOnPosition(); + var drawPosition = GetPosition(currentSlot) + (_beingDragged ? _oldOffset : ImmediateParent.DrawPositionWithParentOffset); + + if (InventoryGridArea.Contains(drawPosition)) + { + _spriteBatch.Draw(_highlightBackground, DrawArea.WithPosition(drawPosition), Color.White); + } } - _spriteBatch.Draw(_itemGraphic, DrawPositionWithParentOffset, Color.White); + _spriteBatch.Draw(_itemGraphic, DrawPositionWithParentOffset, Color.FromNonPremultiplied(255, 255, 255, _beingDragged ? 128 : 255)); _spriteBatch.End(); diff --git a/EndlessClient/HUD/Inventory/InventoryService.cs b/EndlessClient/HUD/Inventory/InventoryService.cs index 1fc1a2405..f111b8af1 100644 --- a/EndlessClient/HUD/Inventory/InventoryService.cs +++ b/EndlessClient/HUD/Inventory/InventoryService.cs @@ -3,6 +3,7 @@ using EOLib.IO; using EOLib.IO.Extensions; using Optional; +using System.Collections.Generic; namespace EndlessClient.HUD.Inventory { @@ -14,7 +15,7 @@ public Option GetNextOpenSlot(bool[,] usedSlots, ItemSize size, Option var (sizeWidth, sizeHeight) = size.GetDimensions(); var preferredSlotIsValid = preferredSlot.Match( - some: slot => IsSlotOpen(usedSlots, slot, size), + some: slot => IsSlotOpen(usedSlots, Option.None(), slot, size), none: () => false); if (preferredSlotIsValid) @@ -25,7 +26,7 @@ public Option GetNextOpenSlot(bool[,] usedSlots, ItemSize size, Option for (int c = 0; c < usedSlots.GetLength(1); c++) { var slot = r * InventoryPanel.InventoryRowSlots + c; - if (!usedSlots[r, c] && IsSlotOpen(usedSlots, slot, size)) + if (!usedSlots[r, c] && IsSlotOpen(usedSlots, Option.None(), slot, size)) return Option.Some(slot); } } @@ -43,17 +44,36 @@ public void ClearSlots(bool[,] usedSlots, int slot, ItemSize size) SetSlotValue(usedSlots, slot, size, value: false); } - private bool IsSlotOpen(bool[,] usedSlots, int slot, ItemSize size) + public bool FitsInSlot(bool[,] usedSlots, int oldSlot, int newSlot, ItemSize size) => + IsSlotOpen(usedSlots, Option.Some(oldSlot), newSlot, size); + + public bool FitsInSlot(bool[,] usedSlots, int newSlot, ItemSize size) => + IsSlotOpen(usedSlots, Option.None(), newSlot, size); + + private bool IsSlotOpen(bool[,] usedSlots, Option oldSlot, int slot, ItemSize size) { var (sizeWidth, sizeHeight) = size.GetDimensions(); + var ignorePoints = new List<(int X, int Y)>(); + oldSlot.MatchSome(s => + { + var oldCol = s % InventoryPanel.InventoryRowSlots; + var oldRow = s / InventoryPanel.InventoryRowSlots; + + for (int r = oldRow; r < oldRow + sizeHeight; r++) + for (int c = oldCol; c < oldCol + sizeWidth; c++) + ignorePoints.Add((c, r)); + }); + var col = slot % InventoryPanel.InventoryRowSlots; var row = slot / InventoryPanel.InventoryRowSlots; for (int r = row; r < row + sizeHeight; r++) { for (int c = col; c < col + sizeWidth; c++) { - if (r >= usedSlots.GetLength(0) || c >= usedSlots.GetLength(1) || usedSlots[r, c]) + if (r >= usedSlots.GetLength(0) || c >= usedSlots.GetLength(1) || + r < 0 || c < 0 || + (!ignorePoints.Contains((c, r)) && usedSlots[r, c])) return false; } } @@ -85,5 +105,9 @@ public interface IInventoryService void SetSlots(bool[,] usedSlots, int slot, ItemSize size); void ClearSlots(bool[,] usedSlots, int slot, ItemSize size); + + bool FitsInSlot(bool[,] usedSlots, int oldSlot, int newSlot, ItemSize size); + + bool FitsInSlot(bool[,] usedSlots, int newSlot, ItemSize size); } } diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index ac56589c6..e551861f1 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -29,8 +29,6 @@ public class InventoryPanel : XNAPanel, IHudPanel { public const int InventoryRowSlots = 14; - // uses absolute coordinates - private static readonly Rectangle InventoryGridArea = new Rectangle(110, 334, 377, 116); private readonly ICharacterActions _characterActions; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IItemStringService _itemStringService; @@ -41,6 +39,7 @@ public class InventoryPanel : XNAPanel, IHudPanel private readonly ICharacterInventoryProvider _characterInventoryProvider; private readonly IPubFileProvider _pubFileProvider; + // todo: move slot state to provider/repository pattern so it can be referenced by InventorySpaceValidator private readonly bool[,] _usedSlots = new bool[4, InventoryRowSlots]; private readonly Dictionary _itemSlotMap; private readonly List _childItems = new List(); @@ -102,8 +101,12 @@ public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, BackgroundImage = NativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 44); DrawArea = new Rectangle(102, 330, BackgroundImage.Width, BackgroundImage.Height); + + Game.Exiting += SaveInventoryFile; } + public bool NoItemsDragging() => _childItems.All(x => !x.IsDragging); + public override void Initialize() { _weightLabel.Initialize(); @@ -186,11 +189,11 @@ protected override void OnUpdateControl(GameTime gameTime) var newItem = new InventoryPanelItem(this, slot, item, itemData); newItem.Initialize(); newItem.SetParentControl(this); - newItem.DrawOrder = 102 - (slot % InventoryRowSlots) * 2; newItem.Text = _itemStringService.GetStringForMapDisplay(itemData, item.Amount); newItem.OnMouseEnter += (_, _) => _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ITEM, newItem.Text); newItem.DoubleClick += HandleItemDoubleClick; + newItem.DoneDragging += HandleItemDoneDragging; _childItems.Add(newItem); }); @@ -206,18 +209,12 @@ protected override void Dispose(bool disposing) { if (disposing) { - var inventory = new IniReader(Constants.InventoryFile); - if (inventory.Load() && inventory.Sections.ContainsKey(_playerInfoProvider.LoggedInAccountName)) - { - var section = inventory.Sections[_playerInfoProvider.LoggedInAccountName]; - - foreach (var item in _childItems) - section[$"{_characterProvider.MainCharacter.Name}.{item.Slot}"] = $"{item.InventoryItem.ItemID}"; - } - _paperdoll.OnMouseEnter -= MouseOverButton; _drop.OnMouseEnter -= MouseOverButton; _junk.OnMouseEnter -= MouseOverButton; + Game.Exiting -= SaveInventoryFile; + + SaveInventoryFile(null, EventArgs.Empty); } base.Dispose(disposing); @@ -291,6 +288,24 @@ private static RegistryKey TryGetCharacterRegistryKey(string accountName, string return retKey; } + private void SaveInventoryFile(object sender, EventArgs e) + { + var inventory = new IniReader(Constants.InventoryFile); + + var section = inventory.Load() && inventory.Sections.ContainsKey(_playerInfoProvider.LoggedInAccountName) + ? inventory.Sections[_playerInfoProvider.LoggedInAccountName] + : new SortedList(); + + foreach (var item in _childItems) + section[$"{_characterProvider.MainCharacter.Name}.{item.Slot}"] = $"{item.InventoryItem.ItemID}"; + + inventory.Sections[_playerInfoProvider.LoggedInAccountName] = section; + + inventory.Save(); + + base.UnloadContent(); + } + private void HandleItemDoubleClick(object sender, EIFRecord itemData) { var c = _characterProvider.MainCharacter; @@ -378,7 +393,7 @@ private void HandleItemDoubleClick(object sender, EIFRecord itemData) //if (m_itemData.ScrollMap == OldWorld.Instance.MainPlayer.ActiveCharacter.CurrentMap && // m_itemData.ScrollX == OldWorld.Instance.MainPlayer.ActiveCharacter.X && // m_itemData.ScrollY == OldWorld.Instance.MainPlayer.ActiveCharacter.Y) - break; //already there - no need to scroll! + break; //already there - no need to scroll! //useItem = true; break; case ItemType.Heal: @@ -418,5 +433,93 @@ private void HandleItemDoubleClick(object sender, EIFRecord itemData) // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); } + + private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCompletedEventArgs e) + { + var item = sender as InventoryPanelItem; + if (item == null) + return; + + var oldSlot = item.Slot; + var newSlot = item.GetCurrentSlotBasedOnPosition(); + + // check overlapping items: + // 1. If there's multiple items under it, snap it back to the original slot + // 2. If there's only one item under it, start dragging that item + // 3. If there's nothing under it, make sure it fits in the inventory, otherwise snap back to original slot + + var overlapped = GetOverlappingTakenSlots(newSlot, e.Data.Size, _childItems.Except(new[] { item }).Select(x => (x.Slot, x.Data.Size))) + .ToList(); + + if (overlapped.Count > 1) + { + e.RestoreOriginalSlot = true; + + if (!_inventoryService.FitsInSlot(_usedSlots, oldSlot, e.Data.Size)) + e.ContinueDrag = true; + } + else if (overlapped.Count == 1) + { + _inventoryService.ClearSlots(_usedSlots, oldSlot, e.Data.Size); + _inventoryService.SetSlots(_usedSlots, newSlot, e.Data.Size); + + // start a chained drag on another item (see below comment) + _childItems.Single(x => x.Slot == overlapped[0]).StartDragging(); + } + else if (oldSlot != newSlot) + { + if (!_inventoryService.FitsInSlot(_usedSlots, oldSlot, newSlot, e.Data.Size)) + { + // if the original slot no longer fits (because this is a chained drag), don't stop dragging this item + if (!_inventoryService.FitsInSlot(_usedSlots, oldSlot, e.Data.Size)) + e.ContinueDrag = true; + else + e.RestoreOriginalSlot = true; + } + else + { + _inventoryService.ClearSlots(_usedSlots, oldSlot, e.Data.Size); + _inventoryService.SetSlots(_usedSlots, newSlot, e.Data.Size); + } + } + + // todo: handle drag to things (dialog, map, buttons) + } + + private static IEnumerable GetOverlappingTakenSlots(int newSlot, ItemSize size, IEnumerable<(int Slot, ItemSize Size)> items) + { + var slotX = newSlot % InventoryRowSlots; + var slotY = newSlot / InventoryRowSlots; + var slotItemDim = size.GetDimensions(); + + var newSlotCoords = new List<(int X, int Y)>(); + for (int r = slotY; r < slotY + slotItemDim.Height; r++) + for (int c = slotX; c < slotX + slotItemDim.Width; c++) + newSlotCoords.Add((c, r)); + + foreach (var item in items) + { + var itemX = item.Slot % InventoryRowSlots; + var itemY = item.Slot / InventoryRowSlots; + var itemDim = item.Size.GetDimensions(); + + var @break = false; + for (int r = itemY; r < itemY + itemDim.Height; r++) + { + if (@break) + break; + + for (int c = itemX; c < itemX + itemDim.Width; c++) + { + if (newSlotCoords.Contains((c, r))) + { + yield return item.Slot; + @break = true; + break; + } + } + } + } + } } } \ No newline at end of file From 5d01f6e12adbece0d68459999531c065f9a516ce Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 27 Mar 2022 18:44:06 -0700 Subject: [PATCH 09/17] Fix render order of inventory item name labels. Fix display of inventory item background outside the bounds of the inventory grid. --- .../HUD/Inventory/InventoryPanelItem.cs | 17 ++++++++++------- EndlessClient/HUD/Panels/InventoryPanel.cs | 4 ++++ 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs index 148333569..6c4d830f9 100644 --- a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs +++ b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs @@ -27,7 +27,7 @@ public class ItemDragCompletedEventArgs } // uses absolute coordinates - private static readonly Rectangle InventoryGridArea = new Rectangle(110, 334, 377, 116); + private static readonly Rectangle InventoryGridArea = new Rectangle(114, 338, 363, 102); private readonly InventoryPanel _inventoryPanel; private readonly Texture2D _itemGraphic; @@ -214,13 +214,16 @@ protected override void OnDrawControl(GameTime gameTime) if (MouseOver) { - // slot based on current mouse position if being dragged - var currentSlot = GetCurrentSlotBasedOnPosition(); - var drawPosition = GetPosition(currentSlot) + (_beingDragged ? _oldOffset : ImmediateParent.DrawPositionWithParentOffset); - - if (InventoryGridArea.Contains(drawPosition)) + if (!_beingDragged || InventoryGridArea.Contains(CurrentMouseState.Position)) { - _spriteBatch.Draw(_highlightBackground, DrawArea.WithPosition(drawPosition), Color.White); + // slot based on current mouse position if being dragged + var currentSlot = GetCurrentSlotBasedOnPosition(); + var drawPosition = GetPosition(currentSlot) + (_beingDragged ? _oldOffset : ImmediateParent.DrawPositionWithParentOffset); + + if (InventoryGridArea.Contains(DrawArea.WithPosition(drawPosition))) + { + _spriteBatch.Draw(_highlightBackground, DrawArea.WithPosition(drawPosition), Color.White); + } } } diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index e551861f1..b867bce02 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -195,6 +195,10 @@ protected override void OnUpdateControl(GameTime gameTime) newItem.DoubleClick += HandleItemDoubleClick; newItem.DoneDragging += HandleItemDoneDragging; + // side-effect of calling newItem.SetParentControl(this) is that the draw order gets reset + // setting the slot manually here resets it so the item labels render appropriately + newItem.Slot = slot; + _childItems.Add(newItem); }); } From b7e3540ea38fc7c381428a8f12647c934dc17980 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 27 Mar 2022 18:52:32 -0700 Subject: [PATCH 10/17] Extract ItemNameColorService for getting colors for item name labels in inventory/map --- .../HUD/Inventory/InventoryPanelItem.cs | 4 +- EndlessClient/HUD/ItemNameColorService.cs | 37 +++++++++++++++++++ EndlessClient/HUD/Panels/HudPanelFactory.cs | 4 ++ EndlessClient/HUD/Panels/InventoryPanel.cs | 5 ++- .../Factories/MouseCursorRendererFactory.cs | 5 +++ .../Rendering/MouseCursorRenderer.cs | 21 +++-------- 6 files changed, 57 insertions(+), 19 deletions(-) create mode 100644 EndlessClient/HUD/ItemNameColorService.cs diff --git a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs index 6c4d830f9..f91bdc04a 100644 --- a/EndlessClient/HUD/Inventory/InventoryPanelItem.cs +++ b/EndlessClient/HUD/Inventory/InventoryPanelItem.cs @@ -81,7 +81,7 @@ public string Text public event EventHandler DoubleClick; public event EventHandler DoneDragging; - public InventoryPanelItem(InventoryPanel inventoryPanel, int slot, IInventoryItem inventoryItem, EIFRecord data) + public InventoryPanelItem(IItemNameColorService itemNameColorService, InventoryPanel inventoryPanel, int slot, IInventoryItem inventoryItem, EIFRecord data) { _inventoryPanel = inventoryPanel; Slot = slot; @@ -97,7 +97,7 @@ public InventoryPanelItem(InventoryPanel inventoryPanel, int slot, IInventoryIte Visible = false, AutoSize = false, TextAlign = LabelAlignment.MiddleCenter, - ForeColor = ColorConstants.LightGrayText, + ForeColor = itemNameColorService.GetColorForInventoryDisplay(Data), BackColor = Color.FromNonPremultiplied(30, 30, 30, 160), Text = string.Empty }; diff --git a/EndlessClient/HUD/ItemNameColorService.cs b/EndlessClient/HUD/ItemNameColorService.cs new file mode 100644 index 000000000..d37a3217c --- /dev/null +++ b/EndlessClient/HUD/ItemNameColorService.cs @@ -0,0 +1,37 @@ +using AutomaticTypeMapper; +using EOLib.Graphics; +using EOLib.IO; +using EOLib.IO.Pub; +using Microsoft.Xna.Framework; + +namespace EndlessClient.HUD +{ + [AutoMappedType] + public class ItemNameColorService : IItemNameColorService + { + public Color GetColorForInventoryDisplay(EIFRecord itemData) => GetColor(itemData, ColorConstants.LightGrayText); + + public Color GetColorForMapDisplay(EIFRecord itemData) => GetColor(itemData, Color.White); + + private static Color GetColor(EIFRecord itemData, Color defaultColor) + { + switch (itemData.Special) + { + case ItemSpecial.Lore: + case ItemSpecial.Unique: + return Color.FromNonPremultiplied(0xff, 0xf0, 0xa5, 0xff); + case ItemSpecial.Rare: + return Color.FromNonPremultiplied(0xf5, 0xc8, 0x9c, 0xff); + } + + return defaultColor; + } + } + + public interface IItemNameColorService + { + Color GetColorForMapDisplay(EIFRecord itemData); + + Color GetColorForInventoryDisplay(EIFRecord itemData); + } +} diff --git a/EndlessClient/HUD/Panels/HudPanelFactory.cs b/EndlessClient/HUD/Panels/HudPanelFactory.cs index 6c14ed107..7100cd0eb 100644 --- a/EndlessClient/HUD/Panels/HudPanelFactory.cs +++ b/EndlessClient/HUD/Panels/HudPanelFactory.cs @@ -41,6 +41,7 @@ public class HudPanelFactory : IHudPanelFactory private readonly IFriendIgnoreListService _friendIgnoreListService; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IItemStringService _itemStringService; + private readonly IItemNameColorService _itemNameColorService; private readonly IInventoryService _inventoryService; public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, @@ -61,6 +62,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, IFriendIgnoreListService friendIgnoreListService, IStatusLabelSetter statusLabelSetter, IItemStringService itemStringService, + IItemNameColorService itemNameColorService, IInventoryService inventoryService) { _nativeGraphicsManager = nativeGraphicsManager; @@ -81,6 +83,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, _friendIgnoreListService = friendIgnoreListService; _statusLabelSetter = statusLabelSetter; _itemStringService = itemStringService; + _itemNameColorService = itemNameColorService; _inventoryService = inventoryService; } @@ -101,6 +104,7 @@ public InventoryPanel CreateInventoryPanel() _characterActions, _statusLabelSetter, _itemStringService, + _itemNameColorService, _inventoryService, _playerInfoProvider, _characterProvider, diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index b867bce02..c00381980 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -32,6 +32,7 @@ public class InventoryPanel : XNAPanel, IHudPanel private readonly ICharacterActions _characterActions; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IItemStringService _itemStringService; + private readonly IItemNameColorService _itemNameColorService; private readonly IInventoryService _inventoryService; private readonly IPlayerInfoProvider _playerInfoProvider; private readonly ICharacterProvider _characterProvider; @@ -58,6 +59,7 @@ public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, ICharacterActions characterActions, IStatusLabelSetter statusLabelSetter, IItemStringService itemStringService, + IItemNameColorService itemNameColorService, IInventoryService inventoryService, IPlayerInfoProvider playerInfoProvider, ICharacterProvider characterProvider, @@ -69,6 +71,7 @@ public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, _characterActions = characterActions; _statusLabelSetter = statusLabelSetter; _itemStringService = itemStringService; + _itemNameColorService = itemNameColorService; _inventoryService = inventoryService; _playerInfoProvider = playerInfoProvider; _characterProvider = characterProvider; @@ -186,7 +189,7 @@ protected override void OnUpdateControl(GameTime gameTime) { _inventoryService.SetSlots(_usedSlots, slot, itemData.Size); - var newItem = new InventoryPanelItem(this, slot, item, itemData); + var newItem = new InventoryPanelItem(_itemNameColorService, this, slot, item, itemData); newItem.Initialize(); newItem.SetParentControl(this); newItem.Text = _itemStringService.GetStringForMapDisplay(itemData, item.Amount); diff --git a/EndlessClient/Rendering/Factories/MouseCursorRendererFactory.cs b/EndlessClient/Rendering/Factories/MouseCursorRendererFactory.cs index eb9084944..19c444b9e 100644 --- a/EndlessClient/Rendering/Factories/MouseCursorRendererFactory.cs +++ b/EndlessClient/Rendering/Factories/MouseCursorRendererFactory.cs @@ -1,6 +1,7 @@ using AutomaticTypeMapper; using EndlessClient.Controllers; using EndlessClient.Dialogs; +using EndlessClient.HUD; using EndlessClient.Input; using EOLib.Domain.Character; using EOLib.Domain.Item; @@ -18,6 +19,7 @@ public class MouseCursorRendererFactory : IMouseCursorRendererFactory private readonly IRenderOffsetCalculator _renderOffsetCalculator; private readonly IMapCellStateProvider _mapCellStateProvider; private readonly IItemStringService _itemStringService; + private readonly IItemNameColorService _itemNameColorService; private readonly IEIFFileProvider _eifFileProvider; private readonly ICurrentMapProvider _currentMapProvider; private readonly IMapInteractionController _mapInteractionController; @@ -30,6 +32,7 @@ public MouseCursorRendererFactory(INativeGraphicsManager nativeGraphicsManager, IRenderOffsetCalculator renderOffsetCalculator, IMapCellStateProvider mapCellStateProvider, IItemStringService itemStringService, + IItemNameColorService itemNameColorService, IEIFFileProvider eifFileProvider, ICurrentMapProvider currentMapProvider, IMapInteractionController mapInteractionController, @@ -42,6 +45,7 @@ public MouseCursorRendererFactory(INativeGraphicsManager nativeGraphicsManager, _renderOffsetCalculator = renderOffsetCalculator; _mapCellStateProvider = mapCellStateProvider; _itemStringService = itemStringService; + _itemNameColorService = itemNameColorService; _eifFileProvider = eifFileProvider; _currentMapProvider = currentMapProvider; _mapInteractionController = mapInteractionController; @@ -57,6 +61,7 @@ public IMouseCursorRenderer Create() _renderOffsetCalculator, _mapCellStateProvider, _itemStringService, + _itemNameColorService, _eifFileProvider, _currentMapProvider, _mapInteractionController, diff --git a/EndlessClient/Rendering/MouseCursorRenderer.cs b/EndlessClient/Rendering/MouseCursorRenderer.cs index acd7d0434..f5bca6a43 100644 --- a/EndlessClient/Rendering/MouseCursorRenderer.cs +++ b/EndlessClient/Rendering/MouseCursorRenderer.cs @@ -1,5 +1,6 @@ using EndlessClient.Controllers; using EndlessClient.Dialogs; +using EndlessClient.HUD; using EndlessClient.Input; using EOLib; using EOLib.Domain.Character; @@ -40,6 +41,7 @@ private enum CursorIndex private readonly IRenderOffsetCalculator _renderOffsetCalculator; private readonly IMapCellStateProvider _mapCellStateProvider; private readonly IItemStringService _itemStringService; + private readonly IItemNameColorService _itemNameColorService; private readonly IEIFFileProvider _eifFileProvider; private readonly ICurrentMapProvider _currentMapProvider; private readonly IMapInteractionController _mapInteractionController; @@ -63,6 +65,7 @@ public MouseCursorRenderer(INativeGraphicsManager nativeGraphicsManager, IRenderOffsetCalculator renderOffsetCalculator, IMapCellStateProvider mapCellStateProvider, IItemStringService itemStringService, + IItemNameColorService itemNameColorService, IEIFFileProvider eifFileProvider, ICurrentMapProvider currentMapProvider, IMapInteractionController mapInteractionController, @@ -75,6 +78,7 @@ public MouseCursorRenderer(INativeGraphicsManager nativeGraphicsManager, _renderOffsetCalculator = renderOffsetCalculator; _mapCellStateProvider = mapCellStateProvider; _itemStringService = itemStringService; + _itemNameColorService = itemNameColorService; _eifFileProvider = eifFileProvider; _currentMapProvider = currentMapProvider; _mapInteractionController = mapInteractionController; @@ -219,7 +223,7 @@ private void UpdateMapItemLabel(Option item) _mapItemText.Visible = true; _mapItemText.Text = text; _mapItemText.ResizeBasedOnText(); - _mapItemText.ForeColor = GetColorForMapDisplay(data); + _mapItemText.ForeColor = _itemNameColorService.GetColorForMapDisplay(data); //relative to cursor DrawPosition, since this control is a parent of MapItemText _mapItemText.DrawPosition = new Vector2(_drawArea.X + 32 - _mapItemText.ActualWidth / 2f, @@ -280,21 +284,6 @@ private void UpdateCursorIndexForTileSpec(TileSpec tileSpec) } } - //todo: extract this into a service (also used by inventory) - private static Color GetColorForMapDisplay(EIFRecord record) - { - switch (record.Special) - { - case ItemSpecial.Lore: - case ItemSpecial.Unique: - return Color.FromNonPremultiplied(0xff, 0xf0, 0xa5, 0xff); - case ItemSpecial.Rare: - return Color.FromNonPremultiplied(0xf5, 0xc8, 0x9c, 0xff); - } - - return Color.White; - } - private async Task CheckForClicks(IMapCellState cellState) { var currentMouseState = _userInputProvider.CurrentMouseState; From 622ce06eec105f60b8935685b6ce4a72500a0c45 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 27 Mar 2022 19:07:34 -0700 Subject: [PATCH 11/17] Extract repository for inventory slots --- EOLib.IO/Map/Matrix.cs | 22 ++++++-------- .../HUD/Inventory/InventorySlotRepository.cs | 29 +++++++++++++++++++ EndlessClient/HUD/Panels/HudPanelFactory.cs | 4 +++ EndlessClient/HUD/Panels/InventoryPanel.cs | 26 +++++++++-------- 4 files changed, 56 insertions(+), 25 deletions(-) create mode 100644 EndlessClient/HUD/Inventory/InventorySlotRepository.cs diff --git a/EOLib.IO/Map/Matrix.cs b/EOLib.IO/Map/Matrix.cs index e43f92c49..553b51a9c 100644 --- a/EOLib.IO/Map/Matrix.cs +++ b/EOLib.IO/Map/Matrix.cs @@ -6,7 +6,7 @@ namespace EOLib.IO.Map { public class Matrix : IReadOnlyMatrix { - private static readonly Matrix _empty = new Matrix(0, 0); + private static readonly Matrix _empty = new Matrix(new T[0,0]); public static Matrix Empty => _empty; private readonly T[,] _arr; @@ -16,22 +16,22 @@ public class Matrix : IReadOnlyMatrix public int Rows { get; } public int Cols { get; } - private Matrix(int rows, int cols) + private Matrix(T[,] other) { - Rows = rows; - Cols = cols; - _arr = new T[rows, cols]; + Rows = other.GetLength(0); + Cols = other.GetLength(1); + _arr = other; } public Matrix(int rows, int cols, T defaultValue) - : this(rows, cols) + : this(new T[rows, cols]) { _default = defaultValue; Fill(defaultValue); } public Matrix(Matrix other) - : this(other.Rows, other.Cols) + : this(new T[other.Rows, other.Cols]) { for (int row = 0; row < other.Rows; ++row) for (int col = 0; col < other.Cols; ++col) @@ -70,16 +70,12 @@ public T[] GetRow(int rowIndex) public static implicit operator T[,](Matrix array) { - var ret = new T[array.Rows, array.Cols]; - Array.Copy(array._arr, ret, ret.Length); - return ret; + return array._arr; } public static implicit operator Matrix(T[,] array) { - var ret = new Matrix(array.GetLength(0), array.GetLength(1)); - Array.Copy(array, ret._arr, array.Length); - return ret; + return new Matrix(array); } public IEnumerator> GetEnumerator() diff --git a/EndlessClient/HUD/Inventory/InventorySlotRepository.cs b/EndlessClient/HUD/Inventory/InventorySlotRepository.cs new file mode 100644 index 000000000..1da3bc145 --- /dev/null +++ b/EndlessClient/HUD/Inventory/InventorySlotRepository.cs @@ -0,0 +1,29 @@ +using AutomaticTypeMapper; +using EndlessClient.HUD.Panels; +using EOLib.IO.Map; + +namespace EndlessClient.HUD.Inventory +{ + public interface IInventorySlotRepository + { + Matrix FilledSlots { get; set; } + } + + public interface IInventorySlotProvider + { + IReadOnlyMatrix FilledSlots { get; } + } + + [AutoMappedType(IsSingleton = true)] + public class InventorySlotRepository : IInventorySlotProvider, IInventorySlotRepository + { + public Matrix FilledSlots { get; set; } + + IReadOnlyMatrix IInventorySlotProvider.FilledSlots => FilledSlots; + + public InventorySlotRepository() + { + FilledSlots = new Matrix(InventoryPanel.InventoryRows, InventoryPanel.InventoryRowSlots, false); + } + } +} diff --git a/EndlessClient/HUD/Panels/HudPanelFactory.cs b/EndlessClient/HUD/Panels/HudPanelFactory.cs index 7100cd0eb..0a68e02c1 100644 --- a/EndlessClient/HUD/Panels/HudPanelFactory.cs +++ b/EndlessClient/HUD/Panels/HudPanelFactory.cs @@ -36,6 +36,7 @@ public class HudPanelFactory : IHudPanelFactory private readonly IExperienceTableProvider _experienceTableProvider; private readonly IPubFileProvider _pubFileProvider; private readonly IPaperdollProvider _paperdollProvider; + private readonly IInventorySlotRepository _inventorySlotRepository; private readonly IEOMessageBoxFactory _messageBoxFactory; private readonly ITrainingController _trainingController; private readonly IFriendIgnoreListService _friendIgnoreListService; @@ -57,6 +58,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, IExperienceTableProvider experienceTableProvider, IPubFileProvider pubFileProvider, IPaperdollProvider paperdollProvider, + IInventorySlotRepository inventorySlotRepository, IEOMessageBoxFactory messageBoxFactory, ITrainingController trainingController, IFriendIgnoreListService friendIgnoreListService, @@ -78,6 +80,7 @@ public HudPanelFactory(INativeGraphicsManager nativeGraphicsManager, _experienceTableProvider = experienceTableProvider; _pubFileProvider = pubFileProvider; _paperdollProvider = paperdollProvider; + _inventorySlotRepository = inventorySlotRepository; _messageBoxFactory = messageBoxFactory; _trainingController = trainingController; _friendIgnoreListService = friendIgnoreListService; @@ -106,6 +109,7 @@ public InventoryPanel CreateInventoryPanel() _itemStringService, _itemNameColorService, _inventoryService, + _inventorySlotRepository, _playerInfoProvider, _characterProvider, _paperdollProvider, diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index c00381980..1c196b962 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -27,6 +27,7 @@ namespace EndlessClient.HUD.Panels { public class InventoryPanel : XNAPanel, IHudPanel { + public const int InventoryRows = 4; public const int InventoryRowSlots = 14; private readonly ICharacterActions _characterActions; @@ -34,14 +35,13 @@ public class InventoryPanel : XNAPanel, IHudPanel private readonly IItemStringService _itemStringService; private readonly IItemNameColorService _itemNameColorService; private readonly IInventoryService _inventoryService; + private readonly IInventorySlotRepository _inventorySlotRepository; private readonly IPlayerInfoProvider _playerInfoProvider; private readonly ICharacterProvider _characterProvider; private readonly IPaperdollProvider _paperdollProvider; private readonly ICharacterInventoryProvider _characterInventoryProvider; private readonly IPubFileProvider _pubFileProvider; - // todo: move slot state to provider/repository pattern so it can be referenced by InventorySpaceValidator - private readonly bool[,] _usedSlots = new bool[4, InventoryRowSlots]; private readonly Dictionary _itemSlotMap; private readonly List _childItems = new List(); @@ -61,6 +61,7 @@ public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, IItemStringService itemStringService, IItemNameColorService itemNameColorService, IInventoryService inventoryService, + IInventorySlotRepository inventorySlotRepository, IPlayerInfoProvider playerInfoProvider, ICharacterProvider characterProvider, IPaperdollProvider paperdollProvider, @@ -73,6 +74,7 @@ public InventoryPanel(INativeGraphicsManager nativeGraphicsManager, _itemStringService = itemStringService; _itemNameColorService = itemNameColorService; _inventoryService = inventoryService; + _inventorySlotRepository = inventorySlotRepository; _playerInfoProvider = playerInfoProvider; _characterProvider = characterProvider; _paperdollProvider = paperdollProvider; @@ -162,7 +164,7 @@ protected override void OnUpdateControl(GameTime gameTime) _childItems.Remove(childItem); var itemData = _pubFileProvider.EIFFile[item.ItemID]; - _inventoryService.ClearSlots(_usedSlots, childItem.Slot, itemData.Size); + _inventoryService.ClearSlots(_inventorySlotRepository.FilledSlots, childItem.Slot, itemData.Size); }); } @@ -183,11 +185,11 @@ protected override void OnUpdateControl(GameTime gameTime) var itemData = _pubFileProvider.EIFFile[item.ItemID]; var preferredSlot = _itemSlotMap.SingleOrNone(x => x.Value == item.ItemID).Map(x => x.Key); - var actualSlot = _inventoryService.GetNextOpenSlot(_usedSlots, itemData.Size, preferredSlot); + var actualSlot = _inventoryService.GetNextOpenSlot(_inventorySlotRepository.FilledSlots, itemData.Size, preferredSlot); actualSlot.MatchSome(slot => { - _inventoryService.SetSlots(_usedSlots, slot, itemData.Size); + _inventoryService.SetSlots(_inventorySlotRepository.FilledSlots, slot, itemData.Size); var newItem = new InventoryPanelItem(_itemNameColorService, this, slot, item, itemData); newItem.Initialize(); @@ -462,31 +464,31 @@ private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCo { e.RestoreOriginalSlot = true; - if (!_inventoryService.FitsInSlot(_usedSlots, oldSlot, e.Data.Size)) + if (!_inventoryService.FitsInSlot(_inventorySlotRepository.FilledSlots, oldSlot, e.Data.Size)) e.ContinueDrag = true; } else if (overlapped.Count == 1) { - _inventoryService.ClearSlots(_usedSlots, oldSlot, e.Data.Size); - _inventoryService.SetSlots(_usedSlots, newSlot, e.Data.Size); + _inventoryService.ClearSlots(_inventorySlotRepository.FilledSlots, oldSlot, e.Data.Size); + _inventoryService.SetSlots(_inventorySlotRepository.FilledSlots, newSlot, e.Data.Size); // start a chained drag on another item (see below comment) _childItems.Single(x => x.Slot == overlapped[0]).StartDragging(); } else if (oldSlot != newSlot) { - if (!_inventoryService.FitsInSlot(_usedSlots, oldSlot, newSlot, e.Data.Size)) + if (!_inventoryService.FitsInSlot(_inventorySlotRepository.FilledSlots, oldSlot, newSlot, e.Data.Size)) { // if the original slot no longer fits (because this is a chained drag), don't stop dragging this item - if (!_inventoryService.FitsInSlot(_usedSlots, oldSlot, e.Data.Size)) + if (!_inventoryService.FitsInSlot(_inventorySlotRepository.FilledSlots, oldSlot, e.Data.Size)) e.ContinueDrag = true; else e.RestoreOriginalSlot = true; } else { - _inventoryService.ClearSlots(_usedSlots, oldSlot, e.Data.Size); - _inventoryService.SetSlots(_usedSlots, newSlot, e.Data.Size); + _inventoryService.ClearSlots(_inventorySlotRepository.FilledSlots, oldSlot, e.Data.Size); + _inventoryService.SetSlots(_inventorySlotRepository.FilledSlots, newSlot, e.Data.Size); } } From b47c2db0bd9f07d109426c04fa9c16892e0a63aa Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 27 Mar 2022 19:12:30 -0700 Subject: [PATCH 12/17] Implement InventorySpaceValidator --- .../HUD/Inventory/InventorySpaceValidator.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs index d0f16b279..3d9f3e88c 100644 --- a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs +++ b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs @@ -1,7 +1,9 @@ using AutomaticTypeMapper; using EOLib.Domain.Map; using EOLib.IO; +using EOLib.IO.Map; using EOLib.IO.Repositories; +using Optional; namespace EndlessClient.HUD.Inventory { @@ -9,10 +11,16 @@ namespace EndlessClient.HUD.Inventory public class InventorySpaceValidator : IInventorySpaceValidator { private readonly IEIFFileProvider _eifFileProvider; + private readonly IInventorySlotProvider _inventorySlotProvider; + private readonly IInventoryService _inventoryService; - public InventorySpaceValidator(IEIFFileProvider eifFileProvider) + public InventorySpaceValidator(IEIFFileProvider eifFileProvider, + IInventorySlotProvider inventorySlotProvider, + IInventoryService inventoryService) { _eifFileProvider = eifFileProvider; + _inventorySlotProvider = inventorySlotProvider; + _inventoryService = inventoryService; } public bool ItemFits(IItem item) @@ -22,8 +30,9 @@ public bool ItemFits(IItem item) public bool ItemFits(ItemSize itemSize) { - // todo: inventory grid management - return true; + return _inventoryService + .GetNextOpenSlot((Matrix)_inventorySlotProvider.FilledSlots, itemSize, Option.None()) + .HasValue; } } From 2d113e7fb1f8f6382297810e6157221929313d67 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Sun, 27 Mar 2022 19:27:16 -0700 Subject: [PATCH 13/17] Remove stale inventory-related code --- .../Dialogs/Old/BankAccountDialog.cs | 20 +- EndlessClient/Dialogs/Old/ChestDialog.cs | 64 +- EndlessClient/Dialogs/Old/LockerDialog.cs | 34 +- EndlessClient/Dialogs/Old/ShopDialog.cs | 28 +- EndlessClient/Dialogs/Old/TradeDialog.cs | 56 +- EndlessClient/HUD/Controls/HUD.cs | 28 - .../HUD/Inventory/InventorySpaceValidator.cs | 2 +- .../HUD/Inventory/OldEOInventoryItem.cs | 590 ------------------ EndlessClient/HUD/Panels/InventoryPanel.cs | 196 ++++++ .../HUD/Panels/Old/OldInventoryPanel.cs | 463 -------------- EndlessClient/Old/OldCharacter.cs | 86 --- EndlessClient/Old/PacketAPICallbackManager.cs | 30 +- 12 files changed, 313 insertions(+), 1284 deletions(-) delete mode 100644 EndlessClient/HUD/Inventory/OldEOInventoryItem.cs delete mode 100644 EndlessClient/HUD/Panels/Old/OldInventoryPanel.cs diff --git a/EndlessClient/Dialogs/Old/BankAccountDialog.cs b/EndlessClient/Dialogs/Old/BankAccountDialog.cs index 79d8d32c2..52af6d17d 100644 --- a/EndlessClient/Dialogs/Old/BankAccountDialog.cs +++ b/EndlessClient/Dialogs/Old/BankAccountDialog.cs @@ -199,16 +199,16 @@ public override void Update(GameTime gt) { if (!Game.IsActive) return; - if (EOGame.Instance.Hud.IsInventoryDragging()) - { - shouldClickDrag = false; - SuppressParentClickDrag(true); - } - else - { - shouldClickDrag = true; - SuppressParentClickDrag(false); - } + //if (EOGame.Instance.Hud.IsInventoryDragging()) + //{ + // shouldClickDrag = false; + // SuppressParentClickDrag(true); + //} + //else + //{ + // shouldClickDrag = true; + // SuppressParentClickDrag(false); + //} base.Update(gt); } diff --git a/EndlessClient/Dialogs/Old/ChestDialog.cs b/EndlessClient/Dialogs/Old/ChestDialog.cs index 4c090175d..46dc7a13b 100644 --- a/EndlessClient/Dialogs/Old/ChestDialog.cs +++ b/EndlessClient/Dialogs/Old/ChestDialog.cs @@ -93,28 +93,28 @@ public void InitializeItems(IList initialItems) OldListDialogItem sender = o as OldListDialogItem; if (sender == null) return; - if (!EOGame.Instance.Hud.InventoryFits(sender.ID)) - { - string _message = OldWorld.GetString(EOResourceID.STATUS_LABEL_ITEM_PICKUP_NO_SPACE_LEFT); - string _caption = OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING); - EOMessageBox.Show(_message, _caption, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, EOResourceID.STATUS_LABEL_ITEM_PICKUP_NO_SPACE_LEFT); - } - else if (rec.Weight * item.Amount + OldWorld.Instance.MainPlayer.ActiveCharacter.Weight > - OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_ITS_TOO_HEAVY_WEIGHT), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - } - else - { - if (!m_api.ChestTakeItem(CurrentChestX, CurrentChestY, sender.ID)) - { - Close(); - EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - } - } + //if (!EOGame.Instance.Hud.InventoryFits(sender.ID)) + //{ + // string _message = OldWorld.GetString(EOResourceID.STATUS_LABEL_ITEM_PICKUP_NO_SPACE_LEFT); + // string _caption = OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING); + // EOMessageBox.Show(_message, _caption, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, EOResourceID.STATUS_LABEL_ITEM_PICKUP_NO_SPACE_LEFT); + //} + //else if (rec.Weight * item.Amount + OldWorld.Instance.MainPlayer.ActiveCharacter.Weight > + // OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight) + //{ + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_ITS_TOO_HEAVY_WEIGHT), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + //} + //else + //{ + // if (!m_api.ChestTakeItem(CurrentChestX, CurrentChestY, sender.ID)) + // { + // Close(); + // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + // } + //} }; } } @@ -141,16 +141,16 @@ public override void Update(GameTime gt) { if (!Game.IsActive) return; - if (EOGame.Instance.Hud.IsInventoryDragging()) - { - shouldClickDrag = false; - SuppressParentClickDrag(true); - } - else - { - shouldClickDrag = true; - SuppressParentClickDrag(false); - } + //if (EOGame.Instance.Hud.IsInventoryDragging()) + //{ + // shouldClickDrag = false; + // SuppressParentClickDrag(true); + //} + //else + //{ + // shouldClickDrag = true; + // SuppressParentClickDrag(false); + //} base.Update(gt); } diff --git a/EndlessClient/Dialogs/Old/LockerDialog.cs b/EndlessClient/Dialogs/Old/LockerDialog.cs index 6cbb32276..23538b8e4 100644 --- a/EndlessClient/Dialogs/Old/LockerDialog.cs +++ b/EndlessClient/Dialogs/Old/LockerDialog.cs @@ -80,13 +80,13 @@ public int GetNewItemAmount(short id, int amount) private void _removeItem(EIFRecord item, int amount) { - if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.STATUS_LABEL_ITEM_PICKUP_NO_SPACE_LEFT), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - return; - } + //if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) + //{ + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.STATUS_LABEL_ITEM_PICKUP_NO_SPACE_LEFT), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // return; + //} if (OldWorld.Instance.MainPlayer.ActiveCharacter.Weight + item.Weight * amount > OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight) { @@ -103,16 +103,16 @@ private void _removeItem(EIFRecord item, int amount) public override void Update(GameTime gt) { if (!Game.IsActive) return; - if (EOGame.Instance.Hud.IsInventoryDragging()) - { - shouldClickDrag = false; - SuppressParentClickDrag(true); - } - else - { - shouldClickDrag = true; - SuppressParentClickDrag(false); - } + //if (EOGame.Instance.Hud.IsInventoryDragging()) + //{ + // shouldClickDrag = false; + // SuppressParentClickDrag(true); + //} + //else + //{ + // shouldClickDrag = true; + // SuppressParentClickDrag(false); + //} base.Update(gt); } diff --git a/EndlessClient/Dialogs/Old/ShopDialog.cs b/EndlessClient/Dialogs/Old/ShopDialog.cs index 4cac1b7aa..f4bc9829d 100644 --- a/EndlessClient/Dialogs/Old/ShopDialog.cs +++ b/EndlessClient/Dialogs/Old/ShopDialog.cs @@ -249,13 +249,13 @@ private void _buySellItem(ShopItem item) var rec = OldWorld.Instance.EIF[item.ID]; if (isBuying) { - if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - return; - } + //if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) + //{ + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // return; + //} if (rec.Weight + OldWorld.Instance.MainPlayer.ActiveCharacter.Weight > OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight) @@ -343,13 +343,13 @@ private void _craftItem(CraftItem item) } } - if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - return; - } + //if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) + //{ + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // return; + //} string _message2 = OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_PUT_INGREDIENTS_TOGETHER) + "\n\n"; foreach (var ingred in item.Ingredients) diff --git a/EndlessClient/Dialogs/Old/TradeDialog.cs b/EndlessClient/Dialogs/Old/TradeDialog.cs index 40b6eded2..4b2956717 100644 --- a/EndlessClient/Dialogs/Old/TradeDialog.cs +++ b/EndlessClient/Dialogs/Old/TradeDialog.cs @@ -282,16 +282,16 @@ public void CompleteTrade(short p1, List p1items, short p2, List< throw new ArgumentException("Invalid player ID for trade session!"); int weightDelta = 0; - foreach (var item in mainCollection) - { - m_main.UpdateInventoryItem(item.ItemID, -item.Amount, true); - weightDelta -= OldWorld.Instance.EIF[item.ItemID].Weight * item.Amount; - } - foreach (var item in otherCollection) - { - m_main.UpdateInventoryItem(item.ItemID, item.Amount, true); - weightDelta += OldWorld.Instance.EIF[item.ItemID].Weight * item.Amount; - } + //foreach (var item in mainCollection) + //{ + // m_main.UpdateInventoryItem(item.ItemID, -item.Amount, true); + // weightDelta -= OldWorld.Instance.EIF[item.ItemID].Weight * item.Amount; + //} + //foreach (var item in otherCollection) + //{ + // m_main.UpdateInventoryItem(item.ItemID, item.Amount, true); + // weightDelta += OldWorld.Instance.EIF[item.ItemID].Weight * item.Amount; + //} m_main.Weight += (byte)weightDelta; ((EOGame)Game).Hud.RefreshStats(); @@ -325,14 +325,14 @@ private void _buttonOkClicked(object sender, EventArgs e) List otherCollection = m_main.ID == m_leftPlayerID ? m_rightItems : m_leftItems; //make sure that the items will fit! - if (!((EOGame)Game).Hud.ItemsFit( - otherCollection.Select(_item => new InventoryItem(_item.ID, _item.Amount)).ToList(), - mainCollection.Select(_item => new InventoryItem(_item.ID, _item.Amount)).ToList())) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - return; - } + //if (!((EOGame)Game).Hud.ItemsFit( + // otherCollection.Select(_item => new InventoryItem(_item.ID, _item.Amount)).ToList(), + // mainCollection.Select(_item => new InventoryItem(_item.ID, _item.Amount)).ToList())) + //{ + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // return; + //} //make sure the change in weight + existing weight is not greater than the max weight! int weightDelta = otherCollection.Sum(itemRef => OldWorld.Instance.EIF[itemRef.ID].Weight * itemRef.Amount); @@ -387,16 +387,16 @@ private void _removeItem(int id) public override void Update(GameTime gt) { - if (EOGame.Instance.Hud.IsInventoryDragging()) - { - shouldClickDrag = false; - SuppressParentClickDrag(true); - } - else - { - shouldClickDrag = true; - SuppressParentClickDrag(false); - } + //if (EOGame.Instance.Hud.IsInventoryDragging()) + //{ + // shouldClickDrag = false; + // SuppressParentClickDrag(true); + //} + //else + //{ + // shouldClickDrag = true; + // SuppressParentClickDrag(false); + //} //do the hiding logic for both sides List scrollBars = new List { m_leftScroll, m_rightScroll }; diff --git a/EndlessClient/HUD/Controls/HUD.cs b/EndlessClient/HUD/Controls/HUD.cs index 26cd2a536..131d04c84 100644 --- a/EndlessClient/HUD/Controls/HUD.cs +++ b/EndlessClient/HUD/Controls/HUD.cs @@ -26,7 +26,6 @@ public class HUD : DrawableGameComponent private const int HUD_CONTROL_DRAW_ORDER = 101; private readonly OldChatRenderer chatRenderer; - private OldEOInventory inventory; private readonly OldEOPartyPanel m_party; private OldActiveSpells activeSpells; @@ -95,7 +94,6 @@ public override void Initialize() //the draw orders are adjusted for child items in the constructor. //calling SetParent will break this. - //inventory = new OldEOInventory(pnlInventory, m_packetAPI); //activeSpells = new OldActiveSpells(pnlActiveSpells, m_packetAPI); activeSpells.Initialize(); @@ -141,33 +139,8 @@ public void SetStatusLabel(EOResourceID type, string detail) //SetStatusLabelText(string.Format("[ {0} ] {1}", typeText, detail)); } - public bool UpdateInventory(InventoryItem item) - { - if (item.Amount <= 0) - inventory.RemoveItem(item.ItemID); - else - return inventory.UpdateItem(item); - return true; - } - public bool IsInventoryDragging() - { - return !inventory.NoItemsDragging(); - } - public bool InventoryFits(short id) - { - return inventory.ItemFits(id); - } - public bool ItemsFit(List newItems, List oldItems = null) - { - return inventory.ItemsFit(newItems, oldItems); - } - public void DisableEffectPotionUse() { inventory.DisableEffectPotions(); } - public void EnableEffectPotionUse() { inventory.EnableEffectPotions(); } - public void RefreshStats() { - if(inventory != null) - inventory.UpdateWeightLabel(); if (activeSpells != null) activeSpells.RefreshTotalSkillPoints(); } @@ -194,7 +167,6 @@ protected override void Dispose(bool disposing) { m_packetAPI.Dispose(); - inventory.Dispose(); chatRenderer.Dispose(); m_expInfo.Close(); diff --git a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs index 3d9f3e88c..2d2aa416e 100644 --- a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs +++ b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs @@ -42,6 +42,6 @@ public interface IInventorySpaceValidator bool ItemFits(ItemSize itemSize); - // need "ItemsFit" method for trading + // todo: need "ItemsFit" method for trading } } diff --git a/EndlessClient/HUD/Inventory/OldEOInventoryItem.cs b/EndlessClient/HUD/Inventory/OldEOInventoryItem.cs deleted file mode 100644 index 3368771a8..000000000 --- a/EndlessClient/HUD/Inventory/OldEOInventoryItem.cs +++ /dev/null @@ -1,590 +0,0 @@ -using System; -using System.Linq; -using System.Threading; -using EndlessClient.Dialogs; -using EndlessClient.Dialogs.Old; -using EndlessClient.HUD.Panels.Old; -using EndlessClient.Old; -using EOLib; -using EOLib.Domain.Character; -using EOLib.Graphics; -using EOLib.IO; -using EOLib.IO.Extensions; -using EOLib.IO.Pub; -using EOLib.Localization; -using EOLib.Net.API; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework.Input; -using XNAControls.Old; - -namespace EndlessClient.HUD.Inventory -{ - //Name conflict: InventoryItem already exists. - //Keeping the EO prefix on this one since naming is hard - public class OldEOInventoryItem : XNAControl - { - private readonly EIFRecord m_itemData; - public EIFRecord ItemData => m_itemData; - - private InventoryItem m_inventory; - public InventoryItem Inventory { get { return m_inventory; } set { m_inventory = value; } } - - public int Slot { get; private set; } - - private readonly Texture2D m_itemgfx, m_highlightBG; - private XNALabel m_nameLabel; - - private bool m_beingDragged; - private int m_alpha = 255; - private int m_preDragDrawOrder; - private XNAControl m_preDragParent; - private int m_oldOffX, m_oldOffY; - public bool Dragging => m_beingDragged; - - private int m_recentClickCount; - private readonly Timer m_recentClickTimer; - - private readonly PacketAPI m_api; - private static bool safetyCommentHasBeenShown; - - public OldEOInventoryItem(PacketAPI api, int slot, EIFRecord itemData, InventoryItem itemInventoryInfo, OldEOInventory inventory) - : base(null, null, inventory) - { - m_api = api; - m_itemData = itemData; - m_inventory = itemInventoryInfo; - Slot = slot; - - UpdateItemLocation(Slot); - - m_itemgfx = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.Items, 2 * itemData.Graphic, true); - - m_highlightBG = new Texture2D(Game.GraphicsDevice, DrawArea.Width - 3, DrawArea.Height - 3); - Color[] highlight = new Color[(drawArea.Width - 3) * (drawArea.Height - 3)]; - for (int i = 0; i < highlight.Length; ++i) { highlight[i] = Color.FromNonPremultiplied(200, 200, 200, 60); } - m_highlightBG.SetData(highlight); - - _initItemLabel(); - - m_recentClickTimer = new Timer( - _state => { if (m_recentClickCount > 0) Interlocked.Decrement(ref m_recentClickCount); }, null, 0, 1000); - } - - public override void Update(GameTime gameTime) - { - if (!Game.IsActive || !Enabled) return; - - //check for drag-drop here - MouseState currentState = Mouse.GetState(); - - if (!m_beingDragged && MouseOverPreviously && MouseOver && PreviousMouseState.LeftButton == ButtonState.Pressed && currentState.LeftButton == ButtonState.Pressed) - { - //Conditions for starting are the mouse is over, the button is pressed, and no other items are being dragged - if (((OldEOInventory)parent).NoItemsDragging()) - { - //start the drag operation and hide the item label - m_beingDragged = true; - m_nameLabel.Visible = false; - m_preDragDrawOrder = DrawOrder; - m_preDragParent = parent; - - //make sure the offsets are maintained! - //required to enable dragging past bounds of the inventory panel - m_oldOffX = xOff; - m_oldOffY = yOff; - SetParent(null); - - m_alpha = 128; - DrawOrder = 200; //arbitrarily large constant so drawn on top while dragging - } - } - - if (m_beingDragged && PreviousMouseState.LeftButton == ButtonState.Pressed && - currentState.LeftButton == ButtonState.Pressed) - { - //dragging has started. continue dragging until mouse is released, update position based on mouse location - DrawLocation = new Vector2(currentState.X - (DrawArea.Width / 2), currentState.Y - (DrawArea.Height / 2)); - } - else if (m_beingDragged && PreviousMouseState.LeftButton == ButtonState.Pressed && - currentState.LeftButton == ButtonState.Released) - { - //need to check for: drop on map (drop action) - // drop on button junk/drop - // drop on grid (inventory move action) - // drop on [x] dialog ([x] add action) - - m_alpha = 255; - SetParent(m_preDragParent); - - if (((OldEOInventory)parent).IsOverDrop() || (OldWorld.Instance.ActiveMapRenderer.MouseOver - //&& ChestDialog.Instance == null && EOPaperdollDialog.Instance == null && LockerDialog.Instance == null - && BankAccountDialog.Instance == null && TradeDialog.Instance == null)) - { - Point loc = OldWorld.Instance.ActiveMapRenderer.MouseOver ? OldWorld.Instance.ActiveMapRenderer.GridCoords : - new Point(OldWorld.Instance.MainPlayer.ActiveCharacter.X, OldWorld.Instance.MainPlayer.ActiveCharacter.Y); - - //in range if maximum coordinate difference is <= 2 away - bool inRange = Math.Abs(Math.Max(OldWorld.Instance.MainPlayer.ActiveCharacter.X - loc.X, OldWorld.Instance.MainPlayer.ActiveCharacter.Y - loc.Y)) <= 2; - - if (m_itemData.Special == ItemSpecial.Lore) - { - EOMessageBox.Show(DialogResourceID.ITEM_IS_LORE_ITEM, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - } - else if (OldWorld.Instance.JailMap == OldWorld.Instance.MainPlayer.ActiveCharacter.CurrentMap) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.JAIL_WARNING_CANNOT_DROP_ITEMS), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - } - else if (m_inventory.Amount > 1 && inRange) - { - ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.DropItems, - m_inventory.Amount); - dlg.DialogClosing += (sender, args) => - { - if (args.Result == XNADialogResult.OK) - { - //note: not sure of the actual limit. 10000 is arbitrary here - if (dlg.SelectedAmount > 10000 && m_inventory.ItemID == 1 && !safetyCommentHasBeenShown) - EOMessageBox.Show(DialogResourceID.DROP_MANY_GOLD_ON_GROUND, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader, - (o, e) => { safetyCommentHasBeenShown = true; }); - else if (!m_api.DropItem(m_inventory.ItemID, dlg.SelectedAmount, (byte)loc.X, (byte)loc.Y)) - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } - }; - } - else if (inRange) - { - if (!m_api.DropItem(m_inventory.ItemID, 1, (byte)loc.X, (byte)loc.Y)) - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } - else /*if (!inRange)*/ - { - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_ITEM_DROP_OUT_OF_RANGE); - } - } - else if (((OldEOInventory)parent).IsOverJunk()) - { - //if (m_inventory.Amount > 1) - //{ - // ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.JunkItems, - // m_inventory.Amount, EOResourceID.DIALOG_TRANSFER_JUNK); - // dlg.DialogClosing += (sender, args) => - // { - // if (args.Result == XNADialogResult.OK && !m_api.JunkItem(m_inventory.ItemID, dlg.SelectedAmount)) - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - // }; - //} - //else if (!m_api.JunkItem(m_inventory.ItemID, 1)) - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } - else if (ChestDialog.Instance != null && ChestDialog.Instance.MouseOver && ChestDialog.Instance.MouseOverPreviously) - { - if (m_itemData.Special == ItemSpecial.Lore) - { - EOMessageBox.Show(DialogResourceID.ITEM_IS_LORE_ITEM, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - } - else if (m_inventory.Amount > 1) - { - ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.DropItems, m_inventory.Amount); - dlg.DialogClosing += (sender, args) => - { - if (args.Result == XNADialogResult.OK && - !m_api.ChestAddItem(ChestDialog.Instance.CurrentChestX, ChestDialog.Instance.CurrentChestY, - m_inventory.ItemID, dlg.SelectedAmount)) - EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - }; - } - else - { - if (!m_api.ChestAddItem(ChestDialog.Instance.CurrentChestX, ChestDialog.Instance.CurrentChestY, m_inventory.ItemID, 1)) - 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; - byte y = LockerDialog.Instance.Y; - if (m_inventory.ItemID == 1) - { - EOMessageBox.Show(DialogResourceID.LOCKER_DEPOSIT_GOLD_ERROR, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - } - else if (m_inventory.Amount > 1) - { - ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.ShopTransfer, m_inventory.Amount, EOResourceID.DIALOG_TRANSFER_TRANSFER); - dlg.DialogClosing += (sender, args) => - { - if (args.Result == XNADialogResult.OK) - { - if (LockerDialog.Instance.GetNewItemAmount(m_inventory.ItemID, dlg.SelectedAmount) > Constants.LockerMaxSingleItemAmount) - EOMessageBox.Show(DialogResourceID.LOCKER_FULL_SINGLE_ITEM_MAX, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - else if (!m_api.LockerAddItem(x, y, m_inventory.ItemID, dlg.SelectedAmount)) - EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - } - }; - } - else - { - if (LockerDialog.Instance.GetNewItemAmount(m_inventory.ItemID, 1) > Constants.LockerMaxSingleItemAmount) - EOMessageBox.Show(DialogResourceID.LOCKER_FULL_SINGLE_ITEM_MAX, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - else if (!m_api.LockerAddItem(x, y, m_inventory.ItemID, 1)) - EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - } - } - else if (BankAccountDialog.Instance != null && BankAccountDialog.Instance.MouseOver && BankAccountDialog.Instance.MouseOverPreviously && m_inventory.ItemID == 1) - { - if (m_inventory.Amount == 0) - { - EOMessageBox.Show(DialogResourceID.BANK_ACCOUNT_UNABLE_TO_DEPOSIT, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - } - else if (m_inventory.Amount > 1) - { - ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.BankTransfer, - m_inventory.Amount, EOResourceID.DIALOG_TRANSFER_DEPOSIT); - dlg.DialogClosing += (o, e) => - { - if (e.Result == XNADialogResult.Cancel) - return; - - if (!m_api.BankDeposit(dlg.SelectedAmount)) - EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - }; - } - else - { - if (!m_api.BankDeposit(1)) - EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - } - } - else if (TradeDialog.Instance != null && TradeDialog.Instance.MouseOver && TradeDialog.Instance.MouseOverPreviously - && !TradeDialog.Instance.MainPlayerAgrees) - { - if (m_itemData.Special == ItemSpecial.Lore) - { - EOMessageBox.Show(DialogResourceID.ITEM_IS_LORE_ITEM); - } - else if (m_inventory.Amount > 1) - { - ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.TradeItems, - m_inventory.Amount, EOResourceID.DIALOG_TRANSFER_OFFER); - dlg.DialogClosing += (o, e) => - { - if (e.Result != XNADialogResult.OK) return; - - if (!m_api.TradeAddItem(m_inventory.ItemID, dlg.SelectedAmount)) - { - TradeDialog.Instance.Close(XNADialogResult.NO_BUTTON_PRESSED); - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } - }; - } - else if (!m_api.TradeAddItem(m_inventory.ItemID, 1)) - { - TradeDialog.Instance.Close(XNADialogResult.NO_BUTTON_PRESSED); - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } - } - - //update the location - if it isn't on the grid, the bounds check will set it back to where it used to be originally - //Item amount will be updated or item will be removed in packet response to the drop operation - UpdateItemLocation(ItemCurrentSlot()); - - //mouse has been released. finish dragging. - m_beingDragged = false; - m_nameLabel.Visible = true; - DrawOrder = m_preDragDrawOrder; - } - - if (!m_beingDragged && PreviousMouseState.LeftButton == ButtonState.Pressed && - currentState.LeftButton == ButtonState.Released && MouseOver && MouseOverPreviously) - { - Interlocked.Increment(ref m_recentClickCount); - if (m_recentClickCount == 2) - { - _handleDoubleClick(); - } - } - - if (!MouseOverPreviously && MouseOver && !m_beingDragged) - { - m_nameLabel.Visible = true; - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ITEM, m_nameLabel.Text); - } - else if (!MouseOver && !m_beingDragged && m_nameLabel != null && m_nameLabel.Visible) - { - m_nameLabel.Visible = false; - } - - base.Update(gameTime); //sets mouseoverpreviously = mouseover, among other things - } - - public override void Draw(GameTime gameTime) - { - if (!Visible) return; - - SpriteBatch.Begin(); - if (MouseOver) - { - int currentSlot = ItemCurrentSlot(); - Vector2 drawLoc = m_beingDragged - ? new Vector2(m_oldOffX + 13 + 26 * (currentSlot % OldEOInventory.INVENTORY_ROW_LENGTH), - m_oldOffY + 9 + 26 * (currentSlot / OldEOInventory.INVENTORY_ROW_LENGTH)) //recalculate the top-left point for the highlight based on the current drag position - : new Vector2(DrawAreaWithOffset.X, DrawAreaWithOffset.Y); - - if (OldEOInventory.GRID_AREA.Contains(DrawAreaWithOffset)) - SpriteBatch.Draw(m_highlightBG, drawLoc, Color.White); - } - if (m_itemgfx != null) - SpriteBatch.Draw(m_itemgfx, new Vector2(DrawAreaWithOffset.X, DrawAreaWithOffset.Y), Color.FromNonPremultiplied(255, 255, 255, m_alpha)); - SpriteBatch.End(); - base.Draw(gameTime); - } - - private void UpdateItemLocation(int newSlot) - { - if (Slot != newSlot && ((OldEOInventory)parent).MoveItem(this, newSlot)) Slot = newSlot; - - //top-left grid slot in the inventory is 115, 339 - //parent top-left is 103, 330 - //grid size is 26*26 (w/o borders 23*23) - int width, height; - OldEOInventory._getItemSizeDeltas(m_itemData.Size, out width, out height); - DrawLocation = new Vector2(13 + 26 * (Slot % OldEOInventory.INVENTORY_ROW_LENGTH), 9 + 26 * (Slot / OldEOInventory.INVENTORY_ROW_LENGTH)); - _setSize(width * 26, height * 26); - - if (m_nameLabel != null) //fix the position of the name label too if we aren't creating the inventoryitem - { - m_nameLabel.DrawLocation = new Vector2(DrawArea.Width, 0); - if (!OldEOInventory.GRID_AREA.Contains(m_nameLabel.DrawAreaWithOffset)) - m_nameLabel.DrawLocation = new Vector2(-m_nameLabel.DrawArea.Width, 0); //show on the right if it isn't in bounds! - m_nameLabel.ResizeBasedOnText(16, 9); - } - } - - private int ItemCurrentSlot() - { - if (!m_beingDragged) return Slot; - - //convert the current draw area to a slot number (for when the item is dragged) - return (int)((DrawLocation.X - m_oldOffX - 13) / 26) + OldEOInventory.INVENTORY_ROW_LENGTH * (int)((DrawLocation.Y - m_oldOffY - 9) / 26); - } - - public void UpdateItemLabel() - { - m_nameLabel.Text = GetNameString(m_inventory.ItemID, m_inventory.Amount); - m_nameLabel.ResizeBasedOnText(16, 9); - } - - protected override void Dispose(bool disposing) - { - if (m_recentClickTimer != null) m_recentClickTimer.Dispose(); - if (m_nameLabel != null) m_nameLabel.Dispose(); - if (m_highlightBG != null) m_highlightBG.Dispose(); - - base.Dispose(disposing); - } - - private void _initItemLabel() - { - if (m_nameLabel != null) m_nameLabel.Dispose(); - - m_nameLabel = new XNALabel(new Rectangle(DrawArea.Width, 0, 150, 23), Constants.FontSize08) - { - Visible = false, - AutoSize = false, - TextAlign = LabelAlignment.MiddleCenter, - ForeColor = Color.FromNonPremultiplied(200, 200, 200, 255), - BackColor = Color.FromNonPremultiplied(30, 30, 30, 160) - }; - - UpdateItemLabel(); - - m_nameLabel.ForeColor = GetItemTextColor((short)m_itemData.ID); - - m_nameLabel.SetParent(this); - m_nameLabel.ResizeBasedOnText(16, 9); - } - - private void _handleDoubleClick() - { - OldCharacter c = OldWorld.Instance.MainPlayer.ActiveCharacter; - - //bool useItem = false; - switch (m_itemData.Type) - { - //equippable items - 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: - byte subLoc = 0; - if (m_itemData.Type == ItemType.Armlet || m_itemData.Type == ItemType.Ring || m_itemData.Type == ItemType.Bracer) - { - if (c.PaperDoll[(int)m_itemData.GetEquipLocation()] == 0) - subLoc = 0; - else if (c.PaperDoll[(int)m_itemData.GetEquipLocation() + 1] == 0) - subLoc = 1; - else - { - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, - EOResourceID.STATUS_LABEL_ITEM_EQUIP_TYPE_ALREADY_EQUIPPED); - break; - } - } - else if (m_itemData.Type == ItemType.Armor && - m_itemData.Gender != c.RenderData.gender) - { - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, - EOResourceID.STATUS_LABEL_ITEM_EQUIP_DOES_NOT_FIT_GENDER); - break; - } - - //check stat requirements - int[] reqs = new int[6]; - string[] reqNames = { "STR", "INT", "WIS", "AGI", "CON", "CHA" }; - if ((reqs[0] = m_itemData.StrReq) > c.Stats.Str || (reqs[1] = m_itemData.IntReq) > c.Stats.Int - || (reqs[2] = m_itemData.WisReq) > c.Stats.Wis || (reqs[3] = m_itemData.AgiReq) > c.Stats.Agi - || (reqs[4] = m_itemData.ConReq) > c.Stats.Con || (reqs[5] = m_itemData.ChaReq) > c.Stats.Cha) - { - int reqIndex = reqs.ToList().FindIndex(x => x > 0); - - ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, - EOResourceID.STATUS_LABEL_ITEM_EQUIP_THIS_ITEM_REQUIRES, - $" {reqs[reqIndex]} {reqNames[reqIndex]}"); - break; - } - //check class requirement - if (m_itemData.ClassReq > 0 && m_itemData.ClassReq != c.Class) - { - ((EOGame) Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, - EOResourceID.STATUS_LABEL_ITEM_EQUIP_CAN_ONLY_BE_USED_BY, - OldWorld.Instance.ECF[m_itemData.ClassReq].Name); - break; - } - - if (c.EquipItem(m_itemData.Type, (short)m_itemData.ID, - (short)m_itemData.DollGraphic)) - { - //if (!m_api.EquipItem((short)m_itemData.ID, subLoc)) - // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - } - else - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, - EOResourceID.STATUS_LABEL_ITEM_EQUIP_TYPE_ALREADY_EQUIPPED); - - break; - //usable items - case ItemType.Teleport: - if (!OldWorld.Instance.ActiveMapRenderer.MapRef.Properties.CanScroll) - { - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_NOTHING_HAPPENED); - break; - } - if (m_itemData.ScrollMap == OldWorld.Instance.MainPlayer.ActiveCharacter.CurrentMap && - m_itemData.ScrollX == OldWorld.Instance.MainPlayer.ActiveCharacter.X && - m_itemData.ScrollY == OldWorld.Instance.MainPlayer.ActiveCharacter.Y) - break; //already there - no need to scroll! - //useItem = true; - break; - case ItemType.Heal: - case ItemType.HairDye: - case ItemType.Beer: - //useItem = true; - break; - case ItemType.CureCurse: - //note: don't actually set the useItem bool here. Call API.UseItem if the dialog result is OK. - if (c.PaperDoll.Select(id => OldWorld.Instance.EIF[id]) - .Any(rec => rec.Special == ItemSpecial.Cursed)) - { - EOMessageBox.Show(DialogResourceID.ITEM_CURSE_REMOVE_PROMPT, EODialogButtons.OkCancel, EOMessageBoxStyle.SmallDialogSmallHeader, - (o, e) => - { - //if (e.Result == XNADialogResult.OK && !m_api.UseItem((short)m_itemData.ID)) - //{ - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - //} - }); - } - break; - case ItemType.EXPReward: - //useItem = true; - break; - case ItemType.EffectPotion: - //useItem = true; - break; - //Not implemented server-side - //case ItemType.SkillReward: - // break; - //case ItemType.StatReward: - // break; - } - - //if (useItem && !m_api.UseItem((short)m_itemData.ID)) - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - - m_recentClickCount = 0; - } - - public static Color GetItemTextColor(short id) //also used in map renderer for mapitems - { - var data = OldWorld.Instance.EIF[id]; - switch (data.Special) - { - case ItemSpecial.Lore: - case ItemSpecial.Unique: - return Color.FromNonPremultiplied(0xff, 0xf0, 0xa5, 0xff); - case ItemSpecial.Rare: - return Color.FromNonPremultiplied(0xf5, 0xc8, 0x9c, 0xff); - } - - return Color.White; - } - - public static string GetNameString(short id, int amount) - { - var data = OldWorld.Instance.EIF[id]; - switch (data.ID) - { - case 1: - return $"{amount} {data.Name}"; - default: - if (amount == 1) - return data.Name; - if (amount > 1) - return $"{data.Name} x{amount}"; - throw new Exception("There shouldn't be an item in the inventory with amount zero"); - } - } - } -} diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index 1c196b962..ddd4c098d 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -492,7 +492,203 @@ private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCo } } + if (e.ContinueDrag || e.RestoreOriginalSlot) + return; + // todo: handle drag to things (dialog, map, buttons) + #region Unimplemented drag action + /* + if (((OldEOInventory)parent).IsOverDrop() || (OldWorld.Instance.ActiveMapRenderer.MouseOver + //&& ChestDialog.Instance == null && EOPaperdollDialog.Instance == null && LockerDialog.Instance == null + && BankAccountDialog.Instance == null && TradeDialog.Instance == null)) + { + Point loc = OldWorld.Instance.ActiveMapRenderer.MouseOver ? OldWorld.Instance.ActiveMapRenderer.GridCoords : + new Point(OldWorld.Instance.MainPlayer.ActiveCharacter.X, OldWorld.Instance.MainPlayer.ActiveCharacter.Y); + + //in range if maximum coordinate difference is <= 2 away + bool inRange = Math.Abs(Math.Max(OldWorld.Instance.MainPlayer.ActiveCharacter.X - loc.X, OldWorld.Instance.MainPlayer.ActiveCharacter.Y - loc.Y)) <= 2; + + if (m_itemData.Special == ItemSpecial.Lore) + { + EOMessageBox.Show(DialogResourceID.ITEM_IS_LORE_ITEM, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + } + else if (OldWorld.Instance.JailMap == OldWorld.Instance.MainPlayer.ActiveCharacter.CurrentMap) + { + EOMessageBox.Show(OldWorld.GetString(EOResourceID.JAIL_WARNING_CANNOT_DROP_ITEMS), + OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + } + else if (m_inventory.Amount > 1 && inRange) + { + ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.DropItems, + m_inventory.Amount); + dlg.DialogClosing += (sender, args) => + { + if (args.Result == XNADialogResult.OK) + { + //note: not sure of the actual limit. 10000 is arbitrary here + if (dlg.SelectedAmount > 10000 && m_inventory.ItemID == 1 && !safetyCommentHasBeenShown) + EOMessageBox.Show(DialogResourceID.DROP_MANY_GOLD_ON_GROUND, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader, + (o, e) => { safetyCommentHasBeenShown = true; }); + else if (!m_api.DropItem(m_inventory.ItemID, dlg.SelectedAmount, (byte)loc.X, (byte)loc.Y)) + ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + } + }; + } + else if (inRange) + { + if (!m_api.DropItem(m_inventory.ItemID, 1, (byte)loc.X, (byte)loc.Y)) + ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + } + else //if (!inRange) + { + EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_ITEM_DROP_OUT_OF_RANGE); + } + } + else if (((OldEOInventory)parent).IsOverJunk()) + { + if (m_inventory.Amount > 1) + { + ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.JunkItems, + m_inventory.Amount, EOResourceID.DIALOG_TRANSFER_JUNK); + dlg.DialogClosing += (sender, args) => + { + if (args.Result == XNADialogResult.OK && !m_api.JunkItem(m_inventory.ItemID, dlg.SelectedAmount)) + ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + }; + } + else if (!m_api.JunkItem(m_inventory.ItemID, 1)) + ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + } + else if (ChestDialog.Instance != null && ChestDialog.Instance.MouseOver && ChestDialog.Instance.MouseOverPreviously) + { + if (m_itemData.Special == ItemSpecial.Lore) + { + EOMessageBox.Show(DialogResourceID.ITEM_IS_LORE_ITEM, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + } + else if (m_inventory.Amount > 1) + { + ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.DropItems, m_inventory.Amount); + dlg.DialogClosing += (sender, args) => + { + if (args.Result == XNADialogResult.OK && + !m_api.ChestAddItem(ChestDialog.Instance.CurrentChestX, ChestDialog.Instance.CurrentChestY, + m_inventory.ItemID, dlg.SelectedAmount)) + EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + }; + } + else + { + if (!m_api.ChestAddItem(ChestDialog.Instance.CurrentChestX, ChestDialog.Instance.CurrentChestY, m_inventory.ItemID, 1)) + 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; + byte y = LockerDialog.Instance.Y; + if (m_inventory.ItemID == 1) + { + EOMessageBox.Show(DialogResourceID.LOCKER_DEPOSIT_GOLD_ERROR, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + } + else if (m_inventory.Amount > 1) + { + ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.ShopTransfer, m_inventory.Amount, EOResourceID.DIALOG_TRANSFER_TRANSFER); + dlg.DialogClosing += (sender, args) => + { + if (args.Result == XNADialogResult.OK) + { + if (LockerDialog.Instance.GetNewItemAmount(m_inventory.ItemID, dlg.SelectedAmount) > Constants.LockerMaxSingleItemAmount) + EOMessageBox.Show(DialogResourceID.LOCKER_FULL_SINGLE_ITEM_MAX, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + else if (!m_api.LockerAddItem(x, y, m_inventory.ItemID, dlg.SelectedAmount)) + EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + } + }; + } + else + { + if (LockerDialog.Instance.GetNewItemAmount(m_inventory.ItemID, 1) > Constants.LockerMaxSingleItemAmount) + EOMessageBox.Show(DialogResourceID.LOCKER_FULL_SINGLE_ITEM_MAX, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + else if (!m_api.LockerAddItem(x, y, m_inventory.ItemID, 1)) + EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + } + } + else if (BankAccountDialog.Instance != null && BankAccountDialog.Instance.MouseOver && BankAccountDialog.Instance.MouseOverPreviously && m_inventory.ItemID == 1) + { + if (m_inventory.Amount == 0) + { + EOMessageBox.Show(DialogResourceID.BANK_ACCOUNT_UNABLE_TO_DEPOSIT, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + } + else if (m_inventory.Amount > 1) + { + ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.BankTransfer, + m_inventory.Amount, EOResourceID.DIALOG_TRANSFER_DEPOSIT); + dlg.DialogClosing += (o, e) => + { + if (e.Result == XNADialogResult.Cancel) + return; + + if (!m_api.BankDeposit(dlg.SelectedAmount)) + EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + }; + } + else + { + if (!m_api.BankDeposit(1)) + EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + } + } + else if (TradeDialog.Instance != null && TradeDialog.Instance.MouseOver && TradeDialog.Instance.MouseOverPreviously + && !TradeDialog.Instance.MainPlayerAgrees) + { + if (m_itemData.Special == ItemSpecial.Lore) + { + EOMessageBox.Show(DialogResourceID.ITEM_IS_LORE_ITEM); + } + else if (m_inventory.Amount > 1) + { + ItemTransferDialog dlg = new ItemTransferDialog(m_itemData.Name, ItemTransferDialog.TransferType.TradeItems, + m_inventory.Amount, EOResourceID.DIALOG_TRANSFER_OFFER); + dlg.DialogClosing += (o, e) => + { + if (e.Result != XNADialogResult.OK) return; + + if (!m_api.TradeAddItem(m_inventory.ItemID, dlg.SelectedAmount)) + { + TradeDialog.Instance.Close(XNADialogResult.NO_BUTTON_PRESSED); + ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + } + }; + } + else if (!m_api.TradeAddItem(m_inventory.ItemID, 1)) + { + TradeDialog.Instance.Close(XNADialogResult.NO_BUTTON_PRESSED); + ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + } + }*/ + #endregion } private static IEnumerable GetOverlappingTakenSlots(int newSlot, ItemSize size, IEnumerable<(int Slot, ItemSize Size)> items) diff --git a/EndlessClient/HUD/Panels/Old/OldInventoryPanel.cs b/EndlessClient/HUD/Panels/Old/OldInventoryPanel.cs deleted file mode 100644 index 157fef214..000000000 --- a/EndlessClient/HUD/Panels/Old/OldInventoryPanel.cs +++ /dev/null @@ -1,463 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using EndlessClient.Dialogs; -using EndlessClient.HUD.Inventory; -using EndlessClient.Old; -using EOLib; -using EOLib.Domain.Character; -using EOLib.Graphics; -using EOLib.IO; -using EOLib.IO.Pub; -using EOLib.Localization; -using EOLib.Net.API; -using Microsoft.Win32; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using XNAControls.Old; - -namespace EndlessClient.HUD.Panels.Old -{ - public class OldEOInventory : XNAControl - { - /// - /// number of slots in an inventory row - /// - public const int INVENTORY_ROW_LENGTH = 14; - - /// - /// Area of the grid portion of the inventory (uses absolute coordinates) - /// - public static Rectangle GRID_AREA = new Rectangle(110, 334, 377, 116); - - private readonly bool[,] m_filledSlots = new bool[4, INVENTORY_ROW_LENGTH]; //4 rows, 14 columns = 56 total in grid - private readonly RegistryKey m_inventoryKey; - private readonly List m_childItems = new List(); - - private readonly XNALabel m_lblWeight; - private readonly XNAButton m_btnDrop, m_btnJunk, m_btnPaperdoll; - - private readonly PacketAPI m_api; - - public OldEOInventory(XNAPanel parent, PacketAPI api) - : base(null, null, parent) - { - m_api = api; - - //load info from registry - Dictionary localItemSlotMap = new Dictionary(); - m_inventoryKey = _tryGetCharacterRegKey(); - if (m_inventoryKey != null) - { - const string itemFmt = "item{0}"; - for (int i = 0; i < INVENTORY_ROW_LENGTH * 4; ++i) - { - int id; - try - { - id = Convert.ToInt32(m_inventoryKey.GetValue(string.Format(itemFmt, i))); - } - catch { continue; } - localItemSlotMap.Add(i, id); - } - } - - //add the inventory items that were retrieved from the server - List localInv = OldWorld.Instance.MainPlayer.ActiveCharacter.Inventory; - if (localInv.Find(_item => _item.ItemID == 1).ItemID != 1) - localInv.Insert(0, new InventoryItem(amount: 0, itemID: 1)); //add 0 gold if there isn't any gold - - bool dialogShown = false; - foreach (var item in localInv) - { - var rec = OldWorld.Instance.EIF[item.ItemID]; - int slot = localItemSlotMap.ContainsValue(item.ItemID) - ? localItemSlotMap.First(_pair => _pair.Value == item.ItemID).Key - : _getNextOpenSlot(rec.Size); - - List> points; - if (!_fitsInSlot(slot, rec.Size, out points)) - slot = _getNextOpenSlot(rec.Size); - - if (!_addItemToSlot(slot, rec, item.Amount) && !dialogShown) - { - dialogShown = true; - EOMessageBox.Show("Something doesn't fit in the inventory. Rearrange items or get rid of them.", "Warning", EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - } - } - - //coordinates for parent of EOInventory: 102, 330 (pnlInventory in InGameHud) - //extra in photoshop right now: 8, 31 - - //current weight label (member variable, needs to have text updated when item amounts change) - m_lblWeight = new XNALabel(new Rectangle(385, 37, 88, 18), Constants.FontSize08pt5) - { - ForeColor = ColorConstants.LightGrayText, - TextAlign = LabelAlignment.MiddleCenter, - Visible = true, - AutoSize = false - }; - m_lblWeight.SetParent(this); - UpdateWeightLabel(); - - Texture2D thatWeirdSheet = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 27); //oh my gawd the offsets on this bish - - //(local variables, added to child controls) - //'paperdoll' button - m_btnPaperdoll = new XNAButton(thatWeirdSheet, new Vector2(385, 9), /*new Rectangle(39, 385, 88, 19)*/null, new Rectangle(126, 385, 88, 19)); - m_btnPaperdoll.SetParent(this); - //m_btnPaperdoll.OnClick += (s, e) => m_api.RequestPaperdoll((short)OldWorld.Instance.MainPlayer.ActiveCharacter.ID); - //'drop' button - //491, 398 -> 389, 68 - //0,15,38,37 - //0,52,38,37 - m_btnDrop = new XNAButton(thatWeirdSheet, new Vector2(389, 68), new Rectangle(0, 15, 38, 37), new Rectangle(0, 52, 38, 37)); - m_btnDrop.SetParent(this); - OldWorld.IgnoreDialogs(m_btnDrop); - //'junk' button - 4 + 38 on the x away from drop - m_btnJunk = new XNAButton(thatWeirdSheet, new Vector2(431, 68), new Rectangle(0, 89, 38, 37), new Rectangle(0, 126, 38, 37)); - m_btnJunk.SetParent(this); - OldWorld.IgnoreDialogs(m_btnJunk); - } - - //----------------------------------------------------- - // Overrides / Control Interface - //----------------------------------------------------- - public override void Update(GameTime gameTime) - { - if (!Visible || !Game.IsActive) return; - - if (IsOverDrop()) - { - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_BUTTON, EOResourceID.STATUS_LABEL_INVENTORY_DROP_BUTTON); - } - else if (IsOverJunk()) - { - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_BUTTON, EOResourceID.STATUS_LABEL_INVENTORY_JUNK_BUTTON); - } - else if (m_btnPaperdoll.MouseOver && !m_btnPaperdoll.MouseOverPreviously) - { - EOGame.Instance.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_BUTTON, EOResourceID.STATUS_LABEL_INVENTORY_SHOW_YOUR_PAPERDOLL); - } - - base.Update(gameTime); - } - - protected override void Dispose(bool disposing) - { - m_inventoryKey.Dispose(); - m_btnPaperdoll.Dispose(); - m_btnJunk.Dispose(); - m_btnDrop.Dispose(); - } - - private bool _addItemToSlot(int slot, EIFRecord item, int count = 1) - { - return _addItemToSlot(m_filledSlots, slot, item, count); - } - - private bool _addItemToSlot(bool[,] filledSlots, int slot, EIFRecord item, int count = 1) - { - //this is ADD item - don't allow adding items that have been added already - if (slot < 0 || m_childItems.Count(_item => _item.Slot == slot) > 0) return false; - - List> points; - if (!_fitsInSlot(filledSlots, slot, item.Size, out points)) return false; - points.ForEach(point => filledSlots[point.Item1, point.Item2] = true); //flag that the spaces are taken - - m_inventoryKey.SetValue($"item{slot}", item.ID, RegistryValueKind.String); //update the registry - m_childItems.Add(new OldEOInventoryItem(m_api, slot, item, new InventoryItem(amount: count, itemID: (short)item.ID), this)); //add the control wrapper for the item - m_childItems[m_childItems.Count - 1].DrawOrder = (int) ControlDrawLayer.DialogLayer - (2 + slot%INVENTORY_ROW_LENGTH); - return true; - } - - public bool ItemFits(short id) - { - //it will fit if the inventory already has it. - if (m_childItems.Find(_i => _i.ItemData.ID == id) != null) - return true; - - var rec = OldWorld.Instance.EIF[id]; - int nextSlot = _getNextOpenSlot(rec.Size); - List> dummy; - return _fitsInSlot(nextSlot, rec.Size, out dummy); - } - - /// - /// Checks if a list of Item IDs will fit in the inventory based on their item record sizes. Does not modify current inventory. - /// - /// List of Items to check - /// Optional list of items to remove from filled slots before checking new IDs (ie items that will be traded) - /// True if everything fits, false otherwise. - public bool ItemsFit(List newItems, List oldItems = null) - { - bool[,] tempFilledSlots = new bool[4, INVENTORY_ROW_LENGTH]; - for (int row = 0; row < 4; ++row) - { - for (int col = 0; col < INVENTORY_ROW_LENGTH; ++col) - { - tempFilledSlots[row, col] = m_filledSlots[row, col]; - } - } - - if(oldItems != null) - foreach (InventoryItem item in oldItems) - { - OldEOInventoryItem control = m_childItems.Find(_item => _item.ItemData.ID == item.ItemID); - if (control != null && control.Inventory.Amount - item.Amount <= 0) - _unmarkItemSlots(tempFilledSlots, _getTakenSlots(control.Slot, control.ItemData.Size)); - } - - foreach (InventoryItem item in newItems) - { - if (oldItems != null && oldItems.FindIndex(_itm => _itm.ItemID == item.ItemID) < 0) - { - if (item.ItemID == 1 || m_childItems.Find(_item => _item.ItemData.ID == item.ItemID) != null) - continue; //already in inventory: skip, since it isn't a new item - } - - var rec = OldWorld.Instance.EIF[item.ItemID]; - - int nextSlot = _getNextOpenSlot(tempFilledSlots, rec.Size); - List> points; - if (nextSlot < 0 || !_fitsInSlot(tempFilledSlots, nextSlot, rec.Size, out points)) - return false; - - foreach (var pt in points) - tempFilledSlots[pt.Item1, pt.Item2] = true; - } - return true; - } - - private void _unmarkItemSlots(bool[,] slots, List> points) - { - points.ForEach(_p => slots[_p.Item1, _p.Item2] = false); - } - - private void _removeItemFromSlot(int slot, int count = 1) - { - OldEOInventoryItem control = m_childItems.Find(_control => _control.Slot == slot); - if (control == null || slot < 0) return; - - int numLeft = control.Inventory.Amount - count; - - if (numLeft <= 0 && control.Inventory.ItemID != 1) - { - ItemSize sz = control.ItemData.Size; - _unmarkItemSlots(m_filledSlots, _getTakenSlots(control.Slot, sz)); - - m_inventoryKey.SetValue($"item{slot}", 0, RegistryValueKind.String); - m_childItems.Remove(control); - control.Visible = false; - control.Close(); - } - else - { - control.Inventory = new InventoryItem(amount: numLeft, itemID: control.Inventory.ItemID); - control.UpdateItemLabel(); - } - } - - public bool MoveItem(OldEOInventoryItem childItem, int newSlot) - { - if (childItem.Slot == newSlot) return true; // We did it, Reddit! - - List> oldPoints = _getTakenSlots(childItem.Slot, childItem.ItemData.Size); - List> points; - if (!_fitsInSlot(newSlot, childItem.ItemData.Size, out points, oldPoints)) return false; - - oldPoints.ForEach(_p => m_filledSlots[_p.Item1, _p.Item2] = false); - points.ForEach(_p => m_filledSlots[_p.Item1, _p.Item2] = true); - - m_inventoryKey.SetValue($"item{childItem.Slot}", 0, RegistryValueKind.String); - m_inventoryKey.SetValue($"item{newSlot}", childItem.ItemData.ID, RegistryValueKind.String); - - childItem.DrawOrder = (int)ControlDrawLayer.DialogLayer - (2 + childItem.Slot % INVENTORY_ROW_LENGTH); - - return true; - } - - private int _getNextOpenSlot(ItemSize size) - { - return _getNextOpenSlot(m_filledSlots, size); - } - - private int _getNextOpenSlot(bool[,] slots, ItemSize size) - { - int width, height; - _getItemSizeDeltas(size, out width, out height); - - //outer loops: iterating over every grid space (56 spaces total) - for (int row = 0; row < 4; ++row) - { - for (int col = 0; col < INVENTORY_ROW_LENGTH; ++col) - { - if (slots[row, col]) continue; - - if (!slots[row, col] && size == ItemSize.Size1x1) - return row*INVENTORY_ROW_LENGTH + col; - - //inner loops: iterating over grid spaces starting at (row, col) for the item size (width, height) - bool ok = true; - for (int y = row; y < row + height; ++y) - { - if (y >= 4) - { - ok = false; - continue; - } - for (int x = col; x < col + width; ++x) - if (x >= INVENTORY_ROW_LENGTH || slots[y, x]) ok = false; - } - - if (ok) return row*INVENTORY_ROW_LENGTH + col; - } - } - - return -1; - } - - public void UpdateWeightLabel(string text = "") - { - if (string.IsNullOrEmpty(text)) - m_lblWeight.Text = - $"{OldWorld.Instance.MainPlayer.ActiveCharacter.Weight} / {OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight}"; - else - m_lblWeight.Text = text; - } - - public bool NoItemsDragging() - { - return m_childItems.Count(invItem => invItem.Dragging) == 0; - } - - public bool UpdateItem(InventoryItem item) - { - OldEOInventoryItem ctrl; - if((ctrl = m_childItems.Find(_ctrl => _ctrl.ItemData.ID == item.ItemID)) != null) - { - ctrl.Inventory = item; - ctrl.UpdateItemLabel(); - } - else - { - var rec = OldWorld.Instance.EIF[item.ItemID]; - return _addItemToSlot(_getNextOpenSlot(rec.Size), rec, item.Amount); - } - - return true; - } - - public void RemoveItem(int id) - { - OldEOInventoryItem ctrl; - if ((ctrl = m_childItems.Find(_ctrl => _ctrl.ItemData.ID == id)) != null) - { - _removeItemFromSlot(ctrl.Slot, ctrl.Inventory.Amount); - } - } - - public bool IsOverDrop() - { - return m_btnDrop.MouseOver && m_btnDrop.MouseOverPreviously; - } - - public bool IsOverJunk() - { - return m_btnJunk.MouseOver && m_btnJunk.MouseOverPreviously; - } - - //----------------------------------------------------- - // Helper methods - //----------------------------------------------------- - private static RegistryKey _tryGetCharacterRegKey() - { - try - { - using (RegistryKey currentUser = Registry.CurrentUser) - { - return currentUser.CreateSubKey( - $"Software\\EndlessClient\\{OldWorld.Instance.MainPlayer.AccountName}\\{OldWorld.Instance.MainPlayer.ActiveCharacter.Name}\\inventory", - RegistryKeyPermissionCheck.ReadWriteSubTree); - } - } - catch (NullReferenceException) { } - return null; - } - - private static List> _getTakenSlots(int slot, ItemSize sz) - { - var ret = new List>(); - - int width, height; - _getItemSizeDeltas(sz, out width, out height); - int y = slot / INVENTORY_ROW_LENGTH, x = slot % INVENTORY_ROW_LENGTH; - for (int row = y; row < height + y; ++row) - { - for (int col = x; col < width + x; ++col) - { - ret.Add(new Tuple(row, col)); - } - } - - return ret; - } - - private bool _fitsInSlot(int slot, ItemSize sz, out List> points, List> itemPoints = null) - { - return _fitsInSlot(m_filledSlots, slot, sz, out points, itemPoints); - } - - private bool _fitsInSlot(bool[,] slots, int slot, ItemSize sz, out List> points, List> itemPoints = null) - { - points = new List>(); - - if (slot < 0 || slot >= 4*INVENTORY_ROW_LENGTH) return false; - - //check the 'filled slots' array to see if the item can go in 'slot' based on its size - int y = slot / INVENTORY_ROW_LENGTH, x = slot % INVENTORY_ROW_LENGTH; - if (y >= 4 || x >= INVENTORY_ROW_LENGTH) return false; - if (itemPoints == null && slots[y, x]) return false; - - points = _getTakenSlots(slot, sz); - if (points.Count(_t => _t.Item1 < 0 || _t.Item1 > 3 || _t.Item2 < 0 || _t.Item2 >= INVENTORY_ROW_LENGTH) > 0) - return false; //some of the coordinates are out of bounds of the maximum inventory length - - List> overLaps = points.FindAll(_pt => slots[_pt.Item1, _pt.Item2]); - if (overLaps.Count > 0 && (itemPoints == null || overLaps.Count(itemPoints.Contains) != overLaps.Count)) - return false; //more than one overlapping point, and the points in overLaps are not contained in itemPoints - - return true; - } - - //this is public because C# doesn't have a 'friend' keyword and I need it in EOInventoryItem - public static void _getItemSizeDeltas(ItemSize size, out int width, out int height) - { - //enum ItemSize: Size[width]x[height], - // where [width] is index 4 and [height] is index 6 (string of length 7) - string sizeStr = Enum.GetName(typeof(ItemSize), size); - if (sizeStr == null || sizeStr.Length != 7) - { - width = height = 0; - return; - } - - width = Convert.ToInt32(sizeStr.Substring(4, 1)); - height = Convert.ToInt32(sizeStr.Substring(6, 1)); - } - - public void EnableEffectPotions() - { - var effectPotions = m_childItems.Where(x => x.ItemData.Type == ItemType.EffectPotion && !x.Enabled); - foreach (var potion in effectPotions) - potion.Enabled = true; - } - - public void DisableEffectPotions() - { - var effectPotions = m_childItems.Where(x => x.ItemData.Type == ItemType.EffectPotion && x.Enabled); - foreach (var potion in effectPotions) - potion.Enabled = false; - } - } -} diff --git a/EndlessClient/Old/OldCharacter.cs b/EndlessClient/Old/OldCharacter.cs index e6cd59f00..9a6128887 100644 --- a/EndlessClient/Old/OldCharacter.cs +++ b/EndlessClient/Old/OldCharacter.cs @@ -430,92 +430,6 @@ public void DoneEmote() RenderData.SetEmoteFrame(-1); } - public void UpdateInventoryItem(short id, int characterAmount, bool add = false) - { - InventoryItem rec; - if ((rec = Inventory.Find(item => item.ItemID == id)).ItemID == id) - { - InventoryItem newRec = new InventoryItem(id, add ? characterAmount + rec.Amount : characterAmount); - if (!Inventory.Remove(rec)) - throw new Exception("Unable to remove from inventory!"); - if (newRec.Amount > 0) - { - Inventory.Add(newRec); - } - if (this == OldWorld.Instance.MainPlayer.ActiveCharacter) EOGame.Instance.Hud.UpdateInventory(newRec); - } - else //if unequipping an item that isn't in the inventory yet - { - InventoryItem newRec = new InventoryItem(amount: characterAmount, itemID: id); - Inventory.Add(newRec); - if (this == OldWorld.Instance.MainPlayer.ActiveCharacter) EOGame.Instance.Hud.UpdateInventory(newRec); - } - } - - public void UpdateInventoryItem(short id, int characterAmount, byte characterWeight, byte characterMaxWeight, bool addToExistingAmount = false) - { - InventoryItem rec; - if ((rec = Inventory.Find(item => item.ItemID == id)).ItemID == id) - { - InventoryItem newRec = new InventoryItem - (amount: addToExistingAmount ? characterAmount + rec.Amount : characterAmount, - itemID: id); - if (this == OldWorld.Instance.MainPlayer.ActiveCharacter) - { - //false when AddItem fails to find a good spot - if (!EOGame.Instance.Hud.UpdateInventory(newRec)) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.STATUS_LABEL_ITEM_PICKUP_NO_SPACE_LEFT), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - return; - } - } - - //if we can hold it, update local inventory and weight stats - if (!Inventory.Remove(rec)) - throw new Exception("Unable to remove from inventory!"); - if (newRec.Amount > 0) - { - Inventory.Add(newRec); - } - Weight = characterWeight; - MaxWeight = characterMaxWeight; - if (this == OldWorld.Instance.MainPlayer.ActiveCharacter) EOGame.Instance.Hud.RefreshStats(); - } - else - { - //for item_get/chest_get packets, the item may not be in the inventory yet - InventoryItem newRec = new InventoryItem(amount: characterAmount, itemID: id); - if (newRec.Amount <= 0) return; - - Inventory.Add(newRec); - if (this == OldWorld.Instance.MainPlayer.ActiveCharacter) - { - //false when AddItem fails to find a good spot - if (!EOGame.Instance.Hud.UpdateInventory(newRec)) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.STATUS_LABEL_ITEM_PICKUP_NO_SPACE_LEFT), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - return; - } - } - Weight = characterWeight; - MaxWeight = characterMaxWeight; - if (this == OldWorld.Instance.MainPlayer.ActiveCharacter) EOGame.Instance.Hud.RefreshStats(); - } - } - - public void SetDisplayItemsFromRenderData(CharRenderData newRenderData) - { - EquipItem(ItemType.Boots, (short)(OldWorld.Instance.EIF.SingleOrDefault(x => x.Type == ItemType.Boots && x.DollGraphic == newRenderData.boots) ?? new EIFRecord()).ID, newRenderData.boots, true); - EquipItem(ItemType.Armor, (short)(OldWorld.Instance.EIF.SingleOrDefault(x => x.Type == ItemType.Armor && x.DollGraphic == newRenderData.armor) ?? new EIFRecord()).ID, newRenderData.armor, true); - EquipItem(ItemType.Hat, (short)(OldWorld.Instance.EIF.SingleOrDefault(x => x.Type == ItemType.Hat && x.DollGraphic == newRenderData.hat) ?? new EIFRecord()).ID, newRenderData.hat, true); - EquipItem(ItemType.Shield, (short)(OldWorld.Instance.EIF.SingleOrDefault(x => x.Type == ItemType.Shield && x.DollGraphic == newRenderData.shield) ?? new EIFRecord()).ID, newRenderData.shield, true); - EquipItem(ItemType.Weapon, (short)(OldWorld.Instance.EIF.SingleOrDefault(x => x.Type == ItemType.Weapon && x.DollGraphic == newRenderData.weapon) ?? new EIFRecord()).ID, newRenderData.weapon, true); - } - public ChestKey CanOpenChest(ChestSpawnMapEntity chest) { ChestKey permission = chest.Key; diff --git a/EndlessClient/Old/PacketAPICallbackManager.cs b/EndlessClient/Old/PacketAPICallbackManager.cs index 1ceb34037..6e861a678 100644 --- a/EndlessClient/Old/PacketAPICallbackManager.cs +++ b/EndlessClient/Old/PacketAPICallbackManager.cs @@ -115,14 +115,14 @@ private void _chestAgree(ChestData data) private void _chestAddItem(short id, int amount, byte weight, byte maxWeight, ChestData data) { - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(id, amount, weight, maxWeight); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(id, amount, weight, maxWeight); ChestDialog.Instance.InitializeItems(data.Items); m_game.Hud.RefreshStats(); } private void _chestGetItem(short id, int amount, byte weight, byte maxWeight, ChestData data) { - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(id, amount, weight, maxWeight, true); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(id, amount, weight, maxWeight, true); ChestDialog.Instance.InitializeItems(data.Items); m_game.Hud.RefreshStats(); } @@ -161,7 +161,7 @@ private void _dropItem(int characterAmount, byte weight, byte maxWeight, OldMapI OldWorld.Instance.ActiveMapRenderer.AddMapItem(item); if (characterAmount >= 0) //will be -1 when another player drops { - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(item.ItemID, characterAmount, weight, maxWeight); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(item.ItemID, characterAmount, weight, maxWeight); var rec = OldWorld.Instance.EIF[item.ItemID]; m_game.Hud.AddChat(ChatTab.System, "", @@ -174,8 +174,8 @@ private void _dropItem(int characterAmount, byte weight, byte maxWeight, OldMapI private void _itemChange(bool wasItemObtained, short id, int amount, byte weight) { - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(id, amount, weight, - OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight, wasItemObtained); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(id, amount, weight, + // OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight, wasItemObtained); } private void _removeItemFromMap(short itemuid) @@ -213,7 +213,7 @@ private void _bankChange(int gold, int bankGold) { if (BankAccountDialog.Instance == null) return; - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(1, gold); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(1, gold); BankAccountDialog.Instance.AccountBalance = $"{bankGold}"; } @@ -225,16 +225,16 @@ private void _shopOpen(int shopid, string name, List tradeitems, List< private void _shopTrade(int gold, short itemID, int amount, byte weight, byte maxWeight, bool isBuy) { - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(1, gold); - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(itemID, amount, weight, maxWeight, isBuy); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(1, gold); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(itemID, amount, weight, maxWeight, isBuy); } private void _shopCraft(short id, byte weight, byte maxWeight, List ingredients) { - OldCharacter c = OldWorld.Instance.MainPlayer.ActiveCharacter; - c.UpdateInventoryItem(id, 1, weight, maxWeight, true); - foreach (var ingred in ingredients) - c.UpdateInventoryItem(ingred.ItemID, ingred.Amount); + //OldCharacter c = OldWorld.Instance.MainPlayer.ActiveCharacter; + //c.UpdateInventoryItem(id, 1, weight, maxWeight, true); + //foreach (var ingred in ingredients) + // c.UpdateInventoryItem(ingred.ItemID, ingred.Amount); } private void _lockerOpen(byte x, byte y, List items) @@ -247,14 +247,14 @@ private void _lockerOpen(byte x, byte y, List items) private void _lockerItemChange(short id, int amount, byte weight, byte maxWeight, bool existingAmount, List items) { if (LockerDialog.Instance == null) return; - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(id, amount, weight, maxWeight, existingAmount); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(id, amount, weight, maxWeight, existingAmount); LockerDialog.Instance.SetLockerData(items); } private void _lockerUpgrade(int remaining, byte upgrades) { if (BankAccountDialog.Instance == null) return; - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(1, remaining); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(1, remaining); BankAccountDialog.Instance.LockerUpgrades = upgrades; m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, EOResourceID.STATUS_LABEL_LOCKER_SPACE_INCREASED); } @@ -390,7 +390,7 @@ private void _statskillLearnSpellSuccess(short id, int remaining) OldWorld.Instance.MainPlayer.ActiveCharacter.Spells.Add(new InventorySpell(id, 0)); if (SkillmasterDialog.Instance != null) SkillmasterDialog.Instance.RemoveSkillByIDFromLearnList(id); - OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(1, remaining); + //OldWorld.Instance.MainPlayer.ActiveCharacter.UpdateInventoryItem(1, remaining); m_game.Hud.AddNewSpellToActiveSpellsByID(id); } From 1d707060c5276f581496ae895a8d27da5d02d3cc Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Mon, 28 Mar 2022 17:12:01 -0700 Subject: [PATCH 14/17] Rename changed PlayerID property -> SessionID --- EOLib/Domain/Login/LoginActions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EOLib/Domain/Login/LoginActions.cs b/EOLib/Domain/Login/LoginActions.cs index 748c4afbf..57ae02db5 100644 --- a/EOLib/Domain/Login/LoginActions.cs +++ b/EOLib/Domain/Login/LoginActions.cs @@ -112,13 +112,13 @@ public async Task RequestCharacterLogin(ICharacter character) _playerInfoRepository.IsFirstTimePlayer = data.FirstTimePlayer; _currentMapStateRepository.CurrentMapID = data.MapID; - _paperdollRepository.VisibleCharacterPaperdolls[data.PlayerID] = new PaperdollData() + _paperdollRepository.VisibleCharacterPaperdolls[data.SessionID] = new PaperdollData() .WithName(data.Name) .WithTitle(data.Title) .WithGuild(data.GuildName) .WithRank(data.GuildRank) .WithClass(data.ClassID) - .WithPlayerID(data.PlayerID) + .WithPlayerID(data.SessionID) .WithPaperdoll(data.Paperdoll); _loginFileChecksumRepository.MapChecksum = data.MapRID.ToArray(); From 2ba0c868ee7d86c5530bf777aca63ad67be3347e Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Mon, 28 Mar 2022 17:17:52 -0700 Subject: [PATCH 15/17] Fix inventory save routine to ini file so that it doesn't persist old slot data for a character --- EndlessClient/HUD/Panels/InventoryPanel.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index ddd4c098d..c03405d36 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -305,14 +305,16 @@ private void SaveInventoryFile(object sender, EventArgs e) ? inventory.Sections[_playerInfoProvider.LoggedInAccountName] : new SortedList(); + var existing = section.Where(x => x.Key.Contains(_characterProvider.MainCharacter.Name)).Select(x => x.Key).ToList(); + foreach (var key in existing) + section.Remove(key); + foreach (var item in _childItems) section[$"{_characterProvider.MainCharacter.Name}.{item.Slot}"] = $"{item.InventoryItem.ItemID}"; inventory.Sections[_playerInfoProvider.LoggedInAccountName] = section; inventory.Save(); - - base.UnloadContent(); } private void HandleItemDoubleClick(object sender, EIFRecord itemData) From ca5dc9d5a8e4c280a11743007812f13ba0493f3b Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Mon, 28 Mar 2022 17:33:00 -0700 Subject: [PATCH 16/17] Fix online list packet translator for new InitReply enum values --- EOLib/Net/Translators/OnlineListPacketTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EOLib/Net/Translators/OnlineListPacketTranslator.cs b/EOLib/Net/Translators/OnlineListPacketTranslator.cs index 426cc8087..d42043077 100644 --- a/EOLib/Net/Translators/OnlineListPacketTranslator.cs +++ b/EOLib/Net/Translators/OnlineListPacketTranslator.cs @@ -18,7 +18,7 @@ public OnlineListPacketTranslator(IECFFileProvider classFileProvider) public IOnlineListData TranslatePacket(IPacket packet) { - var reply = (InitReply)packet.ReadChar(); + var reply = (InitReply)packet.ReadByte(); if (reply != InitReply.AllPlayersList && reply != InitReply.FriendPlayersList) throw new MalformedPacketException($"Expected online list or friend list init data, but was {reply}", packet); From 8459c42e71a644af5f76bd78649b9083f67a505c Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Mon, 28 Mar 2022 17:38:05 -0700 Subject: [PATCH 17/17] Fix update of inventory panel weight label --- EndlessClient/HUD/Panels/InventoryPanel.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index c03405d36..cb1322fbc 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -135,10 +135,11 @@ protected override void OnUpdateControl(GameTime gameTime) some: stats => { stats.SomeWhen(s => s != _characterProvider.MainCharacter.Stats) - .MatchSome(s => + .MatchSome(_ => { - _cachedStats = Option.Some(_characterProvider.MainCharacter.Stats); - _weightLabel.Text = $"{stats[CharacterStat.Weight]} / {stats[CharacterStat.MaxWeight]}"; + var newStats = _characterProvider.MainCharacter.Stats; + _cachedStats = Option.Some(newStats); + _weightLabel.Text = $"{newStats[CharacterStat.Weight]} / {newStats[CharacterStat.MaxWeight]}"; }); }, none: () =>