From 3f14500f5ba17e014b315731358263c32029a4d5 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Tue, 14 Jun 2022 14:14:29 -0700 Subject: [PATCH 01/17] Convert Trade network API calls to TradeActions --- EOLib/Domain/Trade/TradeActions.cs | 92 ++++++++++++++++++ EOLib/Domain/Trade/TradeRepository.cs | 27 ++++++ EOLib/Net/API/Trade.cs | 93 ------------------- EndlessClient/Dialogs/Old/TradeDialog.cs | 32 +++---- EndlessClient/Old/PacketAPICallbackManager.cs | 4 +- 5 files changed, 137 insertions(+), 111 deletions(-) create mode 100644 EOLib/Domain/Trade/TradeActions.cs create mode 100644 EOLib/Domain/Trade/TradeRepository.cs diff --git a/EOLib/Domain/Trade/TradeActions.cs b/EOLib/Domain/Trade/TradeActions.cs new file mode 100644 index 000000000..cae5ab222 --- /dev/null +++ b/EOLib/Domain/Trade/TradeActions.cs @@ -0,0 +1,92 @@ +using AutomaticTypeMapper; +using EOLib.Net; +using EOLib.Net.Communication; +using System; + +namespace EOLib.Domain.Trade +{ + [AutoMappedType] + public class TradeActions : ITradeActions + { + private readonly IPacketSendService _packetSendService; + private readonly ITradeRepository _tradeRepository; + private readonly Random _random; + + public TradeActions(IPacketSendService packetSendService, + ITradeRepository tradeRepository) + { + _packetSendService = packetSendService; + _tradeRepository = tradeRepository; + _random = new Random(); + } + + public void RequestTrade(short characterID) + { + var tradeId = (byte)(_random.Next(252) + 1); + _tradeRepository.TradeSessionID = tradeId; + + var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Request) + .AddChar(tradeId) + .AddShort(characterID) + .Build(); + _packetSendService.SendPacket(packet); + } + + public void AcceptTradeRequest(short characterID) + { + var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Accept) + .AddChar(_tradeRepository.TradeSessionID) + .AddShort(characterID) + .Build(); + _packetSendService.SendPacket(packet); + } + + public void RemoveItemFromOffer(short itemID) + { + var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Remove) + .AddShort(itemID) + .Build(); + _packetSendService.SendPacket(packet); + } + + public void AddItemToOffer(short itemID, int amount) + { + var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Add) + .AddShort(itemID) + .AddInt(amount) + .Build(); + _packetSendService.SendPacket(packet); + } + + public void AgreeToTrade(bool agree) + { + var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Agree) + .AddChar((byte)(agree ? 1 : 0)) + .Build(); + _packetSendService.SendPacket(packet); + } + + public void CancelTrade() + { + var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Close) + .AddChar(_tradeRepository.TradeSessionID) + .Build(); + _packetSendService.SendPacket(packet); + } + } + + public interface ITradeActions + { + void RequestTrade(short characterID); + + void AcceptTradeRequest(short characterID); + + void RemoveItemFromOffer(short itemID); + + void AddItemToOffer(short itemID, int amount); + + void AgreeToTrade(bool agree); + + void CancelTrade(); + } +} diff --git a/EOLib/Domain/Trade/TradeRepository.cs b/EOLib/Domain/Trade/TradeRepository.cs new file mode 100644 index 000000000..6fa3c1a81 --- /dev/null +++ b/EOLib/Domain/Trade/TradeRepository.cs @@ -0,0 +1,27 @@ +namespace EOLib.Domain.Trade +{ + public interface ITradeRepository : IResettable + { + byte TradeSessionID { get; set; } + } + + public interface ITradeProvider + { + byte TradeSessionID { get; } + } + + public class TradeRepository : ITradeRepository, ITradeProvider + { + public byte TradeSessionID { get; set; } + + public TradeRepository() + { + ResetState(); + } + + public void ResetState() + { + TradeSessionID = 0; + } + } +} diff --git a/EOLib/Net/API/Trade.cs b/EOLib/Net/API/Trade.cs index 2b0f9b185..eb3e517a7 100644 --- a/EOLib/Net/API/Trade.cs +++ b/EOLib/Net/API/Trade.cs @@ -29,99 +29,6 @@ private void _createTradeMembers() m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Trade, PacketAction.Close), _handleTradeClose, true); } - /// - /// Request a trade with another player - /// - /// ID of the other player's character - public bool TradeRequest(short characterID) - { - if (!m_client.ConnectedAndInitialized || !Initialized) - return false; - - OldPacket pkt = new OldPacket(PacketFamily.Trade, PacketAction.Request); - pkt.AddChar(123); //? - pkt.AddShort(characterID); - - return m_client.SendPacket(pkt); - } - - /// - /// Accept another players request for trade - /// - /// ID of the other player's character - public bool TradeAcceptRequest(short characterID) - { - if (!m_client.ConnectedAndInitialized || !Initialized) - return false; - - OldPacket pkt = new OldPacket(PacketFamily.Trade, PacketAction.Accept); - pkt.AddChar(123); //? - pkt.AddShort(characterID); - - return m_client.SendPacket(pkt); - } - - /// - /// Remove an item from a pending trade offer - /// - /// Item ID of the item to remove - public bool TradeRemoveItem(short itemID) - { - if (!m_client.ConnectedAndInitialized || !Initialized) - return false; - - OldPacket pkt = new OldPacket(PacketFamily.Trade, PacketAction.Remove); - pkt.AddShort(itemID); - - return m_client.SendPacket(pkt); - } - - /// - /// Add an item to a pending trade offer - /// - /// Item ID of the item to add - /// Amount of the item to add - public bool TradeAddItem(short itemID, int amount) - { - if (!m_client.ConnectedAndInitialized || !Initialized) - return false; - - OldPacket pkt = new OldPacket(PacketFamily.Trade, PacketAction.Add); - pkt.AddShort(itemID); - pkt.AddInt(amount); - - return m_client.SendPacket(pkt); - } - - /// - /// Set the agree flag for a pending trade offer - /// - /// True to agree, false to un-agree - public bool TradeAgree(bool agree) - { - if (!m_client.ConnectedAndInitialized || !Initialized) - return false; - - OldPacket pkt = new OldPacket(PacketFamily.Trade, PacketAction.Agree); - pkt.AddChar((byte)(agree ? 1 : 0)); - - return m_client.SendPacket(pkt); - } - - /// - /// Cancel a pending trade - /// - public bool TradeClose() - { - if (!m_client.ConnectedAndInitialized || !Initialized) - return false; - - OldPacket pkt = new OldPacket(PacketFamily.Trade, PacketAction.Close); - pkt.AddChar(123); //? - - return m_client.SendPacket(pkt); - } - private void _handleTradeRequest(OldPacket pkt) { pkt.Skip(1); //something - will always be 123 from this client diff --git a/EndlessClient/Dialogs/Old/TradeDialog.cs b/EndlessClient/Dialogs/Old/TradeDialog.cs index 685c89c99..dfd317a09 100644 --- a/EndlessClient/Dialogs/Old/TradeDialog.cs +++ b/EndlessClient/Dialogs/Old/TradeDialog.cs @@ -114,8 +114,8 @@ public TradeDialog(PacketAPI apiHandle) { if (e.Result == XNADialogResult.Cancel) { - if (!m_api.TradeClose()) - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + //if (!m_api.TradeClose()) + // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); //((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_ABORTED); } @@ -347,11 +347,11 @@ private void _buttonOkClicked(object sender, EventArgs e) EOMessageBox.Show(DialogResourceID.TRADE_DO_YOU_AGREE, EODialogButtons.OkCancel, EOMessageBoxStyle.SmallDialogSmallHeader, (o, dlgArgs) => { - if (dlgArgs.Result == XNADialogResult.OK && !m_api.TradeAgree(true)) - { - Close(null, XNADialogResult.NO_BUTTON_PRESSED); - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } + //if (dlgArgs.Result == XNADialogResult.OK && !m_api.TradeAgree(true)) + //{ + // Close(null, XNADialogResult.NO_BUTTON_PRESSED); + // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + //} }); } @@ -361,15 +361,15 @@ private void _buttonCancelClicked(object sender, EventArgs e) { if (!m_leftAgrees) //just quit Close(dlgButtons[1], XNADialogResult.Cancel); - else if (!m_api.TradeAgree(false)) //cancel agreement - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + //else if (!m_api.TradeAgree(false)) //cancel agreement + // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); } else if (m_main.ID == m_rightPlayerID) { if (!m_rightAgrees) //just quit Close(dlgButtons[1], XNADialogResult.Cancel); - else if (!m_api.TradeAgree(false)) - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + //else if (!m_api.TradeAgree(false)) + // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); } else throw new InvalidOperationException("Invalid player ID for trade session!"); @@ -378,11 +378,11 @@ private void _buttonCancelClicked(object sender, EventArgs e) //item right-click event handler private void _removeItem(int id) { - if (!m_api.TradeRemoveItem((short)id)) - { - Close(null, XNADialogResult.NO_BUTTON_PRESSED); - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } + //if (!m_api.TradeRemoveItem((short)id)) + //{ + // Close(null, XNADialogResult.NO_BUTTON_PRESSED); + // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); + //} } public override void Update(GameTime gt) diff --git a/EndlessClient/Old/PacketAPICallbackManager.cs b/EndlessClient/Old/PacketAPICallbackManager.cs index 5c0aeba04..83272da86 100644 --- a/EndlessClient/Old/PacketAPICallbackManager.cs +++ b/EndlessClient/Old/PacketAPICallbackManager.cs @@ -40,8 +40,8 @@ private void _tradeRequested(short playerID, string name) EOMessageBox.Show(char.ToUpper(name[0]) + name.Substring(1) + " ", DialogResourceID.TRADE_REQUEST, EODialogButtons.OkCancel, EOMessageBoxStyle.SmallDialogSmallHeader, (o, e) => { - if (e.Result == XNADialogResult.OK && !m_packetAPI.TradeAcceptRequest(playerID)) - m_game.DoShowLostConnectionDialogAndReturnToMainMenu(); + //if (e.Result == XNADialogResult.OK && !m_packetAPI.TradeAcceptRequest(playerID)) + // m_game.DoShowLostConnectionDialogAndReturnToMainMenu(); }); } From 1af2c5bf05511428a3cc1b6ebedb49fc2fd18880 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Tue, 30 Aug 2022 13:21:53 -0700 Subject: [PATCH 02/17] Convert trade packets to new paradigm. Remove PacketAPI and PacketAPICallbackManager. --- EOLib/Domain/Notifiers/ITradeEventNotifier.cs | 23 +++ EOLib/Domain/Trade/TradeOffer.cs | 18 +++ EOLib/Domain/Trade/TradeRepository.cs | 19 ++- EOLib/Net/API/PacketAPI.cs | 30 ---- EOLib/Net/API/Trade.cs | 108 -------------- .../PacketHandlers/Trade/TradeAgreeHandler.cs | 41 +++++ .../PacketHandlers/Trade/TradeCloseHandler.cs | 43 ++++++ .../Trade/TradeOfferUpdateHandler.cs | 141 ++++++++++++++++++ .../PacketHandlers/Trade/TradeOpenHandler.cs | 54 +++++++ .../Trade/TradeRequestHandler.cs | 48 ++++++ .../PacketHandlers/Trade/TradeSpecHandler.cs | 44 ++++++ .../Dialogs/Actions/TradeDialogActions.cs | 63 ++++++++ EndlessClient/Dialogs/Old/EODialogBase.cs | 16 +- EndlessClient/Dialogs/Old/TradeDialog.cs | 4 +- EndlessClient/Old/Game.cs | 2 - EndlessClient/Old/OldCharacter.cs | 9 +- EndlessClient/Old/PacketAPICallbackManager.cs | 97 ------------ .../Rendering/OldCharacterRenderer.cs | 2 +- 18 files changed, 499 insertions(+), 263 deletions(-) create mode 100644 EOLib/Domain/Notifiers/ITradeEventNotifier.cs create mode 100644 EOLib/Domain/Trade/TradeOffer.cs delete mode 100644 EOLib/Net/API/PacketAPI.cs delete mode 100644 EOLib/Net/API/Trade.cs create mode 100644 EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs create mode 100644 EOLib/PacketHandlers/Trade/TradeCloseHandler.cs create mode 100644 EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs create mode 100644 EOLib/PacketHandlers/Trade/TradeOpenHandler.cs create mode 100644 EOLib/PacketHandlers/Trade/TradeRequestHandler.cs create mode 100644 EOLib/PacketHandlers/Trade/TradeSpecHandler.cs create mode 100644 EndlessClient/Dialogs/Actions/TradeDialogActions.cs delete mode 100644 EndlessClient/Old/PacketAPICallbackManager.cs diff --git a/EOLib/Domain/Notifiers/ITradeEventNotifier.cs b/EOLib/Domain/Notifiers/ITradeEventNotifier.cs new file mode 100644 index 000000000..b4021d330 --- /dev/null +++ b/EOLib/Domain/Notifiers/ITradeEventNotifier.cs @@ -0,0 +1,23 @@ +using AutomaticTypeMapper; + +namespace EOLib.Domain.Notifiers +{ + public interface ITradeEventNotifier + { + void NotifyTradeRequest(short playerId, string name); + + void NotifyTradeAccepted(); + + void NotifyTradeClose(bool cancel); + } + + [AutoMappedType] + public class NoopTradeEventNotifier : ITradeEventNotifier + { + public void NotifyTradeRequest(short playerId, string name) { } + + public void NotifyTradeAccepted() { } + + public void NotifyTradeClose(bool cancel) { } + } +} diff --git a/EOLib/Domain/Trade/TradeOffer.cs b/EOLib/Domain/Trade/TradeOffer.cs new file mode 100644 index 000000000..7c1928a63 --- /dev/null +++ b/EOLib/Domain/Trade/TradeOffer.cs @@ -0,0 +1,18 @@ +using Amadevus.RecordGenerator; +using EOLib.Domain.Character; +using System.Collections.Generic; + +namespace EOLib.Domain.Trade +{ + [Record] + public sealed partial class TradeOffer + { + public bool Agrees { get; } + + public short PlayerID { get; } + + public string PlayerName { get; } + + public IReadOnlyList Items { get; } + } +} diff --git a/EOLib/Domain/Trade/TradeRepository.cs b/EOLib/Domain/Trade/TradeRepository.cs index 6fa3c1a81..1790f5e12 100644 --- a/EOLib/Domain/Trade/TradeRepository.cs +++ b/EOLib/Domain/Trade/TradeRepository.cs @@ -1,19 +1,34 @@ -namespace EOLib.Domain.Trade +using EOLib.Domain.Character; +using System.Collections.Generic; + +namespace EOLib.Domain.Trade { public interface ITradeRepository : IResettable { byte TradeSessionID { get; set; } + + TradeOffer PlayerOneOffer { get; set; } + + TradeOffer PlayerTwoOffer { get; set; } } public interface ITradeProvider { byte TradeSessionID { get; } + + TradeOffer PlayerOneOffer { get; } + + TradeOffer PlayerTwoOffer { get; } } public class TradeRepository : ITradeRepository, ITradeProvider { public byte TradeSessionID { get; set; } + public TradeOffer PlayerOneOffer { get; set; } + + public TradeOffer PlayerTwoOffer { get; set; } + public TradeRepository() { ResetState(); @@ -22,6 +37,8 @@ public TradeRepository() public void ResetState() { TradeSessionID = 0; + PlayerOneOffer = new TradeOffer(false, 0, string.Empty, new List()); + PlayerTwoOffer = new TradeOffer(false, 0, string.Empty, new List()); } } } diff --git a/EOLib/Net/API/PacketAPI.cs b/EOLib/Net/API/PacketAPI.cs deleted file mode 100644 index 84835e35c..000000000 --- a/EOLib/Net/API/PacketAPI.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; - -namespace EOLib.Net.API -{ - public sealed partial class PacketAPI : IDisposable - { - private readonly EOClient m_client; - - /// - /// Indicates that the connection handshake has completed successfully. ( Initialize()->HandleInit()->ConfirmInit() ) - /// - public bool Initialized { get; private set; } - - public PacketAPI(EOClient client) - { - if (!client.Connected) - { - throw new ArgumentException("The client must be connected to the server in order to construct the API!"); - } - m_client = client; - - //each of these sets up members of the partial PacketAPI class relevant to a particular packet family - _createTradeMembers(); - } - - public void Dispose() - { - } - } -} diff --git a/EOLib/Net/API/Trade.cs b/EOLib/Net/API/Trade.cs deleted file mode 100644 index eb3e517a7..000000000 --- a/EOLib/Net/API/Trade.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.Generic; -using EOLib.Domain.Character; -using EOLib.Net.Handlers; - -namespace EOLib.Net.API -{ - partial class PacketAPI - { - public delegate void TradeRequestEvent(short playerID, string name); - public delegate void TradeOpenEvent(short player1ID, string player1Name, short player2ID, string player2Name); - public delegate void TradeUpdateEvent(short id1, List items1, short id2, List items2); - public event TradeRequestEvent OnTradeRequested; - public event TradeOpenEvent OnTradeOpen; - public event TradeUpdateEvent OnTradeOfferUpdate; - public event Action OnTradeCancel; - public event Action OnTradeYouAgree; - public event Action OnTradeOtherPlayerAgree; - public event TradeUpdateEvent OnTradeCompleted; - - private void _createTradeMembers() - { - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Trade, PacketAction.Request), _handleTradeRequest, true); - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Trade, PacketAction.Open), _handleTradeOpen, true); - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Trade, PacketAction.Reply), _handleTradeReply, true); - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Trade, PacketAction.Spec), _handleTradeSpec, true); - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Trade, PacketAction.Agree), _handleTradeAgree, true); - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Trade, PacketAction.Use), _handleTradeUse, true); - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Trade, PacketAction.Close), _handleTradeClose, true); - } - - private void _handleTradeRequest(OldPacket pkt) - { - pkt.Skip(1); //something - will always be 123 from this client - short playerID = pkt.GetShort(); - string name = pkt.GetEndString(); - - if (OnTradeRequested != null) - OnTradeRequested(playerID, name); - } - - private void _handleTradeOpen(OldPacket pkt) - { - if (OnTradeOpen == null) return; - - short player1ID = pkt.GetShort(); - string player1Name = pkt.GetBreakString(); - short player2ID = pkt.GetShort(); - string player2Name = pkt.GetBreakString(); - - OnTradeOpen(player1ID, player1Name, player2ID, player2Name); - } - - private void _handleTradeReply(OldPacket pkt) - { - _sharedTradeDataProcess(pkt, OnTradeOfferUpdate); - } - - //sent in response to you agreeing - private void _handleTradeSpec(OldPacket pkt) - { - if (OnTradeYouAgree != null) - OnTradeYouAgree(pkt.GetChar() != 0); - } - - //sent when your trade partner agrees - private void _handleTradeAgree(OldPacket pkt) - { - if (OnTradeOtherPlayerAgree != null) - OnTradeOtherPlayerAgree(pkt.GetShort(), pkt.GetChar() != 0); - } - - //both parties agree to the trade - trade completed - private void _handleTradeUse(OldPacket pkt) - { - _sharedTradeDataProcess(pkt, OnTradeCompleted); - } - - private void _handleTradeClose(OldPacket pkt) - { - if (OnTradeCancel != null) - OnTradeCancel(pkt.GetShort()); - } - - private void _sharedTradeDataProcess(OldPacket pkt, TradeUpdateEvent handler) - { - if (handler == null) return; - - short player1ID = pkt.GetShort(); - List player1Items = new List(); - while (pkt.PeekByte() != 255) - { - player1Items.Add(new InventoryItem(pkt.GetShort(), pkt.GetInt())); - } - pkt.Skip(1); - - short player2ID = pkt.GetShort(); - List player2Items = new List(); - while (pkt.PeekByte() != 255) - { - player2Items.Add(new InventoryItem(pkt.GetShort(), pkt.GetInt())); - } - pkt.Skip(1); - - handler(player1ID, player1Items, player2ID, player2Items); - } - } -} diff --git a/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs b/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs new file mode 100644 index 000000000..3ce81b33d --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs @@ -0,0 +1,41 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Login; +using EOLib.Domain.Trade; +using EOLib.Net; +using EOLib.Net.Handlers; +using Optional; + +namespace EOLib.PacketHandlers.Trade +{ + /// + /// Other party agrees to a trade + /// + [AutoMappedType] + public class TradeAgreeHandler : InGameOnlyPacketHandler + { + private readonly ITradeRepository _tradeRepository; + + public override PacketFamily Family => PacketFamily.Trade; + + public override PacketAction Action => PacketAction.Agree; + + public TradeAgreeHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository) + : base(playerInfoProvider) + { + _tradeRepository = tradeRepository; + } + + public override bool HandlePacket(IPacket packet) + { + var otherPlayerId = packet.ReadShort(); + var otherPlayerAgrees = packet.ReadChar() != 0; + + _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == otherPlayerId) + .Map(x => x.PlayerOneOffer = x.PlayerOneOffer.WithAgrees(otherPlayerAgrees)) + .Or(() => _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer.WithAgrees(otherPlayerAgrees)); + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Trade/TradeCloseHandler.cs b/EOLib/PacketHandlers/Trade/TradeCloseHandler.cs new file mode 100644 index 000000000..421d4239f --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeCloseHandler.cs @@ -0,0 +1,43 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Domain.Trade; +using EOLib.Net; +using EOLib.Net.Handlers; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Trade +{ + /// + /// Other party agrees to a trade + /// + [AutoMappedType] + public class TradeCloseHandler : InGameOnlyPacketHandler + { + private readonly ITradeRepository _tradeRepository; + private readonly IEnumerable _tradeEventNotifiers; + + public override PacketFamily Family => PacketFamily.Trade; + + public override PacketAction Action => PacketAction.Close; + + public TradeCloseHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository, + IEnumerable tradeEventNotifiers) + : base(playerInfoProvider) + { + _tradeRepository = tradeRepository; + _tradeEventNotifiers = tradeEventNotifiers; + } + + public override bool HandlePacket(IPacket packet) + { + foreach (var notifier in _tradeEventNotifiers) + notifier.NotifyTradeClose(cancel: true); + + _tradeRepository.ResetState(); + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs b/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs new file mode 100644 index 000000000..dbdff5c3a --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs @@ -0,0 +1,141 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Domain.Trade; +using EOLib.Net; +using EOLib.Net.Handlers; +using Optional; +using Optional.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace EOLib.PacketHandlers.Trade +{ + public abstract class TradeOfferUpdateHandler : InGameOnlyPacketHandler + { + protected readonly ITradeRepository _tradeRepository; + + public override PacketFamily Family => PacketFamily.Trade; + + protected TradeOfferUpdateHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository) + : base(playerInfoProvider) + { + _tradeRepository = tradeRepository; + } + + public override bool HandlePacket(IPacket packet) + { + var player1Id = packet.ReadShort(); + var player1Items = new List(); + while (packet.PeekByte() != 255) + { + player1Items.Add(new InventoryItem(packet.ReadShort(), packet.ReadInt())); + } + + var player2Id = packet.ReadShort(); + var player2Items = new List(); + while (packet.PeekByte() != 255) + { + player2Items.Add(new InventoryItem(packet.ReadShort(), packet.ReadInt())); + } + + _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == player1Id) + .Match(some: x => + { + x.PlayerOneOffer = x.PlayerOneOffer.WithItems(player1Items); + x.PlayerTwoOffer = x.PlayerTwoOffer.WithItems(player2Items); + }, + none: () => + { + var x = _tradeRepository; + x.PlayerOneOffer = x.PlayerOneOffer.WithItems(player2Items); + x.PlayerTwoOffer = x.PlayerTwoOffer.WithItems(player1Items); + }); + + return true; + } + } + + /// + /// Either player makes an update to their offer + /// + [AutoMappedType] + public class TradeReplyHandler : TradeOfferUpdateHandler + { + public override PacketAction Action => PacketAction.Reply; + + public TradeReplyHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository) + : base(playerInfoProvider, tradeRepository) + { + } + } + + /// + /// Trade completed + /// + public class TradeUseHandler : TradeOfferUpdateHandler + { + private readonly ICharacterProvider _characterProvider; + private readonly ICharacterInventoryRepository _characterInventoryRepository; + private readonly IEnumerable _tradeEventNotifiers; + + public override PacketAction Action => PacketAction.Use; + + public TradeUseHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository, + ICharacterProvider characterProvider, + ICharacterInventoryRepository characterInventoryRepository, + IEnumerable tradeEventNotifiers) + : base(playerInfoProvider, tradeRepository) + { + _characterProvider = characterProvider; + _characterInventoryRepository = characterInventoryRepository; + _tradeEventNotifiers = tradeEventNotifiers; + } + + public override bool HandlePacket(IPacket packet) + { + base.HandlePacket(packet); + + var (removeItems, addItems) = _tradeRepository + .SomeWhen(x => x.PlayerOneOffer.PlayerID == _characterProvider.MainCharacter.ID) + .Match(some: x => (x.PlayerOneOffer.Items, x.PlayerTwoOffer.Items), + none: () => (_tradeRepository.PlayerTwoOffer.Items, _tradeRepository.PlayerOneOffer.Items)); + + foreach (var removedItem in removeItems) + { + _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == removedItem.ItemID) + .MatchSome(x => + { + _characterInventoryRepository.ItemInventory.Remove(x); + if (x.Amount - removedItem.Amount > 0) + { + _characterInventoryRepository.ItemInventory.Add(x.WithAmount(x.Amount - removedItem.Amount)); + } + }); + } + + foreach (var newItem in addItems) + { + _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == newItem.ItemID) + .Match(some: x => + { + _characterInventoryRepository.ItemInventory.Remove(x); + _characterInventoryRepository.ItemInventory.Add(x.WithAmount(x.Amount + newItem.Amount)); + }, + none: () => + { + _characterInventoryRepository.ItemInventory.Add(newItem); + }); + } + + foreach (var notifier in _tradeEventNotifiers) + notifier.NotifyTradeClose(cancel: false); + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Trade/TradeOpenHandler.cs b/EOLib/PacketHandlers/Trade/TradeOpenHandler.cs new file mode 100644 index 000000000..e58fb2699 --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeOpenHandler.cs @@ -0,0 +1,54 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Domain.Trade; +using EOLib.Net; +using EOLib.Net.Handlers; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Trade +{ + /// + /// Trade request is accepted + /// + [AutoMappedType] + public class TradeOpenHandler : InGameOnlyPacketHandler + { + private readonly ITradeRepository _tradeRepository; + private readonly IEnumerable _tradeEventNotifiers; + + public override PacketFamily Family => PacketFamily.Trade; + + public override PacketAction Action => PacketAction.Open; + + public TradeOpenHandler(IPlayerInfoProvider playerInfoProvider, + ITradeRepository tradeRepository, + IEnumerable tradeEventNotifiers) + : base(playerInfoProvider) + { + _tradeRepository = tradeRepository; + _tradeEventNotifiers = tradeEventNotifiers; + } + + public override bool HandlePacket(IPacket packet) + { + _tradeRepository.PlayerOneOffer = _tradeRepository.PlayerOneOffer + .WithAgrees(false) + .WithPlayerID(packet.ReadShort()) + .WithPlayerName(packet.ReadBreakString()) + .WithItems(new List()); + + _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer + .WithAgrees(false) + .WithPlayerID(packet.ReadShort()) + .WithPlayerName(packet.ReadBreakString()) + .WithItems(new List()); + + foreach (var notifier in _tradeEventNotifiers) + notifier.NotifyTradeAccepted(); + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs b/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs new file mode 100644 index 000000000..fe881aa83 --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs @@ -0,0 +1,48 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Login; +using EOLib.Domain.Notifiers; +using EOLib.Domain.Trade; +using EOLib.Net; +using EOLib.Net.Handlers; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Trade +{ + /// + /// Another player requests a trade + /// + [AutoMappedType] + public class TradeRequestHandler : InGameOnlyPacketHandler + { + private readonly ITradeProvider _tradeProvider; + private readonly IEnumerable _tradeEventNotifiers; + + public override PacketFamily Family => PacketFamily.Trade; + + public override PacketAction Action => PacketAction.Request; + + public TradeRequestHandler(IPlayerInfoProvider playerInfoProvider, + ITradeProvider tradeProvider, + IEnumerable tradeEventNotifiers) + : base(playerInfoProvider) + { + _tradeProvider = tradeProvider; + _tradeEventNotifiers = tradeEventNotifiers; + } + + public override bool HandlePacket(IPacket packet) + { + var sessionId = packet.ReadChar(); + var playerId = packet.ReadShort(); + var name = packet.ReadEndString(); + + if (sessionId == _tradeProvider.TradeSessionID) + { + foreach (var notifier in _tradeEventNotifiers) + notifier.NotifyTradeRequest(playerId, name); + } + + return true; + } + } +} diff --git a/EOLib/PacketHandlers/Trade/TradeSpecHandler.cs b/EOLib/PacketHandlers/Trade/TradeSpecHandler.cs new file mode 100644 index 000000000..622c855dc --- /dev/null +++ b/EOLib/PacketHandlers/Trade/TradeSpecHandler.cs @@ -0,0 +1,44 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Character; +using EOLib.Domain.Login; +using EOLib.Domain.Trade; +using EOLib.Net; +using EOLib.Net.Handlers; +using Optional; + +namespace EOLib.PacketHandlers.Trade +{ + /// + /// You agree to a trade + /// + [AutoMappedType] + public class TradeSpecHandler : InGameOnlyPacketHandler + { + private readonly ICharacterProvider _characterProvider; + private readonly ITradeRepository _tradeRepository; + + public override PacketFamily Family => PacketFamily.Trade; + + public override PacketAction Action => PacketAction.Spec; + + public TradeSpecHandler(IPlayerInfoProvider playerInfoProvider, + ICharacterProvider characterProvider, + ITradeRepository tradeRepository) + : base(playerInfoProvider) + { + _characterProvider = characterProvider; + _tradeRepository = tradeRepository; + } + + public override bool HandlePacket(IPacket packet) + { + var youAgree = packet.ReadChar() != 0; + + _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == _characterProvider.MainCharacter.ID) + .Map(x => x.PlayerOneOffer = x.PlayerOneOffer.WithAgrees(youAgree)) + .Or(() => _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer.WithAgrees(youAgree)); + + return true; + } + } +} diff --git a/EndlessClient/Dialogs/Actions/TradeDialogActions.cs b/EndlessClient/Dialogs/Actions/TradeDialogActions.cs new file mode 100644 index 000000000..fc60a6079 --- /dev/null +++ b/EndlessClient/Dialogs/Actions/TradeDialogActions.cs @@ -0,0 +1,63 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Factories; +using EOLib.Config; +using EOLib.Domain.Map; +using EOLib.Domain.Notifiers; +using EOLib.Domain.Trade; +using EOLib.Localization; +using XNAControls; + +namespace EndlessClient.Dialogs.Actions +{ + [AutoMappedType] + public class TradeDialogActions : ITradeEventNotifier + { + private readonly ITradeActions _tradeActions; + private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IConfigurationProvider _configurationProvider; + + public TradeDialogActions(ITradeActions tradeActions, + IEOMessageBoxFactory messageBoxFactory, + IConfigurationProvider configurationProvider) + { + _tradeActions = tradeActions; + _messageBoxFactory = messageBoxFactory; + _configurationProvider = configurationProvider; + } + + public void NotifyTradeRequest(short playerId, string name) + { + if (!_configurationProvider.Interaction) + return; + + var dlg = _messageBoxFactory.CreateMessageBox(char.ToUpper(name[0]) + name[1..] + " ", DialogResourceID.TRADE_REQUEST, EODialogButtons.OkCancel); + dlg.DialogClosing += (_, e) => + { + if (e.Result == XNADialogResult.OK) + { + _tradeActions.AcceptTradeRequest(playerId); + } + }; + + dlg.ShowDialog(); + } + + public void NotifyTradeAccepted() + { + // todo: show trade dialog + + // todo: status label + //m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_YOU_ARE_TRADING_WITH, + // otherName + " " + OldWorld.GetString(EOResourceID.STATUS_LABEL_DRAG_AND_DROP_ITEMS)); + } + + public void NotifyTradeClose(bool cancel) + { + // todo: close trade dialog + + + // todo: status label + //m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_ABORTED); + } + } +} diff --git a/EndlessClient/Dialogs/Old/EODialogBase.cs b/EndlessClient/Dialogs/Old/EODialogBase.cs index 502c7a1e1..2bb90b3eb 100644 --- a/EndlessClient/Dialogs/Old/EODialogBase.cs +++ b/EndlessClient/Dialogs/Old/EODialogBase.cs @@ -1,9 +1,7 @@ -using System; -using EndlessClient.Dialogs.Services; +using EndlessClient.Dialogs.Services; using EndlessClient.GameExecution; using EndlessClient.Old; using EOLib.Graphics; -using EOLib.Net.API; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using XNAControls.Old; @@ -13,18 +11,6 @@ namespace EndlessClient.Dialogs.Old public abstract class EODialogBase : XNADialog { protected readonly Texture2D smallButtonSheet; - protected readonly PacketAPI m_api; - - protected EODialogBase(PacketAPI apiHandle) - { - if (apiHandle != null) - { - if (!apiHandle.Initialized) - throw new ArgumentException("The API is not initialzied. Data transfer will not work."); - m_api = apiHandle; - } - smallButtonSheet = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PreLoginUI, 15, true); - } protected EODialogBase(INativeGraphicsManager nativeGraphicsManager) { diff --git a/EndlessClient/Dialogs/Old/TradeDialog.cs b/EndlessClient/Dialogs/Old/TradeDialog.cs index dfd317a09..a5e25f154 100644 --- a/EndlessClient/Dialogs/Old/TradeDialog.cs +++ b/EndlessClient/Dialogs/Old/TradeDialog.cs @@ -42,8 +42,8 @@ public class TradeDialog : EODialogBase public bool MainPlayerAgrees => (m_main.ID == m_leftPlayerID && m_leftAgrees) || (m_main.ID == m_rightPlayerID && m_rightAgrees); - public TradeDialog(PacketAPI apiHandle) - : base(apiHandle) + public TradeDialog(/*PacketAPI apiHandle*/) + : base(null) { bgTexture = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 50); _setSize(bgTexture.Width, bgTexture.Height); diff --git a/EndlessClient/Old/Game.cs b/EndlessClient/Old/Game.cs index 522f294dc..91835ef82 100644 --- a/EndlessClient/Old/Game.cs +++ b/EndlessClient/Old/Game.cs @@ -33,8 +33,6 @@ public partial class EOGame : Game public GameStates State { get; private set; } - public PacketAPI API => null; - public INativeGraphicsManager GFXManager { get; private set; } #if DEBUG //don't do FPS render on release builds diff --git a/EndlessClient/Old/OldCharacter.cs b/EndlessClient/Old/OldCharacter.cs index 53bcf1624..9e962153e 100644 --- a/EndlessClient/Old/OldCharacter.cs +++ b/EndlessClient/Old/OldCharacter.cs @@ -179,8 +179,6 @@ public bool NeedsSpellTarget public bool IsDrunk { get; set; } - private readonly PacketAPI m_packetAPI; - public OldCharacter() { //mock all members with non-null fields @@ -195,9 +193,8 @@ public OldCharacter() Name = PaddedGuildTag = GuildName = GuildRankStr = ""; } - public OldCharacter(PacketAPI api, int id, CharRenderData data) + public OldCharacter(int id, CharRenderData data) { - m_packetAPI = api; ID = id; RenderData = data ?? new CharRenderData(); @@ -207,11 +204,9 @@ public OldCharacter(PacketAPI api, int id, CharRenderData data) } //constructs a character from a packet sent from the server - public OldCharacter(PacketAPI api, CharacterData data) + public OldCharacter(CharacterData data) { //initialize lists - m_packetAPI = api; - Inventory = new List(); Spells = new List(); PaperDoll = new short[(int)EquipLocation.PAPERDOLL_MAX]; diff --git a/EndlessClient/Old/PacketAPICallbackManager.cs b/EndlessClient/Old/PacketAPICallbackManager.cs deleted file mode 100644 index 83272da86..000000000 --- a/EndlessClient/Old/PacketAPICallbackManager.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using EndlessClient.Dialogs; -using EndlessClient.Dialogs.Old; -using EOLib.Domain.Character; -using EOLib.Localization; -using EOLib.Net.API; -using XNAControls.Old; - -namespace EndlessClient.Old -{ - public sealed class PacketAPICallbackManager - { - private readonly PacketAPI m_packetAPI; - private readonly EOGame m_game; - - public PacketAPICallbackManager(PacketAPI apiObj, EOGame game) - { - m_packetAPI = apiObj; - m_game = game; - } - - public void AssignCallbacks() - { - //trade - m_packetAPI.OnTradeRequested += _tradeRequested; - m_packetAPI.OnTradeOpen += _tradeOpen; - m_packetAPI.OnTradeCancel += _tradeCancel; - m_packetAPI.OnTradeOtherPlayerAgree += _tradeRemotePlayerAgree; - m_packetAPI.OnTradeYouAgree += _tradeSetLocalPlayerAgree; - m_packetAPI.OnTradeOfferUpdate += _tradeOfferUpdate; - m_packetAPI.OnTradeCompleted += _tradeCompleted; - } - - private void _tradeRequested(short playerID, string name) - { - if (!OldWorld.Instance.Interaction) - return; - - EOMessageBox.Show(char.ToUpper(name[0]) + name.Substring(1) + " ", DialogResourceID.TRADE_REQUEST, EODialogButtons.OkCancel, - EOMessageBoxStyle.SmallDialogSmallHeader, (o, e) => - { - //if (e.Result == XNADialogResult.OK && !m_packetAPI.TradeAcceptRequest(playerID)) - // m_game.DoShowLostConnectionDialogAndReturnToMainMenu(); - }); - } - - private void _tradeOpen(short p1, string p1name, short p2, string p2name) - { - TradeDialog dlg = new TradeDialog(m_packetAPI); - dlg.InitPlayerInfo(p1, p1name, p2, p2name); - - string otherName; - if (p1 == OldWorld.Instance.MainPlayer.ActiveCharacter.ID) - otherName = p2name; - else if (p2 == OldWorld.Instance.MainPlayer.ActiveCharacter.ID) - otherName = p1name; - else - throw new ArgumentException("Invalid player ID for this trade session!", nameof(p1)); - - //m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_YOU_ARE_TRADING_WITH, - // otherName + " " + OldWorld.GetString(EOResourceID.STATUS_LABEL_DRAG_AND_DROP_ITEMS)); - } - - private void _tradeCancel(short otherPlayerID) - { - if (TradeDialog.Instance == null) return; - TradeDialog.Instance.Close(XNADialogResult.NO_BUTTON_PRESSED); - //m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_ABORTED); - } - - private void _tradeRemotePlayerAgree(short otherPlayerID, bool agree) - { - if (TradeDialog.Instance == null) return; - TradeDialog.Instance.SetPlayerAgree(false, agree); - } - - private void _tradeSetLocalPlayerAgree(bool agree) - { - if (TradeDialog.Instance == null) return; - TradeDialog.Instance.SetPlayerAgree(true, agree); - } - - private void _tradeOfferUpdate(short id1, List items1, short id2, List items2) - { - if (TradeDialog.Instance == null) return; - TradeDialog.Instance.SetPlayerItems(id1, items1); - TradeDialog.Instance.SetPlayerItems(id2, items2); - } - - private void _tradeCompleted(short id1, List items1, short id2, List items2) - { - if (TradeDialog.Instance == null) return; - TradeDialog.Instance.CompleteTrade(id1, items1, id2, items2); - } - } -} diff --git a/EndlessClient/Rendering/OldCharacterRenderer.cs b/EndlessClient/Rendering/OldCharacterRenderer.cs index 6c4e2b818..333169f45 100644 --- a/EndlessClient/Rendering/OldCharacterRenderer.cs +++ b/EndlessClient/Rendering/OldCharacterRenderer.cs @@ -149,7 +149,7 @@ public OldCharacterRenderer(Vector2 drawLocation, CharRenderData data) : base(drawLocation, null) { noLocUpdate = true; - _char = new OldCharacter(null, -1, data); + _char = new OldCharacter(-1, data); spriteSheet = new EOSpriteSheet(((EOGame)Game).GFXManager, _char); //when this is a part of a dialog, the drawareaoffset will be set accordingly and is used in the draw method //otherwise, it will just draw it at the absolute location specified by drawArea From 33bd06be45e921b9d2cd8315e6622936e063e3c3 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Wed, 31 Aug 2022 20:17:50 -0700 Subject: [PATCH 03/17] Calculate inventory weight changes when completing a trade --- .../Trade/TradeOfferUpdateHandler.cs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs b/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs index dbdff5c3a..9d16266c2 100644 --- a/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs @@ -3,6 +3,7 @@ using EOLib.Domain.Login; using EOLib.Domain.Notifiers; using EOLib.Domain.Trade; +using EOLib.IO.Repositories; using EOLib.Net; using EOLib.Net.Handlers; using Optional; @@ -78,21 +79,24 @@ public class TradeReplyHandler : TradeOfferUpdateHandler /// public class TradeUseHandler : TradeOfferUpdateHandler { - private readonly ICharacterProvider _characterProvider; + private readonly ICharacterRepository _characterRepository; private readonly ICharacterInventoryRepository _characterInventoryRepository; + private readonly IEIFFileProvider _eifFileProvider; private readonly IEnumerable _tradeEventNotifiers; public override PacketAction Action => PacketAction.Use; public TradeUseHandler(IPlayerInfoProvider playerInfoProvider, ITradeRepository tradeRepository, - ICharacterProvider characterProvider, + ICharacterRepository characterRepository, ICharacterInventoryRepository characterInventoryRepository, + IEIFFileProvider eifFileProvider, IEnumerable tradeEventNotifiers) : base(playerInfoProvider, tradeRepository) { - _characterProvider = characterProvider; + _characterRepository = characterRepository; _characterInventoryRepository = characterInventoryRepository; + _eifFileProvider = eifFileProvider; _tradeEventNotifiers = tradeEventNotifiers; } @@ -101,10 +105,11 @@ public override bool HandlePacket(IPacket packet) base.HandlePacket(packet); var (removeItems, addItems) = _tradeRepository - .SomeWhen(x => x.PlayerOneOffer.PlayerID == _characterProvider.MainCharacter.ID) + .SomeWhen(x => x.PlayerOneOffer.PlayerID == _characterRepository.MainCharacter.ID) .Match(some: x => (x.PlayerOneOffer.Items, x.PlayerTwoOffer.Items), none: () => (_tradeRepository.PlayerTwoOffer.Items, _tradeRepository.PlayerOneOffer.Items)); + var stats = _characterRepository.MainCharacter.Stats; foreach (var removedItem in removeItems) { _characterInventoryRepository.ItemInventory.SingleOrNone(x => x.ItemID == removedItem.ItemID) @@ -116,6 +121,8 @@ public override bool HandlePacket(IPacket packet) _characterInventoryRepository.ItemInventory.Add(x.WithAmount(x.Amount - removedItem.Amount)); } }); + + stats = stats.WithNewStat(CharacterStat.Weight, stats[CharacterStat.Weight] - _eifFileProvider.EIFFile[removedItem.ItemID].Weight * removedItem.Amount); } foreach (var newItem in addItems) @@ -130,8 +137,12 @@ public override bool HandlePacket(IPacket packet) { _characterInventoryRepository.ItemInventory.Add(newItem); }); + + stats = stats.WithNewStat(CharacterStat.Weight, stats[CharacterStat.Weight] + _eifFileProvider.EIFFile[newItem.ItemID].Weight * newItem.Amount); } + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); + foreach (var notifier in _tradeEventNotifiers) notifier.NotifyTradeClose(cancel: false); From e4d6dc829b791d3870c1f562cad793fe61e870f2 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Tue, 6 Sep 2022 23:12:04 -0700 Subject: [PATCH 04/17] Trading WIP --- EOLib/Domain/Trade/TradeRepository.cs | 4 +- .../Dialogs/Actions/TradeDialogActions.cs | 11 +- EndlessClient/Dialogs/TradeDialog.cs | 238 ++++++++++++++++++ EndlessClient/Old/OldWorld.cs | 5 - 4 files changed, 249 insertions(+), 9 deletions(-) create mode 100644 EndlessClient/Dialogs/TradeDialog.cs diff --git a/EOLib/Domain/Trade/TradeRepository.cs b/EOLib/Domain/Trade/TradeRepository.cs index 1790f5e12..b298cdb5b 100644 --- a/EOLib/Domain/Trade/TradeRepository.cs +++ b/EOLib/Domain/Trade/TradeRepository.cs @@ -1,4 +1,5 @@ -using EOLib.Domain.Character; +using AutomaticTypeMapper; +using EOLib.Domain.Character; using System.Collections.Generic; namespace EOLib.Domain.Trade @@ -21,6 +22,7 @@ public interface ITradeProvider TradeOffer PlayerTwoOffer { get; } } + [AutoMappedType(IsSingleton = true)] public class TradeRepository : ITradeRepository, ITradeProvider { public byte TradeSessionID { get; set; } diff --git a/EndlessClient/Dialogs/Actions/TradeDialogActions.cs b/EndlessClient/Dialogs/Actions/TradeDialogActions.cs index fc60a6079..7dd69ecb4 100644 --- a/EndlessClient/Dialogs/Actions/TradeDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/TradeDialogActions.cs @@ -55,9 +55,14 @@ public void NotifyTradeClose(bool cancel) { // todo: close trade dialog - - // todo: status label - //m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_ABORTED); + if (cancel) + { + //m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_ABORTED); + } + else + { + //EOMessageBox.Show(DialogResourceID.TRADE_SUCCESS, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + } } } } diff --git a/EndlessClient/Dialogs/TradeDialog.cs b/EndlessClient/Dialogs/TradeDialog.cs new file mode 100644 index 000000000..1d595da83 --- /dev/null +++ b/EndlessClient/Dialogs/TradeDialog.cs @@ -0,0 +1,238 @@ +using EndlessClient.Content; +using EndlessClient.Dialogs.Services; +using EndlessClient.UIControls; +using EOLib; +using EOLib.Domain.Character; +using EOLib.Domain.Trade; +using EOLib.Graphics; +using EOLib.Localization; +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using XNAControls; + +namespace EndlessClient.Dialogs +{ + public class TradeDialog : BaseEODialog + { + private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly ITradeProvider _tradeProvider; + private readonly ICharacterProvider _characterProvider; + + private readonly IXNALabel _leftPlayerName, _rightPlayerName; + private readonly IXNALabel _leftPlayerStatus, _rightPlayerStatus; + private readonly ScrollBar _leftScroll, _rightScroll; + + private readonly IXNAButton _ok, _cancel; + + private readonly List _leftItems, _rightItems; + + // cached values: updated/compared from domain state + private TradeOffer _leftOffer, _rightOffer; + private int _leftScrollOffset, _rightScrollOffset; + + // tracks state around the trade partner quickly changing an offer + // pops up warning for "other player trying to trick you" + private int _recentPartnerItemChanges; + private Stopwatch _partnerItemChangeTick; + + public TradeDialog(INativeGraphicsManager nativeGraphicsManager, + ILocalizedStringFinder localizedStringFinder, + IEODialogButtonService dialogButtonService, + ITradeProvider tradeProvider, + ICharacterProvider characterProvider) + : base(isInGame: true) + { + _nativeGraphicsManager = nativeGraphicsManager; + _localizedStringFinder = localizedStringFinder; + _tradeProvider = tradeProvider; + _characterProvider = characterProvider; + + BackgroundTexture = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 50); + + _leftPlayerName = new XNALabel(Constants.FontSize08pt5) + { + DrawArea = new Rectangle(20, 14, 166, 20), + AutoSize = false, + TextAlign = LabelAlignment.MiddleLeft, + ForeColor = ColorConstants.LightGrayText + }; + _leftPlayerName.SetParentControl(this); + + _rightPlayerName = new XNALabel(Constants.FontSize08pt5) + { + DrawArea = new Rectangle(285, 14, 166, 20), + AutoSize = false, + TextAlign = LabelAlignment.MiddleLeft, + ForeColor = ColorConstants.LightGrayText + }; + _rightPlayerName.SetParentControl(this); + + _leftPlayerStatus = new XNALabel(Constants.FontSize08pt5) + { + DrawArea = new Rectangle(195, 14, 79, 20), + AutoSize = false, + TextAlign = LabelAlignment.MiddleLeft, + ForeColor = ColorConstants.LightGrayText, + Text = _localizedStringFinder.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING) + }; + _leftPlayerStatus.SetParentControl(this); + + _rightPlayerStatus = new XNALabel(Constants.FontSize08pt5) + { + DrawArea = new Rectangle(462, 14, 79, 20), + AutoSize = false, + TextAlign = LabelAlignment.MiddleLeft, + ForeColor = ColorConstants.LightGrayText, + Text = _localizedStringFinder.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING) + }; + _rightPlayerStatus.SetParentControl(this); + + _leftScroll = new ScrollBar(new Vector2(252, 44), new Vector2(16, 199), ScrollBarColors.LightOnMed, _nativeGraphicsManager) { LinesToRender = 5 }; + _leftScroll.SetParentControl(this); + _rightScroll = new ScrollBar(new Vector2(518, 44), new Vector2(16, 199), ScrollBarColors.LightOnMed, _nativeGraphicsManager) { LinesToRender = 5 }; + _rightScroll.SetParentControl(this); + + _ok = new XNAButton(dialogButtonService.SmallButtonSheet, new Vector2(356, 252), + dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Ok), + dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.Ok)); + _ok.OnClick += OkButtonClicked; + _ok.SetParentControl(this); + + _cancel = new XNAButton(dialogButtonService.SmallButtonSheet, new Vector2(449, 252), + dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Cancel), + dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.Cancel)); + _cancel.OnClick += CancelButtonClicked; + _cancel.SetParentControl(this); + + _leftItems = new List(); + _rightItems = new List(); + _leftOffer = new TradeOffer.Builder().ToImmutable(); + _rightOffer = new TradeOffer.Builder().ToImmutable(); + } + + public override void Initialize() + { + base.Initialize(); + + _leftPlayerName.Initialize(); + _rightPlayerName.Initialize(); + + _leftPlayerStatus.Initialize(); + _rightPlayerStatus.Initialize(); + + _leftScroll.Initialize(); + _rightScroll.Initialize(); + + _ok.Initialize(); + _cancel.Initialize(); + } + + protected override void OnUpdateControl(GameTime gameTime) + { + if (_tradeProvider.PlayerOneOffer != null && !_tradeProvider.PlayerOneOffer.Equals(_leftOffer)) + { + UpdateOffer(_tradeProvider.PlayerOneOffer, _leftOffer, _leftPlayerName, _leftPlayerStatus, _leftItems, -3); + _leftOffer = _tradeProvider.PlayerOneOffer; + _leftScroll.UpdateDimensions(_leftOffer.Items.Count); + } + + if (_tradeProvider.PlayerTwoOffer != null && !_tradeProvider.PlayerTwoOffer.Equals(_rightOffer)) + { + UpdateOffer(_tradeProvider.PlayerTwoOffer, _rightOffer, _rightPlayerName, _rightPlayerStatus, _rightItems, 263); + _rightOffer = _tradeProvider.PlayerTwoOffer; + _rightScroll.UpdateDimensions(_rightOffer.Items.Count); + } + + if (_leftScrollOffset != _leftScroll.ScrollOffset) + { + // todo: update left list item display + _leftScrollOffset = _leftScroll.ScrollOffset; + } + + if (_rightScrollOffset != _rightScroll.ScrollOffset) + { + // todo: update right list item display + _rightScrollOffset = _rightScroll.ScrollOffset; + } + + if (_partnerItemChangeTick?.ElapsedMilliseconds > 1000) + { + _recentPartnerItemChanges--; + _partnerItemChangeTick = Stopwatch.StartNew(); + } + + base.OnUpdateControl(gameTime); + } + + private void UpdateOffer(TradeOffer actualOffer, TradeOffer cachedOffer, + IXNALabel playerNameLabel, IXNALabel playerStatusLabel, + List listItems, + int listitemOffset) + { + if (actualOffer.PlayerName != cachedOffer.PlayerName || actualOffer.Items.Count != cachedOffer.Items.Count) + { + playerNameLabel.Text = $"{actualOffer.PlayerName}{(actualOffer.Items.Any() ? $"[{actualOffer.Items.Count}]" : "")}"; + } + + // todo: check if packets properly reset agrees to false when items change + if (actualOffer.Agrees != cachedOffer.Agrees) + { + playerStatusLabel.Text = actualOffer.Agrees + ? _localizedStringFinder.GetString(EOResourceID.DIALOG_TRADE_WORD_AGREE) + : _localizedStringFinder.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING); + + //if (agrees && !m_leftAgrees) + // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, + // isMain ? EOResourceID.STATUS_LABEL_TRADE_YOU_ACCEPT : EOResourceID.STATUS_LABEL_TRADE_OTHER_ACCEPT); + //else if (!agrees && m_leftAgrees) + // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, + // isMain ? EOResourceID.STATUS_LABEL_TRADE_YOU_CANCEL : EOResourceID.STATUS_LABEL_TRADE_OTHER_CANCEL); + } + + if (!actualOffer.Items.ToHashSet().SetEquals(cachedOffer.Items)) + { + var added = actualOffer.Items.Except(cachedOffer.Items); + var removed = cachedOffer.Items.Where(i => !actualOffer.Items.Contains(i)); + + foreach (var addedItem in added) + { + + } + + foreach (var removedItem in removed) + { + + } + + if (actualOffer.PlayerID != _characterProvider.MainCharacter.ID) + { + _partnerItemChangeTick = Stopwatch.StartNew(); + _recentPartnerItemChanges++; + + if (_recentPartnerItemChanges == 3) + { + //EOMessageBox.Show(DialogResourceID.TRADE_OTHER_PLAYER_TRICK_YOU, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + //m_recentPartnerRemoves = -1000; //this will prevent the message from showing more than once (I'm too lazy to find something more elegant) + } + else + { + //EOMessageBox.Show(DialogResourceID.TRADE_ABORTED_OFFER_CHANGED, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + //((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_TRADE_OTHER_PLAYER_CHANGED_OFFER); + } + } + } + } + + private void OkButtonClicked(object sender, EventArgs e) + { + } + + private void CancelButtonClicked(object sender, EventArgs e) + { + } + } +} diff --git a/EndlessClient/Old/OldWorld.cs b/EndlessClient/Old/OldWorld.cs index 693e43980..2267d76bd 100644 --- a/EndlessClient/Old/OldWorld.cs +++ b/EndlessClient/Old/OldWorld.cs @@ -230,10 +230,5 @@ private void Dispose(bool disposing) m_client.Dispose(); } } - - public static void IgnoreDialogs(XNAControl control) - { - control.IgnoreDialog(typeof(TradeDialog)); - } } } From 64e1ba791bc8c30f6e0665389196492aac8b86c7 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 15 Sep 2022 09:48:06 -0700 Subject: [PATCH 05/17] Add check for NPC renderer existence before attempting to show damage counter --- EndlessClient/Rendering/NPC/NPCActions.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EndlessClient/Rendering/NPC/NPCActions.cs b/EndlessClient/Rendering/NPC/NPCActions.cs index 449ec09be..1efff1933 100644 --- a/EndlessClient/Rendering/NPC/NPCActions.cs +++ b/EndlessClient/Rendering/NPC/NPCActions.cs @@ -103,7 +103,8 @@ public void ShowNPCSpeechBubble(int npcIndex, string message) public void NPCTakeDamage(short npcIndex, int fromPlayerId, int damageToNpc, short npcPctHealth, Option spellId) { - _npcRendererRepository.NPCRenderers[npcIndex].ShowDamageCounter(damageToNpc, npcPctHealth, isHeal: false); + if (_npcRendererRepository.NPCRenderers.ContainsKey(npcIndex)) + _npcRendererRepository.NPCRenderers[npcIndex].ShowDamageCounter(damageToNpc, npcPctHealth, isHeal: false); spellId.MatchSome(spell => { From cc295d66c7f6e9a0fce13f895d89aa4dfbba3e17 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 15 Sep 2022 11:19:21 -0700 Subject: [PATCH 06/17] Update base dialog to store a NativeGraphicsManager. Allows trade dialog to hold ListDialogItems --- EndlessClient/Dialogs/BardDialog.cs | 8 +++----- EndlessClient/Dialogs/BaseEODialog.cs | 12 ++++++++++-- EndlessClient/Dialogs/ChangePasswordDialog.cs | 4 ++-- EndlessClient/Dialogs/CreateCharacterDialog.cs | 6 +++--- EndlessClient/Dialogs/EOMessageBox.cs | 4 ++-- EndlessClient/Dialogs/GameLoadingDialog.cs | 4 ++-- EndlessClient/Dialogs/ItemTransferDialog.cs | 4 ++-- EndlessClient/Dialogs/ListDialogItem.cs | 12 ++++++------ EndlessClient/Dialogs/PaperdollDialog.cs | 10 ++++------ EndlessClient/Dialogs/ProgressDialog.cs | 6 +++--- EndlessClient/Dialogs/ScrollingListDialog.cs | 7 +------ EndlessClient/Dialogs/ScrollingMessageDialog.cs | 6 +++--- EndlessClient/Dialogs/SessionExpDialog.cs | 6 +++--- EndlessClient/Dialogs/TextInputDialog.cs | 4 ++-- EndlessClient/Dialogs/TradeDialog.cs | 12 +++++------- 15 files changed, 51 insertions(+), 54 deletions(-) diff --git a/EndlessClient/Dialogs/BardDialog.cs b/EndlessClient/Dialogs/BardDialog.cs index 2aa1d2f0b..9ba25f780 100644 --- a/EndlessClient/Dialogs/BardDialog.cs +++ b/EndlessClient/Dialogs/BardDialog.cs @@ -12,7 +12,6 @@ namespace EndlessClient.Dialogs { public class BardDialog : BaseEODialog { - private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IBardController _bardController; private readonly Texture2D _noteHighlight; private readonly Rectangle _noteRectangleArea; @@ -25,12 +24,11 @@ public class BardDialog : BaseEODialog public BardDialog(INativeGraphicsManager nativeGraphicsManager, IBardController bardController, IEODialogButtonService dialogButtonService) - : base(isInGame: true) + : base(nativeGraphicsManager, isInGame: true) { - _nativeGraphicsManager = nativeGraphicsManager; _bardController = bardController; - BackgroundTexture = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 65); - _noteHighlight = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 66); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 65); + _noteHighlight = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 66); _noteRectangleArea = new Rectangle(15, 15, 240, 60); var cancel = new XNAButton(dialogButtonService.SmallButtonSheet, new Vector2(92, 83), diff --git a/EndlessClient/Dialogs/BaseEODialog.cs b/EndlessClient/Dialogs/BaseEODialog.cs index 9f405ffa4..8a64c10c3 100644 --- a/EndlessClient/Dialogs/BaseEODialog.cs +++ b/EndlessClient/Dialogs/BaseEODialog.cs @@ -1,4 +1,5 @@ using EndlessClient.GameExecution; +using EOLib.Graphics; using Microsoft.Xna.Framework; using System; using XNAControls; @@ -9,13 +10,20 @@ public abstract class BaseEODialog : XNADialog { private readonly Func _isInGame; - protected BaseEODialog(IGameStateProvider gameStateProvider) + public bool ChildControlClickHandled { get; set; } + + public INativeGraphicsManager GraphicsManager { get; } + + protected BaseEODialog(INativeGraphicsManager graphicsManager, + IGameStateProvider gameStateProvider) { + GraphicsManager = graphicsManager; _isInGame = () => gameStateProvider.CurrentState == GameStates.PlayingTheGame; } - protected BaseEODialog(bool isInGame) + protected BaseEODialog(INativeGraphicsManager graphicsManager, bool isInGame) { + GraphicsManager = graphicsManager; _isInGame = () => isInGame; } diff --git a/EndlessClient/Dialogs/ChangePasswordDialog.cs b/EndlessClient/Dialogs/ChangePasswordDialog.cs index 19bfeedd7..ea1f46f4e 100644 --- a/EndlessClient/Dialogs/ChangePasswordDialog.cs +++ b/EndlessClient/Dialogs/ChangePasswordDialog.cs @@ -43,7 +43,7 @@ public class ChangePasswordDialog : BaseEODialog IPlayerInfoProvider playerInfoProvider, IEODialogButtonService dialogButtonService, IXnaControlSoundMapper xnaControlSoundMapper) - : base(gameStateProvider) + : base(nativeGraphicsManager, gameStateProvider) { _eoMessageBoxFactory = eoMessageBoxFactory; _playerInfoProvider = playerInfoProvider; @@ -51,7 +51,7 @@ public class ChangePasswordDialog : BaseEODialog var dispatcher = keyboardDispatcherProvider.Dispatcher; - BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 21); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 21); var cursorTexture = contentProvider.Textures[ContentProvider.Cursor]; diff --git a/EndlessClient/Dialogs/CreateCharacterDialog.cs b/EndlessClient/Dialogs/CreateCharacterDialog.cs index 97a062e2e..270bc1cd3 100644 --- a/EndlessClient/Dialogs/CreateCharacterDialog.cs +++ b/EndlessClient/Dialogs/CreateCharacterDialog.cs @@ -47,13 +47,13 @@ public class CreateCharacterDialog : BaseEODialog IEOMessageBoxFactory messageBoxFactory, IEODialogButtonService eoDialogButtonService, IXnaControlSoundMapper xnaControlSoundMapper) - : base(gameStateProvider) + : base(nativeGraphicsManager, gameStateProvider) { _messageBoxFactory = messageBoxFactory; _xnaControlSoundMapper = xnaControlSoundMapper; - BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 20); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 20); - _charCreateSheet = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 22); + _charCreateSheet = GraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 22); var cursorTexture = contentProvider.Textures[ContentProvider.Cursor]; _inputBox = new XNATextBox(new Rectangle(80, 57, 138, 19), Constants.FontSize08, caretTexture: cursorTexture) diff --git a/EndlessClient/Dialogs/EOMessageBox.cs b/EndlessClient/Dialogs/EOMessageBox.cs index acb22eb23..2e9e1b3c4 100644 --- a/EndlessClient/Dialogs/EOMessageBox.cs +++ b/EndlessClient/Dialogs/EOMessageBox.cs @@ -28,7 +28,7 @@ public class EOMessageBox : BaseEODialog string caption = "", EOMessageBoxStyle style = EOMessageBoxStyle.SmallDialogSmallHeader, EODialogButtons whichButtons = EODialogButtons.Ok) - : base(gameStateProvider) + : base(graphicsManager, gameStateProvider) { var useSmallHeader = style != EOMessageBoxStyle.SmallDialogLargeHeader; @@ -41,7 +41,7 @@ public class EOMessageBox : BaseEODialog default: throw new ArgumentOutOfRangeException(nameof(style), "Unrecognized dialog style!"); } - BackgroundTexture = graphicsManager.TextureFromResource(GFXTypes.PreLoginUI, graphic); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, graphic); _messageLabel = new XNALabel(Constants.FontSize10) { diff --git a/EndlessClient/Dialogs/GameLoadingDialog.cs b/EndlessClient/Dialogs/GameLoadingDialog.cs index c7862379f..2a126af6c 100644 --- a/EndlessClient/Dialogs/GameLoadingDialog.cs +++ b/EndlessClient/Dialogs/GameLoadingDialog.cs @@ -23,10 +23,10 @@ public class GameLoadingDialog : BaseEODialog IGameStateProvider gameStateProvider, IClientWindowSizeProvider clientWindowSizeProvider, ILocalizedStringFinder localizedStringFinder) - : base(gameStateProvider) + : base(nativeGraphicsManager, gameStateProvider) { _localizedStringFinder = localizedStringFinder; - _backgroundSprite = nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 33); + _backgroundSprite = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 33); DrawPosition = new Vector2(clientWindowSizeProvider.Width - _backgroundSprite.Width / 4 - 10, clientWindowSizeProvider.Height - _backgroundSprite.Height - 10); diff --git a/EndlessClient/Dialogs/ItemTransferDialog.cs b/EndlessClient/Dialogs/ItemTransferDialog.cs index 4eb253b9e..22c84a44a 100644 --- a/EndlessClient/Dialogs/ItemTransferDialog.cs +++ b/EndlessClient/Dialogs/ItemTransferDialog.cs @@ -49,12 +49,12 @@ public enum TransferType TransferType transferType, int totalAmount, EOResourceID message) - : base(isInGame: true) + : base(nativeGraphicsManager, isInGame: true) { if (!IsValidMessage(message)) throw new ArgumentOutOfRangeException(nameof(message), "Use one of the approved messages."); - _backgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 27); + _backgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 27); _backgroundTextureSource = new Rectangle(38, 0, 265, 170); // set so CenterInGameView works properly (expected BackgroundTexture to be set) diff --git a/EndlessClient/Dialogs/ListDialogItem.cs b/EndlessClient/Dialogs/ListDialogItem.cs index 7c02667c4..4b3d28502 100644 --- a/EndlessClient/Dialogs/ListDialogItem.cs +++ b/EndlessClient/Dialogs/ListDialogItem.cs @@ -25,7 +25,7 @@ public enum ListItemStyle private readonly Texture2D _gfxPadThing; private readonly Texture2D _backgroundColor; - private readonly ScrollingListDialog _parentList; + private readonly BaseEODialog _parentDialog; private bool _drawBackground; @@ -98,9 +98,9 @@ public string SubText public event EventHandler RightClick; public event EventHandler LeftClick; - public ListDialogItem(ScrollingListDialog parent, ListItemStyle style, int listIndex = -1) + public ListDialogItem(BaseEODialog parent, ListItemStyle style, int listIndex = -1) { - _parentList = parent; + _parentDialog = parent; DrawPosition += new Vector2(17, 0); @@ -221,10 +221,10 @@ protected override void OnUpdateControl(GameTime gameTime) _drawBackground = true; if (CurrentMouseState.RightButton == ButtonState.Released && PreviousMouseState.RightButton == ButtonState.Pressed && - !_parentList.ChildControlClickHandled) + !_parentDialog.ChildControlClickHandled) { RightClick?.Invoke(this, EventArgs.Empty); - _parentList.ChildControlClickHandled = true; + _parentDialog.ChildControlClickHandled = true; } else if(CurrentMouseState.LeftButton == ButtonState.Released && PreviousMouseState.LeftButton == ButtonState.Pressed) @@ -234,7 +234,7 @@ protected override void OnUpdateControl(GameTime gameTime) !(_primaryText is IXNAHyperLink || _subText is IXNAHyperLink)) LeftClick?.Invoke(this, EventArgs.Empty); - _parentList.ChildControlClickHandled = true; + _parentDialog.ChildControlClickHandled = true; } } else diff --git a/EndlessClient/Dialogs/PaperdollDialog.cs b/EndlessClient/Dialogs/PaperdollDialog.cs index f044f8a69..d61fd4f67 100644 --- a/EndlessClient/Dialogs/PaperdollDialog.cs +++ b/EndlessClient/Dialogs/PaperdollDialog.cs @@ -32,7 +32,6 @@ public class PaperdollDialog : BaseEODialog { private static readonly Rectangle _iconDrawRect = new Rectangle(227, 258, 44, 21); - private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly IInventoryController _inventoryController; private readonly IPaperdollProvider _paperdollProvider; private readonly IPubFileProvider _pubFileProvider; @@ -71,7 +70,7 @@ public class PaperdollDialog : BaseEODialog IStatusLabelSetter statusLabelSetter, ISfxPlayer sfxPlayer, Character character, bool isMainCharacter) - : base(gameStateProvider) + : base(nativeGraphicsManager, gameStateProvider) { _paperdollProvider = paperdollProvider; _pubFileProvider = pubFileProvider; @@ -79,18 +78,17 @@ public class PaperdollDialog : BaseEODialog _eoMessageBoxFactory = eoMessageBoxFactory; _statusLabelSetter = statusLabelSetter; _sfxPlayer = sfxPlayer; - _nativeGraphicsManager = nativeGraphicsManager; _inventoryController = inventoryController; Character = character; _isMainCharacter = isMainCharacter; - _characterIconSheet = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 32, true); + _characterIconSheet = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 32, true); _characterIconSourceRect = Option.None(); _inventoryPanel = hudControlProvider.GetComponent(HudControlIdentifier.InventoryPanel); _childItems = new List(); - BackgroundTexture = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 49); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 49); BackgroundTextureSource = new Rectangle(0, BackgroundTexture.Height / 2 * Character.RenderProperties.Gender, DrawArea.Width, BackgroundTexture.Height / 2); var okButton = new XNAButton(eoDialogButtonService.SmallButtonSheet, @@ -203,7 +201,7 @@ private void UpdateDisplayedData(PaperdollData paperdollData) var id = paperdollData.Paperdoll[equipLocation]; var eifRecord = id.SomeWhen(i => i > 0).Map(i => _pubFileProvider.EIFFile[i]); - var paperdollItem = new PaperdollDialogItem(_nativeGraphicsManager, _sfxPlayer, _inventoryPanel, this, _isMainCharacter, equipLocation, eifRecord) + var paperdollItem = new PaperdollDialogItem(GraphicsManager, _sfxPlayer, _inventoryPanel, this, _isMainCharacter, equipLocation, eifRecord) { DrawArea = equipLocation.GetEquipLocationRectangle() }; diff --git a/EndlessClient/Dialogs/ProgressDialog.cs b/EndlessClient/Dialogs/ProgressDialog.cs index 68c1bf8a3..5a698f105 100644 --- a/EndlessClient/Dialogs/ProgressDialog.cs +++ b/EndlessClient/Dialogs/ProgressDialog.cs @@ -28,11 +28,11 @@ public class ProgressDialog : BaseEODialog IEODialogButtonService eoDialogButtonService, string messageText, string captionText) - : base(gameStateProvider) + : base(nativeGraphicsManager, gameStateProvider) { _configurationProvider = configurationProvider; - BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 18); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 18); _messageLabel = new XNALabel(Constants.FontSize10) { @@ -60,7 +60,7 @@ public class ProgressDialog : BaseEODialog _cancelButton.OnClick += DoCancel; _cancelButton.SetParentControl(this); - _pbBackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 19); + _pbBackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 19); _pbForegroundTexture = new Texture2D(Game.GraphicsDevice, 1, _pbBackgroundTexture.Height - 2); //foreground texture is just a fill var pbForeFill = new Color[_pbForegroundTexture.Width * _pbForegroundTexture.Height]; diff --git a/EndlessClient/Dialogs/ScrollingListDialog.cs b/EndlessClient/Dialogs/ScrollingListDialog.cs index 6a6886d66..4d0aea02d 100644 --- a/EndlessClient/Dialogs/ScrollingListDialog.cs +++ b/EndlessClient/Dialogs/ScrollingListDialog.cs @@ -146,8 +146,6 @@ public ScrollingListDialogButtons Buttons } } - public INativeGraphicsManager GraphicsManager { get; } - public ScrollingListDialogSize DialogSize { get; } public event EventHandler AddAction; @@ -160,18 +158,15 @@ public ScrollingListDialogButtons Buttons public event EventHandler ProgressAction; - public bool ChildControlClickHandled { get; set; } - public ScrollingListDialog(INativeGraphicsManager nativeGraphicsManager, IEODialogButtonService dialogButtonService, ScrollingListDialogSize dialogSize = ScrollingListDialogSize.Large) - : base(isInGame: true) + : base(nativeGraphicsManager, isInGame: true) { // todo: implement boards if (dialogSize == ScrollingListDialogSize.MediumWithHeader) throw new NotImplementedException(); - GraphicsManager = nativeGraphicsManager; DialogSize = dialogSize; _listItems = new List(); diff --git a/EndlessClient/Dialogs/ScrollingMessageDialog.cs b/EndlessClient/Dialogs/ScrollingMessageDialog.cs index e77349389..9f14fc92b 100644 --- a/EndlessClient/Dialogs/ScrollingMessageDialog.cs +++ b/EndlessClient/Dialogs/ScrollingMessageDialog.cs @@ -56,12 +56,12 @@ public string MessageText IContentProvider contentProvider, IGameStateProvider gameStateProvider, IEODialogButtonService eoDialogButtonService) - : base(gameStateProvider) + : base(nativeGraphicsManager, gameStateProvider) { _font = contentProvider.Fonts[Constants.FontSize08]; _textSplitter = new TextSplitter("", _font) { LineLength = 275 }; - BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 40); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 40); var smallButtonSheet = eoDialogButtonService.SmallButtonSheet; @@ -73,7 +73,7 @@ public string MessageText _ok.SetParentControl(this); _scrollBar = new ScrollBar(new Vector2(320, 66), new Vector2(16, 119), - ScrollBarColors.LightOnMed, nativeGraphicsManager); + ScrollBarColors.LightOnMed, GraphicsManager); _scrollBar.SetParentControl(this); MessageText = ""; diff --git a/EndlessClient/Dialogs/SessionExpDialog.cs b/EndlessClient/Dialogs/SessionExpDialog.cs index 917e06635..d368cc1af 100644 --- a/EndlessClient/Dialogs/SessionExpDialog.cs +++ b/EndlessClient/Dialogs/SessionExpDialog.cs @@ -29,11 +29,11 @@ static SessionExpDialog() ICharacterProvider characterProvider, IExperienceTableProvider expTableProvider, ICharacterSessionProvider characterSessionProvider) - : base(isInGame: true) + : base(nativeGraphicsManager, isInGame: true) { - BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 61); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 61); - _icons = nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 68, true); + _icons = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 68, true); var okButton = new XNAButton(dialogButtonService.SmallButtonSheet, new Vector2(98, 214), diff --git a/EndlessClient/Dialogs/TextInputDialog.cs b/EndlessClient/Dialogs/TextInputDialog.cs index b703f1594..954699b32 100644 --- a/EndlessClient/Dialogs/TextInputDialog.cs +++ b/EndlessClient/Dialogs/TextInputDialog.cs @@ -23,11 +23,11 @@ public class TextInputDialog : BaseEODialog IContentProvider contentProvider, string prompt, int maxInputChars = 12) - : base(isInGame: true) + : base(nativeGraphicsManager, isInGame: true) { _keyboardDispatcherRepository = keyboardDispatcherRepository; - BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 54); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 54); SetSize(BackgroundTexture.Width, BackgroundTexture.Height); var lblPrompt = new XNALabel(Constants.FontSize10) diff --git a/EndlessClient/Dialogs/TradeDialog.cs b/EndlessClient/Dialogs/TradeDialog.cs index 1d595da83..682b5c6c5 100644 --- a/EndlessClient/Dialogs/TradeDialog.cs +++ b/EndlessClient/Dialogs/TradeDialog.cs @@ -17,7 +17,6 @@ namespace EndlessClient.Dialogs { public class TradeDialog : BaseEODialog { - private readonly INativeGraphicsManager _nativeGraphicsManager; private readonly ILocalizedStringFinder _localizedStringFinder; private readonly ITradeProvider _tradeProvider; private readonly ICharacterProvider _characterProvider; @@ -44,14 +43,13 @@ public class TradeDialog : BaseEODialog IEODialogButtonService dialogButtonService, ITradeProvider tradeProvider, ICharacterProvider characterProvider) - : base(isInGame: true) + : base(nativeGraphicsManager, isInGame: true) { - _nativeGraphicsManager = nativeGraphicsManager; _localizedStringFinder = localizedStringFinder; _tradeProvider = tradeProvider; _characterProvider = characterProvider; - BackgroundTexture = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 50); + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 50); _leftPlayerName = new XNALabel(Constants.FontSize08pt5) { @@ -91,9 +89,9 @@ public class TradeDialog : BaseEODialog }; _rightPlayerStatus.SetParentControl(this); - _leftScroll = new ScrollBar(new Vector2(252, 44), new Vector2(16, 199), ScrollBarColors.LightOnMed, _nativeGraphicsManager) { LinesToRender = 5 }; + _leftScroll = new ScrollBar(new Vector2(252, 44), new Vector2(16, 199), ScrollBarColors.LightOnMed, GraphicsManager) { LinesToRender = 5 }; _leftScroll.SetParentControl(this); - _rightScroll = new ScrollBar(new Vector2(518, 44), new Vector2(16, 199), ScrollBarColors.LightOnMed, _nativeGraphicsManager) { LinesToRender = 5 }; + _rightScroll = new ScrollBar(new Vector2(518, 44), new Vector2(16, 199), ScrollBarColors.LightOnMed, GraphicsManager) { LinesToRender = 5 }; _rightScroll.SetParentControl(this); _ok = new XNAButton(dialogButtonService.SmallButtonSheet, new Vector2(356, 252), @@ -200,7 +198,7 @@ protected override void OnUpdateControl(GameTime gameTime) foreach (var addedItem in added) { - + //var newListItem = new ListDialogItem(this, ) } foreach (var removedItem in removed) From 716f63620c8b972c16c9807aa8d0bcbbc19d579e Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 15 Sep 2022 12:08:21 -0700 Subject: [PATCH 07/17] Update inventory drag+drop to work with bank deposit --- .../Controllers/InventoryController.cs | 25 ++++++++++++- EndlessClient/Dialogs/BankAccountDialog.cs | 9 +++++ EndlessClient/HUD/Panels/InventoryPanel.cs | 35 +++++-------------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/EndlessClient/Controllers/InventoryController.cs b/EndlessClient/Controllers/InventoryController.cs index 8e8553faf..c856056ee 100644 --- a/EndlessClient/Controllers/InventoryController.cs +++ b/EndlessClient/Controllers/InventoryController.cs @@ -10,6 +10,7 @@ using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Interact; +using EOLib.Domain.Interact.Bank; using EOLib.Domain.Item; using EOLib.Domain.Map; using EOLib.IO; @@ -30,6 +31,7 @@ public class InventoryController : IInventoryController private readonly IPaperdollActions _paperdollActions; private readonly IChestActions _chestActions; private readonly ILockerActions _lockerActions; + private readonly IBankActions _bankActions; private readonly IItemEquipValidator _itemEquipValidator; private readonly IItemDropValidator _itemDropValidator; private readonly ICharacterProvider _characterProvider; @@ -47,6 +49,7 @@ public class InventoryController : IInventoryController IPaperdollActions paperdollActions, IChestActions chestActions, ILockerActions lockerActions, + IBankActions bankActions, IItemEquipValidator itemEquipValidator, IItemDropValidator itemDropValidator, ICharacterProvider characterProvider, @@ -64,6 +67,7 @@ public class InventoryController : IInventoryController _paperdollActions = paperdollActions; _chestActions = chestActions; _lockerActions = lockerActions; + _bankActions = bankActions; _itemEquipValidator = itemEquipValidator; _itemDropValidator = itemDropValidator; _characterProvider = characterProvider; @@ -262,6 +266,23 @@ public void DropItemInLocker(EIFRecord itemData, InventoryItem inventoryItem) } } + public void DropItemInBank(EIFRecord itemData, InventoryItem inventoryItem) + { + if (inventoryItem.Amount == 0) + { + var dlg = _eoMessageBoxFactory.CreateMessageBox(DialogResourceID.BANK_ACCOUNT_UNABLE_TO_DEPOSIT); + dlg.ShowDialog(); + } + else + { + DoItemDrop(itemData, + inventoryItem, + a => _bankActions.Deposit(a), + ItemTransferDialog.TransferType.BankTransfer, + EOResourceID.DIALOG_TRANSFER_DEPOSIT); + } + } + public void JunkItem(EIFRecord itemData, InventoryItem inventoryItem) { if (inventoryItem.Amount > 1) @@ -301,7 +322,7 @@ public void JunkItem(EIFRecord itemData, InventoryItem inventoryItem) { if (e.Result == XNADialogResult.OK) { - if (inventoryItem.ItemID == 1 && transferDialog.SelectedAmount > 10000) + if (inventoryItem.ItemID == 1 && transferDialog.SelectedAmount > 10000 && transferType == ItemTransferDialog.TransferType.DropItems) { var warningMsg = _eoMessageBoxFactory.CreateMessageBox(DialogResourceID.DROP_MANY_GOLD_ON_GROUND, EODialogButtons.OkCancel); warningMsg.DialogClosing += (_, warningArgs) => @@ -342,6 +363,8 @@ public interface IInventoryController void DropItemInLocker(EIFRecord itemData, InventoryItem inventoryItem); + void DropItemInBank(EIFRecord itemData, InventoryItem inventoryItem); + void JunkItem(EIFRecord itemData, InventoryItem inventoryItem); } } diff --git a/EndlessClient/Dialogs/BankAccountDialog.cs b/EndlessClient/Dialogs/BankAccountDialog.cs index 09cd38234..1d1898f2e 100644 --- a/EndlessClient/Dialogs/BankAccountDialog.cs +++ b/EndlessClient/Dialogs/BankAccountDialog.cs @@ -139,6 +139,9 @@ protected override void OnUpdateControl(GameTime gameTime) private void Deposit(object sender, EventArgs e) { + if (!_inventoryPanel.NoItemsDragging()) + return; + _characterInventoryProvider.ItemInventory.SingleOrNone(x => x.ItemID == 1) .Match( some: characterGold => @@ -176,6 +179,9 @@ private void Deposit(object sender, EventArgs e) private void Withdraw(object sender, EventArgs e) { + if (!_inventoryPanel.NoItemsDragging()) + return; + if (_bankDataProvider.AccountValue == 0) { var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.BANK_ACCOUNT_UNABLE_TO_WITHDRAW); @@ -201,6 +207,9 @@ private void Withdraw(object sender, EventArgs e) private void Upgrade(object sender, EventArgs e) { + if (!_inventoryPanel.NoItemsDragging()) + return; + _bankDataProvider.LockerUpgrades.MatchSome(lockerUpgrades => { if (lockerUpgrades == Constants.MaxLockerUpgrades) diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index 9f13b672f..7c89b0b5b 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -416,6 +416,14 @@ private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCo _inventoryController.DropItemInLocker(item.Data, item.InventoryItem); } }); + _activeDialogProvider.BankAccountDialog.MatchSome(x => + { + if (x.MouseOver && x.MouseOverPreviously && item.Data.ID == 1) + { + dialogDrop = true; + _inventoryController.DropItemInBank(item.Data, item.InventoryItem); + } + }); if (dialogDrop) { @@ -479,32 +487,7 @@ private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCo #region Unimplemented drag action /* - 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 + if (TradeDialog.Instance != null && TradeDialog.Instance.MouseOver && TradeDialog.Instance.MouseOverPreviously && !TradeDialog.Instance.MainPlayerAgrees) { if (m_itemData.Special == ItemSpecial.Lore) From c0d114531ea0f086321a788c90e58c1e8297af81 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 15 Sep 2022 12:53:19 -0700 Subject: [PATCH 08/17] First-pass implementation of trade dialog. TODO: - Wire up to open on trade requests - Inventory space validator implementation - Drag+drop from inventory to add items - Testing --- EndlessClient/Dialogs/ListDialogItem.cs | 2 + EndlessClient/Dialogs/Old/EODialogBase.cs | 106 ----- .../Dialogs/Old/OldListDialogItem.cs | 321 ------------- EndlessClient/Dialogs/Old/TradeDialog.cs | 445 ------------------ EndlessClient/Dialogs/TradeDialog.cs | 175 ++++++- .../HUD/Inventory/InventorySpaceValidator.cs | 9 +- EndlessClient/Old/OldWorld.cs | 1 - .../Rendering/Map/MapItemGraphicProvider.cs | 2 +- EndlessClient/Rendering/OldNPCRenderer.cs | 1 - 9 files changed, 167 insertions(+), 895 deletions(-) delete mode 100644 EndlessClient/Dialogs/Old/EODialogBase.cs delete mode 100644 EndlessClient/Dialogs/Old/OldListDialogItem.cs delete mode 100644 EndlessClient/Dialogs/Old/TradeDialog.cs diff --git a/EndlessClient/Dialogs/ListDialogItem.cs b/EndlessClient/Dialogs/ListDialogItem.cs index 4b3d28502..e159e34c8 100644 --- a/EndlessClient/Dialogs/ListDialogItem.cs +++ b/EndlessClient/Dialogs/ListDialogItem.cs @@ -95,6 +95,8 @@ public string SubText public bool ShowIconBackGround { get; set; } + public object Data { get; set; } + public event EventHandler RightClick; public event EventHandler LeftClick; diff --git a/EndlessClient/Dialogs/Old/EODialogBase.cs b/EndlessClient/Dialogs/Old/EODialogBase.cs deleted file mode 100644 index 2bb90b3eb..000000000 --- a/EndlessClient/Dialogs/Old/EODialogBase.cs +++ /dev/null @@ -1,106 +0,0 @@ -using EndlessClient.Dialogs.Services; -using EndlessClient.GameExecution; -using EndlessClient.Old; -using EOLib.Graphics; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using XNAControls.Old; - -namespace EndlessClient.Dialogs.Old -{ - public abstract class EODialogBase : XNADialog - { - protected readonly Texture2D smallButtonSheet; - - protected EODialogBase(INativeGraphicsManager nativeGraphicsManager) - { - smallButtonSheet = nativeGraphicsManager.TextureFromResource(GFXTypes.PreLoginUI, 15, true); - } - - protected void endConstructor(bool centerDialog = true) - { - //center dialog based on txtSize of background texture - if (centerDialog) - { - Center(Game.GraphicsDevice); - if (EOGame.Instance.State == GameStates.PlayingTheGame) - { - DrawLocation = new Vector2(DrawLocation.X, (330 - DrawArea.Height) / 2f); - } - } - _fixDrawOrder(); - DrawOrder += 100; - Dialogs.Push(this); - - Game.Components.Add(this); - } - - //todo: usage of this should eventually be refactored out if possible - protected void CenterAndFixDrawOrder(IGraphicsDeviceProvider graphicsDeviceProvider, - IGameStateProvider gameStateProvider, - bool shouldCenter = true) - { - if (shouldCenter) - { - Center(graphicsDeviceProvider.GraphicsDevice); - - if (gameStateProvider.CurrentState == GameStates.PlayingTheGame) - DrawLocation = new Vector2(DrawLocation.X, (330 - DrawArea.Height)/2f); - } - - _fixDrawOrder(); - DrawOrder += 100; - - Dialogs.Push(this); - Game.Components.Add(this); - } - - protected Rectangle _getSmallButtonOut(SmallButton whichOne) - { - int widthDelta = smallButtonSheet.Width / 2; - int heightDelta = smallButtonSheet.Height / (int)SmallButton.NUM_BUTTONS; - return new Rectangle(0, heightDelta * (int)whichOne, widthDelta, heightDelta); - } - - protected Rectangle _getSmallButtonOver(SmallButton whichOne) - { - int widthDelta = smallButtonSheet.Width / 2; - int heightDelta = smallButtonSheet.Height / (int)SmallButton.NUM_BUTTONS; - return new Rectangle(widthDelta, heightDelta * (int)whichOne, widthDelta, heightDelta); - } - - protected enum ListIcon - { - Buy = 0, - Sell, - BankDeposit, - BankWithdraw, - Craft, - BankLockerUpgrade, - - Learn = 20, - Forget = 21, - } - protected Texture2D _getDlgIcon(ListIcon whichOne) - { - const int NUM_PER_ROW = 9; - const int ICON_SIZE = 31; - - Texture2D weirdSheet = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 27); - Color[] dat = new Color[ICON_SIZE * ICON_SIZE]; - - Rectangle src = new Rectangle(((int)whichOne % NUM_PER_ROW) * ICON_SIZE, 291 + ((int)whichOne / NUM_PER_ROW) * ICON_SIZE, ICON_SIZE, ICON_SIZE); - weirdSheet.GetData(0, src, dat, 0, dat.Length); - - Texture2D ret = new Texture2D(EOGame.Instance.GraphicsDevice, ICON_SIZE, ICON_SIZE); - ret.SetData(dat); - return ret; - } - - /// - /// This is a no-op to hide Resharper warnings. It may eventually do something. - /// It would be nice to trigger adding all controls to Components by calling this. - /// - public virtual void Show() { } - } -} diff --git a/EndlessClient/Dialogs/Old/OldListDialogItem.cs b/EndlessClient/Dialogs/Old/OldListDialogItem.cs deleted file mode 100644 index 6c4006c59..000000000 --- a/EndlessClient/Dialogs/Old/OldListDialogItem.cs +++ /dev/null @@ -1,321 +0,0 @@ -using System; -using EndlessClient.Old; -using EOLib; -using EOLib.Graphics; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using Microsoft.Xna.Framework.Input; -using XNAControls.Old; - -namespace EndlessClient.Dialogs.Old -{ - public class OldListDialogItem : XNAControl - { - private static readonly object disposingLock = new object(); - private bool m_disposing; - - /// - /// Optional item ID to use for this List Item Record - /// - public short ID { get; set; } - /// - /// Optional item amount to use for this List Item Record - /// - public int Amount { get; set; } - - private int m_index; - /// - /// Get or Set the index within the parent control. - /// - public int Index - { - get { return m_index; } - set - { - m_index = value; - DrawLocation = new Vector2(DrawLocation.X, OffsetY + (m_index * (Style == ListItemStyle.Large ? 36 : 16))); - } - } - - private int m_xOffset, m_yOffset; - - public int OffsetX - { - get - { - return m_xOffset; - } - set - { - int oldOff = m_xOffset; - m_xOffset = value; - DrawLocation = DrawLocation + new Vector2(m_xOffset - oldOff, 0); - } - } - - /// - /// Starting Y Offset to draw list item controls - /// - public int OffsetY - { - get - { - return m_yOffset; - } - set - { - int oldOff = m_yOffset; - m_yOffset = value; - DrawLocation = DrawLocation + new Vector2(0, m_yOffset - oldOff); - } - } - - /// - /// Style of the control - either small (single text row) or large (graphic w/two rows of text) - /// - public ListItemStyle Style { get; set; } - - /// - /// For Large style control, sets whether or not the item graphic has a background image (ie red pad thing) - /// - public bool ShowItemBackGround { get; set; } - - /// - /// Get or set the primary text - /// - public string Text - { - get { return m_primaryText.Text; } - set - { - m_primaryText.Text = value; - m_primaryText.ResizeBasedOnText(); - } - } - - /// - /// Get or set the secondary text - /// - public string SubText - { - get { return m_secondaryText.Text; } - set - { - m_secondaryText.Text = value; - m_secondaryText.ResizeBasedOnText(); - } - } - - public Texture2D IconGraphic - { - get { return m_gfxItem; } - set { m_gfxItem = value; } - } - - public event EventHandler OnRightClick; - public event EventHandler OnLeftClick; - - protected XNALabel m_primaryText; - protected XNALabel m_secondaryText; - - private readonly Texture2D m_gfxPadThing; - private Texture2D m_gfxItem; - private readonly Texture2D m_backgroundColor; - private bool m_drawBackground; - private bool m_rightClicked; - - public enum ListItemStyle - { - Small, - Large - } - - public OldListDialogItem(EODialogBase parent, ListItemStyle style, int listIndex = -1) - { - DrawLocation = new Vector2(17, DrawLocation.Y); //the base X coordinate is 17 - this can be adjusted with OffsetX property - - Style = style; - if (listIndex >= 0) - Index = listIndex; - - _setSize(232, Style == ListItemStyle.Large ? 36 : 13); - - int colorFactor = Style == ListItemStyle.Large ? 0xc8 : 0xb4; - - m_primaryText = new XNALabel(new Rectangle(Style == ListItemStyle.Large ? 56 : 2, Style == ListItemStyle.Large ? 5 : 0, 1, 1), Constants.FontSize08pt5) - { - AutoSize = false, - BackColor = Color.Transparent, - ForeColor = Color.FromNonPremultiplied(colorFactor, colorFactor, colorFactor, 0xff), - TextAlign = LabelAlignment.TopLeft, - Text = " " - }; - m_primaryText.ResizeBasedOnText(); - - if (Style == ListItemStyle.Large) - { - m_secondaryText = new XNALabel(new Rectangle(56, 20, 1, 1), Constants.FontSize08pt5) - { - AutoSize = true, - BackColor = m_primaryText.BackColor, - ForeColor = m_primaryText.ForeColor, - Text = " " - }; - m_secondaryText.ResizeBasedOnText(); - - m_gfxPadThing = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.MapTiles, 0, true); - ShowItemBackGround = true; - } - m_backgroundColor = new Texture2D(Game.GraphicsDevice, 1, 1); - m_backgroundColor.SetData(new[] { Color.FromNonPremultiplied(0xff, 0xff, 0xff, 64) }); - - SetParent(parent); - m_primaryText.SetParent(this); - if (Style == ListItemStyle.Large) - { - m_secondaryText.SetParent(this); - } - OffsetY = Style == ListItemStyle.Large ? 25 : 45; - } - - /// - /// turns the primary text into a link that performs the specified action. When Style is Small, the entire item becomes clickable. - /// - /// The action to perform - public void SetPrimaryTextLink(Action onClickAction) - { - if (m_primaryText == null) - return; - XNALabel oldText = m_primaryText; - m_primaryText = new XNAHyperLink(oldText.DrawArea, Constants.FontSize08pt5) - { - AutoSize = false, - BackColor = oldText.BackColor, - ForeColor = oldText.ForeColor, - HighlightColor = oldText.ForeColor, - Text = oldText.Text, - Underline = true - }; - m_primaryText.ResizeBasedOnText(); - ((XNAHyperLink)m_primaryText).OnClick += (o, e) => onClickAction(); - m_primaryText.SetParent(this); - oldText.Close(); - - if (Style == ListItemStyle.Small) - OnLeftClick += (o, e) => onClickAction(); - } - - //turns the subtext into a link that performs the specified action - public void SetSubtextLink(Action onClickAction) - { - if (m_secondaryText == null || Style == ListItemStyle.Small) - return; - XNALabel oldText = m_secondaryText; - m_secondaryText = new XNAHyperLink(oldText.DrawArea, Constants.FontSize08pt5) - { - AutoSize = false, - BackColor = oldText.BackColor, - ForeColor = oldText.ForeColor, - HighlightColor = oldText.ForeColor, - Text = oldText.Text, - Underline = true - }; - m_secondaryText.ResizeBasedOnText(); - ((XNAHyperLink)m_secondaryText).OnClick += (o, e) => onClickAction(); - m_secondaryText.SetParent(this); - oldText.Close(); - } - - public override void Update(GameTime gameTime) - { - if (!Visible || !Game.IsActive) return; - - lock (disposingLock) - { - if (m_disposing) return; - - MouseState ms = Mouse.GetState(); - - if (MouseOver && MouseOverPreviously) - { - m_drawBackground = true; - if (ms.RightButton == ButtonState.Pressed) - { - m_rightClicked = true; - } - - if (m_rightClicked && ms.RightButton == ButtonState.Released && OnRightClick != null) - { - OnRightClick(this, null); - m_rightClicked = false; - } - else if (PreviousMouseState.LeftButton == ButtonState.Pressed && ms.LeftButton == ButtonState.Released && - OnLeftClick != null) - { - //If the sub text is a hyperlink and the mouse is over it do the click event for the sub text and not for this item - if (m_secondaryText is XNAHyperLink && m_secondaryText.MouseOver) - ((XNAHyperLink)m_secondaryText).Click(); - else - OnLeftClick(this, null); - } - } - else - { - m_drawBackground = false; - } - - base.Update(gameTime); - } - } - - public override void Draw(GameTime gameTime) - { - if (!Visible) return; - - lock (disposingLock) - { - if (m_disposing) - return; - SpriteBatch.Begin(); - if (m_drawBackground) - { - //Rectangle backgroundRect = new Rectangle(DrawAreaWithOffset.X + OffsetX, DrawAreaWithOffset.Y + OffsetY, DrawAreaWithOffset.Width, DrawAreaWithOffset.Height); - SpriteBatch.Draw(m_backgroundColor, DrawAreaWithOffset, Color.White); - } - if (Style == ListItemStyle.Large) - { - //The area for showing these is 64x36px: center the icon and background accordingly - Vector2 offset = new Vector2(xOff + OffsetX + 14/*not sure of the significance of this offset*/, yOff + OffsetY + 36 * Index); - if (ShowItemBackGround) - SpriteBatch.Draw(m_gfxPadThing, new Vector2(offset.X + ((64 - m_gfxPadThing.Width) / 2f), offset.Y + (36 - m_gfxPadThing.Height) / 2f), Color.White); - if (m_gfxItem != null) - SpriteBatch.Draw(m_gfxItem, - new Vector2((float)Math.Round(offset.X + ((64 - m_gfxItem.Width) / 2f)), - (float)Math.Round(offset.Y + (36 - m_gfxItem.Height) / 2f)), - Color.White); - } - SpriteBatch.End(); - base.Draw(gameTime); - } - } - - public void SetActive() - { - m_primaryText.ForeColor = Color.FromNonPremultiplied(0xf0, 0xf0, 0xf0, 0xff); - } - - protected override void Dispose(bool disposing) - { - lock (disposingLock) - { - m_disposing = true; - if (disposing) - { - m_backgroundColor.Dispose(); - } - } - - base.Dispose(disposing); - } - } -} diff --git a/EndlessClient/Dialogs/Old/TradeDialog.cs b/EndlessClient/Dialogs/Old/TradeDialog.cs deleted file mode 100644 index a5e25f154..000000000 --- a/EndlessClient/Dialogs/Old/TradeDialog.cs +++ /dev/null @@ -1,445 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using EndlessClient.Dialogs.Services; -using EndlessClient.Old; -using EndlessClient.UIControls; -using EOLib; -using EOLib.Domain.Character; -using EOLib.Graphics; -using EOLib.IO; -using EOLib.Localization; -using EOLib.Net.API; -using Microsoft.Xna.Framework; -using XNAControls.Old; - -namespace EndlessClient.Dialogs.Old -{ - public class TradeDialog : EODialogBase - { - //dialog has: - // - 2 lists of items on each side - // - 2 scroll bars (1 each side) - // - 2 name labels (1 each side) - // - 2 agree/trading labels (1 each side) - // - Ok/cancel buttons - - private short m_leftPlayerID, m_rightPlayerID; - private string m_leftNameStr, m_rightNameStr; - private readonly XNALabel m_leftPlayerName, m_rightPlayerName; - private readonly XNALabel m_leftPlayerStatus, m_rightPlayerStatus; - private readonly OldScrollBar m_leftScroll, m_rightScroll; - private bool m_leftAgrees, m_rightAgrees; - private readonly List m_leftItems, m_rightItems; - - private readonly OldCharacter m_main; //local reference - - private int m_recentPartnerRemoves; - - public static TradeDialog Instance { get; private set; } - - public bool MainPlayerAgrees => (m_main.ID == m_leftPlayerID && m_leftAgrees) || - (m_main.ID == m_rightPlayerID && m_rightAgrees); - - public TradeDialog(/*PacketAPI apiHandle*/) - : base(null) - { - bgTexture = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 50); - _setSize(bgTexture.Width, bgTexture.Height); - - Instance = this; - DialogClosing += (sender, args) => Instance = null; - m_main = OldWorld.Instance.MainPlayer.ActiveCharacter; - - m_leftItems = new List(); - m_rightItems = new List(); - - m_leftPlayerID = 0; - m_rightPlayerID = 0; - - m_leftPlayerName = new XNALabel(new Rectangle(20, 14, 166, 20), Constants.FontSize08pt5) - { - AutoSize = false, - TextAlign = LabelAlignment.MiddleLeft, - ForeColor = ColorConstants.LightGrayText - }; - m_leftPlayerName.SetParent(this); - m_rightPlayerName = new XNALabel(new Rectangle(285, 14, 166, 20), Constants.FontSize08pt5) - { - AutoSize = false, - TextAlign = LabelAlignment.MiddleLeft, - ForeColor = ColorConstants.LightGrayText - }; - m_rightPlayerName.SetParent(this); - m_leftPlayerStatus = new XNALabel(new Rectangle(195, 14, 79, 20), Constants.FontSize08pt5) - { - AutoSize = false, - TextAlign = LabelAlignment.MiddleLeft, - Text = OldWorld.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING), - ForeColor = ColorConstants.LightGrayText - }; - m_leftPlayerStatus.SetParent(this); - m_rightPlayerStatus = new XNALabel(new Rectangle(462, 14, 79, 20), Constants.FontSize08pt5) - { - AutoSize = false, - TextAlign = LabelAlignment.MiddleLeft, - Text = OldWorld.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING), - ForeColor = ColorConstants.LightGrayText - }; - m_rightPlayerStatus.SetParent(this); - - m_leftScroll = new OldScrollBar(this, new Vector2(252, 44), new Vector2(16, 199), ScrollBarColors.LightOnMed) { LinesToRender = 5 }; - m_rightScroll = new OldScrollBar(this, new Vector2(518, 44), new Vector2(16, 199), ScrollBarColors.LightOnMed) { LinesToRender = 5 }; - - //BUTTONSSSS - XNAButton ok = new XNAButton(smallButtonSheet, new Vector2(356, 252), _getSmallButtonOut(SmallButton.Ok), - _getSmallButtonOver(SmallButton.Ok)); - ok.OnClick += _buttonOkClicked; - ok.SetParent(this); - dlgButtons.Add(ok); - XNAButton cancel = new XNAButton(smallButtonSheet, new Vector2(449, 252), _getSmallButtonOut(SmallButton.Cancel), - _getSmallButtonOver(SmallButton.Cancel)); - cancel.OnClick += _buttonCancelClicked; - cancel.SetParent(this); - dlgButtons.Add(cancel); - - Timer localTimer = new Timer(state => - { - if (m_recentPartnerRemoves > 0) - m_recentPartnerRemoves--; - }, null, 0, 5000); - - DialogClosing += (o, e) => - { - if (e.Result == XNADialogResult.Cancel) - { - //if (!m_api.TradeClose()) - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - //((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_ABORTED); - } - - localTimer.Dispose(); - }; - - Center(Game.GraphicsDevice); - DrawLocation = new Vector2(DrawLocation.X, 30); - endConstructor(false); - } - - public void InitPlayerInfo(short player1, string player1Name, short player2, string player2Name) - { - m_leftPlayerID = player1; - m_rightPlayerID = player2; - m_leftNameStr = m_leftPlayerName.Text = char.ToUpper(player1Name[0]) + player1Name.Substring(1); - m_rightNameStr = m_rightPlayerName.Text = char.ToUpper(player2Name[0]) + player2Name.Substring(1); - } - - public void SetPlayerItems(short playerID, List items) - { - int xOffset; - List collectionRef; - OldScrollBar scrollRef; - - if (playerID == m_leftPlayerID) - { - collectionRef = m_leftItems; - scrollRef = m_leftScroll; - xOffset = -3; - m_leftPlayerName.Text = $"{m_leftNameStr} {(items.Count > 0 ? "[" + items.Count + "]" : "")}"; - - if (m_leftAgrees) - { - m_leftAgrees = false; - m_leftPlayerStatus.Text = OldWorld.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING); - } - - //left player is NOT main, and right player (ie main) agrees, and the item count is different for left player - //cancel the offer for the main player since the other player changed the offer - if (m_main.ID != playerID && m_rightAgrees && collectionRef.Count != items.Count) - { - m_rightAgrees = false; - m_rightPlayerStatus.Text = OldWorld.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING); - EOMessageBox.Show(DialogResourceID.TRADE_ABORTED_OFFER_CHANGED, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - //((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_TRADE_OTHER_PLAYER_CHANGED_OFFER); - } - } - else if (playerID == m_rightPlayerID) - { - collectionRef = m_rightItems; - scrollRef = m_rightScroll; - xOffset = 263; - m_rightPlayerName.Text = $"{m_rightNameStr} {(items.Count > 0 ? "[" + items.Count + "]" : "")}"; - - if (m_rightAgrees) - { - m_rightAgrees = false; - m_rightPlayerStatus.Text = OldWorld.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING); - } - - //right player is NOT main, and left player (ie main) agrees, and the item count is different for right player - //cancel the offer for the main player since the other player changed the offer - if (m_main.ID != playerID && m_leftAgrees && collectionRef.Count != items.Count) - { - m_leftAgrees = false; - m_leftPlayerStatus.Text = OldWorld.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING); - EOMessageBox.Show(DialogResourceID.TRADE_ABORTED_OFFER_CHANGED, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - //((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_TRADE_OTHER_PLAYER_CHANGED_OFFER); - } - } - else - throw new ArgumentException("Invalid Player ID for trade session!", nameof(playerID)); - - if (m_main.ID != playerID && collectionRef.Count > items.Count) - m_recentPartnerRemoves++; - if (m_recentPartnerRemoves == 3) - { - EOMessageBox.Show(DialogResourceID.TRADE_OTHER_PLAYER_TRICK_YOU, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - m_recentPartnerRemoves = -1000; //this will prevent the message from showing more than once (I'm too lazy to find something more elegant) - } - - foreach (var oldItem in collectionRef) oldItem.Close(); - collectionRef.Clear(); - - int index = 0; - foreach (InventoryItem item in items) - { - int localID = item.ItemID; - - var rec = OldWorld.Instance.EIF[item.ItemID]; - string secondary = - $"x {item.Amount} {(rec.Type == ItemType.Armor ? "(" + (rec.Gender == 0 ? OldWorld.GetString(EOResourceID.FEMALE) : OldWorld.GetString(EOResourceID.MALE)) + ")" : "")}"; - - int gfxNum = item.ItemID == 1 - ? 269 + 2 * (item.Amount >= 100000 ? 4 : (item.Amount >= 10000 ? 3 : (item.Amount >= 100 ? 2 : (item.Amount >= 2 ? 1 : 0)))) - : 2 * rec.Graphic - 1; - - var nextItem = new OldListDialogItem(this, OldListDialogItem.ListItemStyle.Large, index++) - { - Text = rec.Name, - SubText = secondary, - IconGraphic = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.Items, gfxNum, true), - ID = item.ItemID, - Amount = item.Amount, - OffsetX = xOffset, - OffsetY = 46 - }; - if (playerID == m_main.ID) - nextItem.OnRightClick += (sender, args) => _removeItem(localID); - collectionRef.Add(nextItem); - } - - scrollRef.UpdateDimensions(collectionRef.Count); - } - - public void SetPlayerAgree(bool isMain, bool agrees) - { - short playerID = isMain ? (short)m_main.ID : (m_leftPlayerID == m_main.ID ? m_rightPlayerID : m_leftPlayerID); - if (playerID == m_leftPlayerID) - { - //if (agrees && !m_leftAgrees) - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, - // isMain ? EOResourceID.STATUS_LABEL_TRADE_YOU_ACCEPT : EOResourceID.STATUS_LABEL_TRADE_OTHER_ACCEPT); - //else if (!agrees && m_leftAgrees) - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, - // isMain ? EOResourceID.STATUS_LABEL_TRADE_YOU_CANCEL : EOResourceID.STATUS_LABEL_TRADE_OTHER_CANCEL); - - m_leftAgrees = agrees; - m_leftPlayerStatus.Text = - OldWorld.GetString(agrees ? EOResourceID.DIALOG_TRADE_WORD_AGREE : EOResourceID.DIALOG_TRADE_WORD_TRADING); - } - else if (playerID == m_rightPlayerID) - { - //if (agrees && !m_rightAgrees) - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, - // isMain ? EOResourceID.STATUS_LABEL_TRADE_YOU_ACCEPT : EOResourceID.STATUS_LABEL_TRADE_OTHER_ACCEPT); - //else if (!agrees && m_rightAgrees) - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, - // isMain ? EOResourceID.STATUS_LABEL_TRADE_YOU_CANCEL : EOResourceID.STATUS_LABEL_TRADE_OTHER_CANCEL); - - m_rightAgrees = agrees; - m_rightPlayerStatus.Text = - OldWorld.GetString(agrees ? EOResourceID.DIALOG_TRADE_WORD_AGREE : EOResourceID.DIALOG_TRADE_WORD_TRADING); - } - else - throw new ArgumentException("Invalid Player ID for trade session!"); - } - - public void CompleteTrade(short p1, List p1items, short p2, List p2items) - { - List mainCollection, otherCollection; - if (p1 == m_main.ID) - { - mainCollection = p1items; - otherCollection = p2items; - } - else if (p2 == m_main.ID) - { - mainCollection = p2items; - otherCollection = p1items; - } - else - 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; - //} - m_main.Weight += (byte)weightDelta; - //((EOGame)Game).Hud.RefreshStats(); - - Close(null, XNADialogResult.NO_BUTTON_PRESSED); - EOMessageBox.Show(DialogResourceID.TRADE_SUCCESS, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - } - - private void _buttonOkClicked(object sender, EventArgs e) - { - if (m_leftPlayerID == m_main.ID) - { - if (m_leftAgrees) return; //main already agrees - } - else if (m_rightPlayerID == m_main.ID) - { - if (m_rightAgrees) return; //main already agrees - } - else - throw new InvalidOperationException("Invalid Player ID for trade session!"); - - if (m_leftItems.Count == 0 || m_rightItems.Count == 0) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRADE_BOTH_PLAYERS_OFFER_ONE_ITEM), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), EODialogButtons.Ok, - EOMessageBoxStyle.SmallDialogSmallHeader); - //((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.DIALOG_TRADE_BOTH_PLAYERS_OFFER_ONE_ITEM); - return; - } - - List mainCollection = m_main.ID == m_leftPlayerID ? m_leftItems : m_rightItems; - 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; - //} - - //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); - weightDelta = mainCollection.Aggregate(weightDelta, (current, itemRef) => current - OldWorld.Instance.EIF[itemRef.ID].Weight * itemRef.Amount); - if (weightDelta + m_main.Weight > m_main.MaxWeight) - { - EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_WEIGHT), - OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - return; - } - - EOMessageBox.Show(DialogResourceID.TRADE_DO_YOU_AGREE, EODialogButtons.OkCancel, EOMessageBoxStyle.SmallDialogSmallHeader, - (o, dlgArgs) => - { - //if (dlgArgs.Result == XNADialogResult.OK && !m_api.TradeAgree(true)) - //{ - // Close(null, XNADialogResult.NO_BUTTON_PRESSED); - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - //} - }); - } - - private void _buttonCancelClicked(object sender, EventArgs e) - { - if (m_main.ID == m_leftPlayerID) - { - if (!m_leftAgrees) //just quit - Close(dlgButtons[1], XNADialogResult.Cancel); - //else if (!m_api.TradeAgree(false)) //cancel agreement - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } - else if (m_main.ID == m_rightPlayerID) - { - if (!m_rightAgrees) //just quit - Close(dlgButtons[1], XNADialogResult.Cancel); - //else if (!m_api.TradeAgree(false)) - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } - else - throw new InvalidOperationException("Invalid player ID for trade session!"); - } - - //item right-click event handler - private void _removeItem(int id) - { - //if (!m_api.TradeRemoveItem((short)id)) - //{ - // Close(null, XNADialogResult.NO_BUTTON_PRESSED); - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - //} - } - - public override void Update(GameTime gt) - { - //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 }; - List> lists = new List> { m_leftItems, m_rightItems }; - for (int ndx = 0; ndx < 2; ++ndx) - { - var list = lists[ndx]; - var scroll = scrollBars[ndx]; - - //which items should we render? - if (list.Count > scroll.LinesToRender) - { - for (int i = 0; i < list.Count; ++i) - { - OldListDialogItem curr = list[i]; - if (i < scroll.ScrollOffset) - { - curr.Visible = false; - continue; - } - - if (i < scroll.LinesToRender + scroll.ScrollOffset) - { - curr.Visible = true; - curr.Index = i - scroll.ScrollOffset; - } - else - { - curr.Visible = false; - } - } - } - else if (list.Any(_item => !_item.Visible)) - list.ForEach(_item => _item.Visible = true); //all items visible if less than # lines to render - } - - base.Update(gt); - } - - public void Close(XNADialogResult result) - { - Close(null, result); - Close(); - } - } -} diff --git a/EndlessClient/Dialogs/TradeDialog.cs b/EndlessClient/Dialogs/TradeDialog.cs index 682b5c6c5..c47c969b8 100644 --- a/EndlessClient/Dialogs/TradeDialog.cs +++ b/EndlessClient/Dialogs/TradeDialog.cs @@ -1,12 +1,19 @@ -using EndlessClient.Content; +using EndlessClient.Dialogs.Factories; using EndlessClient.Dialogs.Services; +using EndlessClient.HUD; +using EndlessClient.HUD.Inventory; +using EndlessClient.HUD.Panels; +using EndlessClient.Rendering.Map; using EndlessClient.UIControls; using EOLib; using EOLib.Domain.Character; using EOLib.Domain.Trade; using EOLib.Graphics; +using EOLib.IO; +using EOLib.IO.Repositories; using EOLib.Localization; using Microsoft.Xna.Framework; +using Optional.Collections; using System; using System.Collections.Generic; using System.Diagnostics; @@ -17,9 +24,16 @@ namespace EndlessClient.Dialogs { public class TradeDialog : BaseEODialog { + private readonly ITradeActions _tradeActions; private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IStatusLabelSetter _statusLabelSetter; + private readonly IInventorySpaceValidator _inventorySpaceValidator; private readonly ITradeProvider _tradeProvider; private readonly ICharacterProvider _characterProvider; + private readonly IEIFFileProvider _eifFileProvider; + private readonly IMapItemGraphicProvider _mapItemGraphicProvider; + private readonly InventoryPanel _inventoryPanel; private readonly IXNALabel _leftPlayerName, _rightPlayerName; private readonly IXNALabel _leftPlayerStatus, _rightPlayerStatus; @@ -39,16 +53,29 @@ public class TradeDialog : BaseEODialog private Stopwatch _partnerItemChangeTick; public TradeDialog(INativeGraphicsManager nativeGraphicsManager, + ITradeActions tradeActions, ILocalizedStringFinder localizedStringFinder, IEODialogButtonService dialogButtonService, + IEOMessageBoxFactory messageBoxFactory, + IStatusLabelSetter statusLabelSetter, + IInventorySpaceValidator inventorySpaceValidator, ITradeProvider tradeProvider, - ICharacterProvider characterProvider) + ICharacterProvider characterProvider, + IEIFFileProvider eifFileProvider, + IMapItemGraphicProvider mapItemGraphicProvider, + InventoryPanel inventoryPanel) : base(nativeGraphicsManager, isInGame: true) { + _tradeActions = tradeActions; _localizedStringFinder = localizedStringFinder; + _messageBoxFactory = messageBoxFactory; + _statusLabelSetter = statusLabelSetter; + _inventorySpaceValidator = inventorySpaceValidator; _tradeProvider = tradeProvider; _characterProvider = characterProvider; - + _eifFileProvider = eifFileProvider; + _mapItemGraphicProvider = mapItemGraphicProvider; + _inventoryPanel = inventoryPanel; BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 50); _leftPlayerName = new XNALabel(Constants.FontSize08pt5) @@ -131,11 +158,14 @@ public override void Initialize() protected override void OnUpdateControl(GameTime gameTime) { + var updateItemVisibility = false; + if (_tradeProvider.PlayerOneOffer != null && !_tradeProvider.PlayerOneOffer.Equals(_leftOffer)) { UpdateOffer(_tradeProvider.PlayerOneOffer, _leftOffer, _leftPlayerName, _leftPlayerStatus, _leftItems, -3); _leftOffer = _tradeProvider.PlayerOneOffer; _leftScroll.UpdateDimensions(_leftOffer.Items.Count); + updateItemVisibility = true; } if (_tradeProvider.PlayerTwoOffer != null && !_tradeProvider.PlayerTwoOffer.Equals(_rightOffer)) @@ -143,17 +173,18 @@ protected override void OnUpdateControl(GameTime gameTime) UpdateOffer(_tradeProvider.PlayerTwoOffer, _rightOffer, _rightPlayerName, _rightPlayerStatus, _rightItems, 263); _rightOffer = _tradeProvider.PlayerTwoOffer; _rightScroll.UpdateDimensions(_rightOffer.Items.Count); + updateItemVisibility = true; } - if (_leftScrollOffset != _leftScroll.ScrollOffset) + if (updateItemVisibility || _leftScrollOffset != _leftScroll.ScrollOffset) { - // todo: update left list item display + UpdateItemScrollIndexes(_leftScroll, _leftItems); _leftScrollOffset = _leftScroll.ScrollOffset; } - if (_rightScrollOffset != _rightScroll.ScrollOffset) + if (updateItemVisibility || _rightScrollOffset != _rightScroll.ScrollOffset) { - // todo: update right list item display + UpdateItemScrollIndexes(_rightScroll, _rightItems); _rightScrollOffset = _rightScroll.ScrollOffset; } @@ -163,6 +194,8 @@ protected override void OnUpdateControl(GameTime gameTime) _partnerItemChangeTick = Stopwatch.StartNew(); } + SuppressClickDragEvent(!_inventoryPanel.NoItemsDragging()); + base.OnUpdateControl(gameTime); } @@ -183,12 +216,20 @@ protected override void OnUpdateControl(GameTime gameTime) ? _localizedStringFinder.GetString(EOResourceID.DIALOG_TRADE_WORD_AGREE) : _localizedStringFinder.GetString(EOResourceID.DIALOG_TRADE_WORD_TRADING); - //if (agrees && !m_leftAgrees) - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, - // isMain ? EOResourceID.STATUS_LABEL_TRADE_YOU_ACCEPT : EOResourceID.STATUS_LABEL_TRADE_OTHER_ACCEPT); - //else if (!agrees && m_leftAgrees) - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, - // isMain ? EOResourceID.STATUS_LABEL_TRADE_YOU_CANCEL : EOResourceID.STATUS_LABEL_TRADE_OTHER_CANCEL); + if (actualOffer.Agrees) + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, + actualOffer.PlayerID == _characterProvider.MainCharacter.ID + ? EOResourceID.STATUS_LABEL_TRADE_YOU_ACCEPT + : EOResourceID.STATUS_LABEL_TRADE_OTHER_ACCEPT); + } + else + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, + actualOffer.PlayerID == _characterProvider.MainCharacter.ID + ? EOResourceID.STATUS_LABEL_TRADE_YOU_CANCEL + : EOResourceID.STATUS_LABEL_TRADE_OTHER_CANCEL); + } } if (!actualOffer.Items.ToHashSet().SetEquals(cachedOffer.Items)) @@ -198,12 +239,34 @@ protected override void OnUpdateControl(GameTime gameTime) foreach (var addedItem in added) { - //var newListItem = new ListDialogItem(this, ) + var itemRec = _eifFileProvider.EIFFile[addedItem.ItemID]; + var subText = $"x {addedItem.Amount} {(itemRec.Type == ItemType.Armor ? $"({_localizedStringFinder.GetString(itemRec.Gender == 0 ? EOResourceID.FEMALE : EOResourceID.MALE)})" : string.Empty)}"; + + var newListItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large) + { + Data = addedItem, + PrimaryText = itemRec.Name, + SubText = subText, + IconGraphic = _mapItemGraphicProvider.GetItemGraphic(addedItem.ItemID, addedItem.Amount), + OffsetX = listitemOffset, + OffsetY = 46 + }; + + if (actualOffer.PlayerID == _characterProvider.MainCharacter.ID) + newListItem.RightClick += (_, _) => _tradeActions.RemoveItemFromOffer((short)itemRec.ID); + + newListItem.SetParentControl(this); + listItems.Add(newListItem); } foreach (var removedItem in removed) { - + listItems.SingleOrNone(y => ((InventoryItem)y.Data).ItemID == removedItem.ItemID) + .MatchSome(listItem => + { + listItems.Remove(listItem); + listItem.Dispose(); + }); } if (actualOffer.PlayerID != _characterProvider.MainCharacter.ID) @@ -213,24 +276,98 @@ protected override void OnUpdateControl(GameTime gameTime) if (_recentPartnerItemChanges == 3) { - //EOMessageBox.Show(DialogResourceID.TRADE_OTHER_PLAYER_TRICK_YOU, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - //m_recentPartnerRemoves = -1000; //this will prevent the message from showing more than once (I'm too lazy to find something more elegant) + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.TRADE_OTHER_PLAYER_TRICK_YOU); + dlg.ShowDialog(); + + // this will prevent the message from showing more than once per trade (I'm too lazy to find something more elegant) + _recentPartnerItemChanges = -1000; } else { - //EOMessageBox.Show(DialogResourceID.TRADE_ABORTED_OFFER_CHANGED, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - //((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_TRADE_OTHER_PLAYER_CHANGED_OFFER); + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.TRADE_ABORTED_OFFER_CHANGED); + dlg.ShowDialog(); + + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_TRADE_OTHER_PLAYER_CHANGED_OFFER); } } } } + private void UpdateItemScrollIndexes(ScrollBar scrollBar, List items) + { + var scrollOffset = items.Count > scrollBar.LinesToRender ? scrollBar.ScrollOffset : 0; + + for (int i = 0; i < items.Count; i++) + { + items[i].Visible = i >= scrollOffset && i <= scrollBar.LinesToRender + scrollOffset; + items[i].Index = i - scrollOffset; + } + } + private void OkButtonClicked(object sender, EventArgs e) { + var (offer, partnerOffer) = _leftOffer.PlayerID == _characterProvider.MainCharacter.ID + ? (_leftOffer, _rightOffer) + : (_rightOffer, _leftOffer); + + if (offer.Agrees) + return; + + if (_leftOffer.Items.Count == 0 || _rightOffer.Items.Count == 0) + { + var dlg = _messageBoxFactory.CreateMessageBox(EOResourceID.DIALOG_TRADE_BOTH_PLAYERS_OFFER_ONE_ITEM, EOResourceID.STATUS_LABEL_TYPE_WARNING); + dlg.ShowDialog(); + return; + } + + if (!_inventorySpaceValidator.ItemsFit(offer.Items, partnerOffer.Items)) + { + var dlg = _messageBoxFactory.CreateMessageBox(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE, EOResourceID.STATUS_LABEL_TYPE_WARNING); + dlg.ShowDialog(); + return; + } + + var partnerItemWeight = partnerOffer.Items + .Select(x => _eifFileProvider.EIFFile[x.ItemID].Weight * x.Amount) + .Aggregate((a, b) => a + b); + var offerItemWeight = offer.Items + .Select(x => _eifFileProvider.EIFFile[x.ItemID].Weight * x.Amount) + .Aggregate((a, b) => a + b); + + var stats = _characterProvider.MainCharacter.Stats; + if (stats[CharacterStat.Weight] - offerItemWeight + partnerItemWeight > stats[CharacterStat.MaxWeight]) + { + var dlg = _messageBoxFactory.CreateMessageBox(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_WEIGHT, EOResourceID.STATUS_LABEL_TYPE_WARNING); + dlg.ShowDialog(); + return; + } + + var finalCheckDlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.TRADE_DO_YOU_AGREE, EODialogButtons.OkCancel); + finalCheckDlg.DialogClosing += (o, e) => + { + if (e.Result == XNADialogResult.OK) + { + _tradeActions.AgreeToTrade(true); + } + }; + finalCheckDlg.ShowDialog(); } private void CancelButtonClicked(object sender, EventArgs e) { + var offer = _leftOffer.PlayerID == _characterProvider.MainCharacter.ID + ? _leftOffer + : _rightOffer; + + if (!offer.Agrees) + { + _tradeActions.CancelTrade(); + Close(XNADialogResult.Cancel); + } + else + { + _tradeActions.AgreeToTrade(false); + } } } } diff --git a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs index 42a30ad6f..54766b72c 100644 --- a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs +++ b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs @@ -5,7 +5,9 @@ using EOLib.IO.Map; using EOLib.IO.Repositories; using Optional; +using System.Collections.Generic; using System.Linq; +using System.Windows.Documents; namespace EndlessClient.HUD.Inventory { @@ -38,6 +40,11 @@ public bool ItemFits(int itemId) return _characterInventoryProvider.ItemInventory.Any(x => x.ItemID == itemId) || ItemFits(_eifFileProvider.EIFFile[itemId].Size); } + public bool ItemsFit(IReadOnlyList outItems, IReadOnlyList inItems) + { + return true; + } + private bool ItemFits(ItemSize itemSize) { return _inventoryService @@ -52,6 +59,6 @@ public interface IInventorySpaceValidator bool ItemFits(int itemId); - // todo: need "ItemsFit" method for trading + bool ItemsFit(IReadOnlyList outItems, IReadOnlyList inItems); } } diff --git a/EndlessClient/Old/OldWorld.cs b/EndlessClient/Old/OldWorld.cs index 2267d76bd..05ff2597b 100644 --- a/EndlessClient/Old/OldWorld.cs +++ b/EndlessClient/Old/OldWorld.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using EndlessClient.Dialogs; -using EndlessClient.Dialogs.Old; using EndlessClient.GameExecution; using EndlessClient.Rendering; using EOLib.Config; diff --git a/EndlessClient/Rendering/Map/MapItemGraphicProvider.cs b/EndlessClient/Rendering/Map/MapItemGraphicProvider.cs index 4bdf33e6a..62a0ec038 100644 --- a/EndlessClient/Rendering/Map/MapItemGraphicProvider.cs +++ b/EndlessClient/Rendering/Map/MapItemGraphicProvider.cs @@ -6,7 +6,7 @@ namespace EndlessClient.Rendering.Map { - [MappedType(BaseType = typeof(IMapItemGraphicProvider), IsSingleton = true)] + [AutoMappedType] public class MapItemGraphicProvider : IMapItemGraphicProvider { private readonly INativeGraphicsManager _nativeGraphicsManager; diff --git a/EndlessClient/Rendering/OldNPCRenderer.cs b/EndlessClient/Rendering/OldNPCRenderer.cs index 9f5d4e9ea..088461b3b 100644 --- a/EndlessClient/Rendering/OldNPCRenderer.cs +++ b/EndlessClient/Rendering/OldNPCRenderer.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using EndlessClient.Dialogs.Old; using EndlessClient.Old; using EndlessClient.Rendering.Sprites; using EOLib; From fdd97b28e5ce6215936006a7b94592c4edf01768 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 15 Sep 2022 19:56:16 -0700 Subject: [PATCH 09/17] Implement InventorySpaceValidator.ItemsFit --- EOLib.IO/Map/Matrix.cs | 2 +- .../HUD/Inventory/InventorySlotRepository.cs | 10 +++++ .../HUD/Inventory/InventorySpaceValidator.cs | 26 +++++++++++++ EndlessClient/HUD/Panels/InventoryPanel.cs | 37 +------------------ 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/EOLib.IO/Map/Matrix.cs b/EOLib.IO/Map/Matrix.cs index 553b51a9c..bfb05f807 100644 --- a/EOLib.IO/Map/Matrix.cs +++ b/EOLib.IO/Map/Matrix.cs @@ -30,7 +30,7 @@ public Matrix(int rows, int cols, T defaultValue) Fill(defaultValue); } - public Matrix(Matrix other) + public Matrix(IReadOnlyMatrix other) : this(new T[other.Rows, other.Cols]) { for (int row = 0; row < other.Rows; ++row) diff --git a/EndlessClient/HUD/Inventory/InventorySlotRepository.cs b/EndlessClient/HUD/Inventory/InventorySlotRepository.cs index 1f1b6811a..b3da1b47a 100644 --- a/EndlessClient/HUD/Inventory/InventorySlotRepository.cs +++ b/EndlessClient/HUD/Inventory/InventorySlotRepository.cs @@ -2,17 +2,22 @@ using EndlessClient.HUD.Panels; using EOLib; using EOLib.IO.Map; +using System.Collections.Generic; namespace EndlessClient.HUD.Inventory { public interface IInventorySlotRepository { Matrix FilledSlots { get; set; } + + Dictionary SlotMap { get; set; } } public interface IInventorySlotProvider { IReadOnlyMatrix FilledSlots { get; } + + IReadOnlyDictionary SlotMap { get; } } [AutoMappedType(IsSingleton = true)] @@ -20,8 +25,12 @@ public class InventorySlotRepository : IInventorySlotProvider, IInventorySlotRep { public Matrix FilledSlots { get; set; } + public Dictionary SlotMap { get; set; } + IReadOnlyMatrix IInventorySlotProvider.FilledSlots => FilledSlots; + IReadOnlyDictionary IInventorySlotProvider.SlotMap => SlotMap; + public InventorySlotRepository() { ResetState(); @@ -30,6 +39,7 @@ public InventorySlotRepository() public void ResetState() { FilledSlots = new Matrix(InventoryPanel.InventoryRows, InventoryPanel.InventoryRowSlots, false); + SlotMap = new Dictionary(); } } } diff --git a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs index 54766b72c..a69af1f8a 100644 --- a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs +++ b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs @@ -5,6 +5,7 @@ using EOLib.IO.Map; using EOLib.IO.Repositories; using Optional; +using Optional.Collections; using System.Collections.Generic; using System.Linq; using System.Windows.Documents; @@ -42,6 +43,31 @@ public bool ItemFits(int itemId) public bool ItemsFit(IReadOnlyList outItems, IReadOnlyList inItems) { + var slotsCopy = new Matrix(_inventorySlotProvider.FilledSlots); + + foreach (var item in outItems) + { + var itemData = _eifFileProvider.EIFFile[item.ItemID]; + _inventorySlotProvider.SlotMap.SingleOrNone(x => x.Value == item.ItemID) + .Map(x => x.Key) + .MatchSome(x => _inventoryService.ClearSlots(slotsCopy, x, itemData.Size)); + } + + foreach (var item in inItems) + { + var itemData = _eifFileProvider.EIFFile[item.ItemID]; + var itemFits = _inventoryService + .GetNextOpenSlot(slotsCopy, itemData.Size, Option.None()) + .Match(some: slot => + { + _inventoryService.SetSlots(slotsCopy, slot, itemData.Size); + return true; + }, + none: () => false); + if (!itemFits) + return false; + } + return true; } diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index 7c89b0b5b..c87fd8238 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -50,7 +50,6 @@ public class InventoryPanel : XNAPanel, IHudPanel private readonly IActiveDialogProvider _activeDialogProvider; private readonly ISfxPlayer _sfxPlayer; - private readonly Dictionary _itemSlotMap; private readonly List _childItems = new List(); private readonly IXNALabel _weightLabel; @@ -101,7 +100,7 @@ public class InventoryPanel : XNAPanel, IHudPanel AutoSize = false }; - _itemSlotMap = GetItemSlotMap(_playerInfoProvider.LoggedInAccountName, _characterProvider.MainCharacter.Name); + _inventorySlotRepository.SlotMap = GetItemSlotMap(_playerInfoProvider.LoggedInAccountName, _characterProvider.MainCharacter.Name); var weirdOffsetSheet = NativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 27); @@ -206,7 +205,7 @@ 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 preferredSlot = _inventorySlotRepository.SlotMap.SingleOrNone(x => x.Value == item.ItemID).Map(x => x.Key); var actualSlot = _inventoryService.GetNextOpenSlot(_inventorySlotRepository.FilledSlots, itemData.Size, preferredSlot); actualSlot.MatchSome(slot => @@ -484,38 +483,6 @@ private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCo { _sfxPlayer.PlaySfx(SoundEffectID.InventoryPlace); } - - #region Unimplemented drag action - /* - 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) From a4524c21bd13fa642e3d615e775357ab63f2346a Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Thu, 15 Sep 2022 20:22:26 -0700 Subject: [PATCH 10/17] Support drag+drop to add item to trade offer --- .../Controllers/InventoryController.cs | 32 +++++++++++++++++++ .../Dialogs/ActiveDialogRepository.cs | 8 +++++ EndlessClient/HUD/Panels/InventoryPanel.cs | 8 +++++ 3 files changed, 48 insertions(+) diff --git a/EndlessClient/Controllers/InventoryController.cs b/EndlessClient/Controllers/InventoryController.cs index c856056ee..15940e46f 100644 --- a/EndlessClient/Controllers/InventoryController.cs +++ b/EndlessClient/Controllers/InventoryController.cs @@ -13,6 +13,7 @@ using EOLib.Domain.Interact.Bank; using EOLib.Domain.Item; using EOLib.Domain.Map; +using EOLib.Domain.Trade; using EOLib.IO; using EOLib.IO.Pub; using EOLib.IO.Repositories; @@ -32,6 +33,7 @@ public class InventoryController : IInventoryController private readonly IChestActions _chestActions; private readonly ILockerActions _lockerActions; private readonly IBankActions _bankActions; + private readonly ITradeActions _tradeActions; private readonly IItemEquipValidator _itemEquipValidator; private readonly IItemDropValidator _itemDropValidator; private readonly ICharacterProvider _characterProvider; @@ -40,6 +42,7 @@ public class InventoryController : IInventoryController private readonly ICurrentMapProvider _currentMapProvider; private readonly IEIFFileProvider _eifFileProvider; private readonly IActiveDialogProvider _activeDialogProvider; + private readonly ITradeProvider _tradeProvider; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IItemTransferDialogFactory _itemTransferDialogFactory; private readonly IEOMessageBoxFactory _eoMessageBoxFactory; @@ -50,6 +53,7 @@ public class InventoryController : IInventoryController IChestActions chestActions, ILockerActions lockerActions, IBankActions bankActions, + ITradeActions tradeActions, IItemEquipValidator itemEquipValidator, IItemDropValidator itemDropValidator, ICharacterProvider characterProvider, @@ -58,6 +62,7 @@ public class InventoryController : IInventoryController ICurrentMapProvider currentMapProvider, IEIFFileProvider eifFileProvider, IActiveDialogProvider activeDialogProvider, + ITradeProvider tradeProvider, IStatusLabelSetter statusLabelSetter, IItemTransferDialogFactory itemTransferDialogFactory, IEOMessageBoxFactory eoMessageBoxFactory) @@ -68,6 +73,7 @@ public class InventoryController : IInventoryController _chestActions = chestActions; _lockerActions = lockerActions; _bankActions = bankActions; + _tradeActions = tradeActions; _itemEquipValidator = itemEquipValidator; _itemDropValidator = itemDropValidator; _characterProvider = characterProvider; @@ -76,6 +82,7 @@ public class InventoryController : IInventoryController _currentMapProvider = currentMapProvider; _eifFileProvider = eifFileProvider; _activeDialogProvider = activeDialogProvider; + _tradeProvider = tradeProvider; _statusLabelSetter = statusLabelSetter; _itemTransferDialogFactory = itemTransferDialogFactory; _eoMessageBoxFactory = eoMessageBoxFactory; @@ -307,6 +314,29 @@ public void JunkItem(EIFRecord itemData, InventoryItem inventoryItem) } } + public void TradeItem(EIFRecord itemData, InventoryItem inventoryItem) + { + var mainPlayerAgrees = _characterProvider.MainCharacter.ID == _tradeProvider.PlayerOneOffer.PlayerID + ? _tradeProvider.PlayerOneOffer.Agrees + : _tradeProvider.PlayerTwoOffer.Agrees; + + if (mainPlayerAgrees) + return; + + if (itemData.Special == ItemSpecial.Lore) + { + var dlg = _eoMessageBoxFactory.CreateMessageBox(DialogResourceID.ITEM_IS_LORE_ITEM); + dlg.ShowDialog(); + } + else + { + DoItemDrop(itemData, inventoryItem, + a => _tradeActions.AddItemToOffer(inventoryItem.ItemID, a), + ItemTransferDialog.TransferType.TradeItems, + EOResourceID.DIALOG_TRANSFER_OFFER); + } + } + private void DoItemDrop(EIFRecord itemData, InventoryItem inventoryItem, Action dropAction, ItemTransferDialog.TransferType transferType = ItemTransferDialog.TransferType.DropItems, EOResourceID message = EOResourceID.DIALOG_TRANSFER_DROP) @@ -366,5 +396,7 @@ public interface IInventoryController void DropItemInBank(EIFRecord itemData, InventoryItem inventoryItem); void JunkItem(EIFRecord itemData, InventoryItem inventoryItem); + + void TradeItem(EIFRecord itemData, InventoryItem inventoryItem); } } diff --git a/EndlessClient/Dialogs/ActiveDialogRepository.cs b/EndlessClient/Dialogs/ActiveDialogRepository.cs index cca28ff36..1b2f360cf 100644 --- a/EndlessClient/Dialogs/ActiveDialogRepository.cs +++ b/EndlessClient/Dialogs/ActiveDialogRepository.cs @@ -33,6 +33,8 @@ public interface IActiveDialogProvider : IDisposable Option MessageDialog { get; } + Option TradeDialog { get; } + IReadOnlyList> ActiveDialogs { get; } } @@ -62,6 +64,8 @@ public interface IActiveDialogRepository : IDisposable Option MessageDialog { get; set; } + Option TradeDialog { get; set; } + IReadOnlyList> ActiveDialogs { get; } } @@ -92,6 +96,8 @@ public class ActiveDialogRepository : IActiveDialogRepository, IActiveDialogProv public Option MessageDialog { get; set; } + public Option TradeDialog { get; set; } + IReadOnlyList> ActiveDialogs { get @@ -110,6 +116,7 @@ IReadOnlyList> ActiveDialogs SkillmasterDialog.Map(d => (IXNADialog)d), BardDialog.Map(d => (IXNADialog)d), MessageDialog.Map(d => (IXNADialog)d), + TradeDialog.Map(d => (IXNADialog)d), }.ToList(); } } @@ -135,6 +142,7 @@ public void Dispose() SkillmasterDialog = Option.None(); BardDialog = Option.None(); MessageDialog = Option.None(); + TradeDialog = Option.None(); } } } diff --git a/EndlessClient/HUD/Panels/InventoryPanel.cs b/EndlessClient/HUD/Panels/InventoryPanel.cs index c87fd8238..891b516e5 100644 --- a/EndlessClient/HUD/Panels/InventoryPanel.cs +++ b/EndlessClient/HUD/Panels/InventoryPanel.cs @@ -423,6 +423,14 @@ private void HandleItemDoneDragging(object sender, InventoryPanelItem.ItemDragCo _inventoryController.DropItemInBank(item.Data, item.InventoryItem); } }); + _activeDialogProvider.TradeDialog.MatchSome(x => + { + if (x.MouseOver && x.MouseOverPreviously) + { + dialogDrop = true; + _inventoryController.TradeItem(item.Data, item.InventoryItem); + } + }); if (dialogDrop) { From a461571ab7761ef72fbe9612d3989c56f119ac30 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 16 Sep 2022 10:30:59 -0700 Subject: [PATCH 11/17] Wire up trade actions to context menu. Finish implementing trade dialog actions. --- .../Dialogs/Actions/InGameDialogActions.cs | 26 ++++++ .../Dialogs/Actions/TradeDialogActions.cs | 36 +++++++-- EndlessClient/Dialogs/BaseEODialog.cs | 7 ++ .../Dialogs/Factories/TradeDialogFactory.cs | 80 +++++++++++++++++++ EndlessClient/Dialogs/ScrollingListDialog.cs | 2 - EndlessClient/Dialogs/TradeDialog.cs | 3 +- .../Rendering/ContextMenuRenderer.cs | 57 ++++++------- .../Factories/ContextMenuRendererFactory.cs | 5 ++ 8 files changed, 178 insertions(+), 38 deletions(-) create mode 100644 EndlessClient/Dialogs/Factories/TradeDialogFactory.cs diff --git a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs index 37521c394..957eba9d4 100644 --- a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs @@ -29,6 +29,7 @@ public class InGameDialogActions : IInGameDialogActions private readonly ISkillmasterDialogFactory _skillmasterDialogFactory; private readonly IBardDialogFactory _bardDialogFactory; private readonly IScrollingListDialogFactory _scrollingListDialogFactory; + private readonly ITradeDialogFactory _tradeDialogFactory; private readonly ISfxPlayer _sfxPlayer; private readonly IShopDialogFactory _shopDialogFactory; private readonly IQuestDialogFactory _questDialogFactory; @@ -49,6 +50,7 @@ public class InGameDialogActions : IInGameDialogActions ISkillmasterDialogFactory skillmasterDialogFactory, IBardDialogFactory bardDialogFactory, IScrollingListDialogFactory scrollingListDialogFactory, + ITradeDialogFactory tradeDialogFactory, ISfxPlayer sfxPlayer) { _friendIgnoreListDialogFactory = friendIgnoreListDialogFactory; @@ -65,6 +67,7 @@ public class InGameDialogActions : IInGameDialogActions _skillmasterDialogFactory = skillmasterDialogFactory; _bardDialogFactory = bardDialogFactory; _scrollingListDialogFactory = scrollingListDialogFactory; + _tradeDialogFactory = tradeDialogFactory; _sfxPlayer = sfxPlayer; _shopDialogFactory = shopDialogFactory; _questDialogFactory = questDialogFactory; @@ -281,6 +284,25 @@ public void ShowMessageDialog(string title, IReadOnlyList messages) }); } + public void ShowTradeDialog() + { + _activeDialogRepository.TradeDialog.MatchNone(() => + { + var dlg = _tradeDialogFactory.Create(); + dlg.DialogClosed += (_, _) => _activeDialogRepository.TradeDialog = Option.None(); + _activeDialogRepository.TradeDialog = Option.Some(dlg); + + UseDefaultDialogSounds(dlg); + + dlg.Show(); + }); + } + + public void CloseTradeDialog() + { + _activeDialogRepository.TradeDialog.MatchSome(dlg => dlg.Close()); + } + private void UseDefaultDialogSounds(ScrollingListDialog dialog) { UseDefaultDialogSounds((BaseEODialog)dialog); @@ -334,5 +356,9 @@ public interface IInGameDialogActions void ShowBardDialog(); void ShowMessageDialog(string title, IReadOnlyList messages); + + void ShowTradeDialog(); + + void CloseTradeDialog(); } } diff --git a/EndlessClient/Dialogs/Actions/TradeDialogActions.cs b/EndlessClient/Dialogs/Actions/TradeDialogActions.cs index 7dd69ecb4..5d0da0b4e 100644 --- a/EndlessClient/Dialogs/Actions/TradeDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/TradeDialogActions.cs @@ -1,7 +1,8 @@ using AutomaticTypeMapper; using EndlessClient.Dialogs.Factories; +using EndlessClient.HUD; using EOLib.Config; -using EOLib.Domain.Map; +using EOLib.Domain.Character; using EOLib.Domain.Notifiers; using EOLib.Domain.Trade; using EOLib.Localization; @@ -13,15 +14,30 @@ namespace EndlessClient.Dialogs.Actions public class TradeDialogActions : ITradeEventNotifier { private readonly ITradeActions _tradeActions; + private readonly IInGameDialogActions _inGameDialogActions; private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IStatusLabelSetter _statusLabelSetter; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly ITradeProvider _tradeProvider; + private readonly ICharacterProvider _characterProvider; private readonly IConfigurationProvider _configurationProvider; public TradeDialogActions(ITradeActions tradeActions, + IInGameDialogActions inGameDialogActions, IEOMessageBoxFactory messageBoxFactory, + IStatusLabelSetter statusLabelSetter, + ILocalizedStringFinder localizedStringFinder, + ITradeProvider tradeProvider, + ICharacterProvider characterProvider, IConfigurationProvider configurationProvider) { _tradeActions = tradeActions; + _inGameDialogActions = inGameDialogActions; _messageBoxFactory = messageBoxFactory; + _statusLabelSetter = statusLabelSetter; + _localizedStringFinder = localizedStringFinder; + _tradeProvider = tradeProvider; + _characterProvider = characterProvider; _configurationProvider = configurationProvider; } @@ -44,24 +60,28 @@ public void NotifyTradeRequest(short playerId, string name) public void NotifyTradeAccepted() { - // todo: show trade dialog + _inGameDialogActions.ShowTradeDialog(); - // todo: status label - //m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_YOU_ARE_TRADING_WITH, - // otherName + " " + OldWorld.GetString(EOResourceID.STATUS_LABEL_DRAG_AND_DROP_ITEMS)); + var otherName = _tradeProvider.PlayerOneOffer.PlayerID == _characterProvider.MainCharacter.ID + ? _tradeProvider.PlayerOneOffer.PlayerName + : _tradeProvider.PlayerTwoOffer.PlayerName; + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, + EOResourceID.STATUS_LABEL_TRADE_YOU_ARE_TRADING_WITH, + $"{otherName} {_localizedStringFinder.GetString(EOResourceID.STATUS_LABEL_DRAG_AND_DROP_ITEMS)}"); } public void NotifyTradeClose(bool cancel) { - // todo: close trade dialog + _inGameDialogActions.CloseTradeDialog(); if (cancel) { - //m_game.Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_ABORTED); + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_ABORTED); } else { - //EOMessageBox.Show(DialogResourceID.TRADE_SUCCESS, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.TRADE_SUCCESS); + dlg.ShowDialog(); } } } diff --git a/EndlessClient/Dialogs/BaseEODialog.cs b/EndlessClient/Dialogs/BaseEODialog.cs index 8a64c10c3..4ee98c542 100644 --- a/EndlessClient/Dialogs/BaseEODialog.cs +++ b/EndlessClient/Dialogs/BaseEODialog.cs @@ -34,5 +34,12 @@ public override void CenterInGameView() if (_isInGame()) DrawPosition = new Vector2(DrawPosition.X, (330 - DrawArea.Height)/2f); } + + protected override void OnUpdateControl(GameTime gameTime) + { + ChildControlClickHandled = false; + + base.OnUpdateControl(gameTime); + } } } diff --git a/EndlessClient/Dialogs/Factories/TradeDialogFactory.cs b/EndlessClient/Dialogs/Factories/TradeDialogFactory.cs new file mode 100644 index 000000000..ebaeaa872 --- /dev/null +++ b/EndlessClient/Dialogs/Factories/TradeDialogFactory.cs @@ -0,0 +1,80 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Services; +using EndlessClient.HUD.Inventory; +using EndlessClient.HUD; +using EndlessClient.Rendering.Map; +using EOLib.Domain.Character; +using EOLib.Domain.Trade; +using EOLib.Graphics; +using EOLib.IO.Repositories; +using EOLib.Localization; +using EndlessClient.ControlSets; +using EndlessClient.HUD.Panels; + +namespace EndlessClient.Dialogs.Factories +{ + [AutoMappedType] + public class TradeDialogFactory : ITradeDialogFactory + { + private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly ITradeActions _tradeActions; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly IEODialogButtonService _dialogButtonService; + private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IStatusLabelSetter _statusLabelSetter; + private readonly IInventorySpaceValidator _inventorySpaceValidator; + private readonly ITradeProvider _tradeProvider; + private readonly ICharacterProvider _characterProvider; + private readonly IEIFFileProvider _eifFileProvider; + private readonly IMapItemGraphicProvider _mapItemGraphicProvider; + private readonly IHudControlProvider _hudControlProvider; + + public TradeDialogFactory(INativeGraphicsManager nativeGraphicsManager, + ITradeActions tradeActions, + ILocalizedStringFinder localizedStringFinder, + IEODialogButtonService dialogButtonService, + IEOMessageBoxFactory messageBoxFactory, + IStatusLabelSetter statusLabelSetter, + IInventorySpaceValidator inventorySpaceValidator, + ITradeProvider tradeProvider, + ICharacterProvider characterProvider, + IEIFFileProvider eifFileProvider, + IMapItemGraphicProvider mapItemGraphicProvider, + IHudControlProvider hudControlProvider) + { + _nativeGraphicsManager = nativeGraphicsManager; + _tradeActions = tradeActions; + _localizedStringFinder = localizedStringFinder; + _dialogButtonService = dialogButtonService; + _messageBoxFactory = messageBoxFactory; + _statusLabelSetter = statusLabelSetter; + _inventorySpaceValidator = inventorySpaceValidator; + _tradeProvider = tradeProvider; + _characterProvider = characterProvider; + _eifFileProvider = eifFileProvider; + _mapItemGraphicProvider = mapItemGraphicProvider; + _hudControlProvider = hudControlProvider; + } + + public TradeDialog Create() + { + return new TradeDialog(_nativeGraphicsManager, + _tradeActions, + _localizedStringFinder, + _dialogButtonService, + _messageBoxFactory, + _statusLabelSetter, + _inventorySpaceValidator, + _tradeProvider, + _characterProvider, + _eifFileProvider, + _mapItemGraphicProvider, + _hudControlProvider.GetComponent(HUD.Controls.HudControlIdentifier.InventoryPanel)); + } + } + + public interface ITradeDialogFactory + { + TradeDialog Create(); + } +} diff --git a/EndlessClient/Dialogs/ScrollingListDialog.cs b/EndlessClient/Dialogs/ScrollingListDialog.cs index 4d0aea02d..ef6f6e2ae 100644 --- a/EndlessClient/Dialogs/ScrollingListDialog.cs +++ b/EndlessClient/Dialogs/ScrollingListDialog.cs @@ -364,8 +364,6 @@ public override void Initialize() protected override void OnUpdateControl(GameTime gameTime) { - ChildControlClickHandled = false; - if (_listItems.Count > _scrollBar.LinesToRender) { for (int i = 0; i < _listItems.Count; ++i) diff --git a/EndlessClient/Dialogs/TradeDialog.cs b/EndlessClient/Dialogs/TradeDialog.cs index c47c969b8..aba0b07e9 100644 --- a/EndlessClient/Dialogs/TradeDialog.cs +++ b/EndlessClient/Dialogs/TradeDialog.cs @@ -156,7 +156,8 @@ public override void Initialize() _cancel.Initialize(); } - protected override void OnUpdateControl(GameTime gameTime) + public void Close() => Close(XNADialogResult.NO_BUTTON_PRESSED); + { var updateItemVisibility = false; diff --git a/EndlessClient/Rendering/ContextMenuRenderer.cs b/EndlessClient/Rendering/ContextMenuRenderer.cs index fea00f08f..4fa4cc071 100644 --- a/EndlessClient/Rendering/ContextMenuRenderer.cs +++ b/EndlessClient/Rendering/ContextMenuRenderer.cs @@ -13,6 +13,7 @@ using EOLib.Domain.Chat; using EOLib.Domain.Interact; using EOLib.Domain.Party; +using EOLib.Domain.Trade; using EOLib.Graphics; using EOLib.Localization; using Microsoft.Xna.Framework; @@ -46,6 +47,7 @@ private enum MenuAction private readonly IInGameDialogActions _inGameDialogActions; private readonly IPaperdollActions _paperdollActions; private readonly IPartyActions _partyActions; + private readonly ITradeActions _tradeActions; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IFriendIgnoreListService _friendIgnoreListService; private readonly IHudControlProvider _hudControlProvider; @@ -54,13 +56,14 @@ private enum MenuAction private readonly IPartyDataProvider _partyDataProvider; private readonly ICharacterRenderer _characterRenderer; - //private DateTime? m_lastTradeRequestedTime; + private static DateTime? _lastTradeRequestedTime; private static DateTime? _lastPartyRequestTime; public ContextMenuRenderer(INativeGraphicsManager nativeGraphicsManager, IInGameDialogActions inGameDialogActions, IPaperdollActions paperdollActions, IPartyActions partyActions, + ITradeActions tradeActions, IStatusLabelSetter statusLabelSetter, IFriendIgnoreListService friendIgnoreListService, IHudControlProvider hudControlProvider, @@ -73,6 +76,7 @@ private enum MenuAction _inGameDialogActions = inGameDialogActions; _paperdollActions = paperdollActions; _partyActions = partyActions; + _tradeActions = tradeActions; _statusLabelSetter = statusLabelSetter; _friendIgnoreListService = friendIgnoreListService; _hudControlProvider = hudControlProvider; @@ -222,10 +226,10 @@ private Action GetActionFromMenuAction(MenuAction menuAction) switch (menuAction) { case MenuAction.Paperdoll: return ShowPaperdollAction; - case MenuAction.Book: return () => { };//return _eventShowBook; + case MenuAction.Book: return ShowBook; case MenuAction.Join: return JoinParty; case MenuAction.Invite: return InviteToParty; - case MenuAction.Trade: return () => { }; //return _eventTrade; + case MenuAction.Trade: return Trade; case MenuAction.Whisper: return PrivateMessage; case MenuAction.Friend: return AddFriend; case MenuAction.Ignore: return AddIgnore; @@ -239,10 +243,9 @@ private void ShowPaperdollAction() _inGameDialogActions.ShowPaperdollDialog(_characterRenderer.Character, isMainCharacter: false); } - //private void _eventShowBook(object arg1, EventArgs arg2) - //{ - // EOMessageBox.Show("TODO: Show quest info", "TODO ITEM", EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - //} + private void ShowBook() + { + } private void JoinParty() { @@ -282,26 +285,26 @@ private void InviteToParty() _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, _characterRenderer.Character.Name, EOResourceID.STATUS_LABEL_PARTY_IS_INVITED); } - //private void _eventTrade(object arg1, EventArgs arg2) - //{ - // if (OldWorld.Instance.MainPlayer.ActiveCharacter.CurrentMap == OldWorld.Instance.JailMap) - // EOMessageBox.Show(OldWorld.GetString(EOResourceID.JAIL_WARNING_CANNOT_TRADE), - // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - // else - // { - // if(m_lastTradeRequestedTime != null && (DateTime.Now - m_lastTradeRequestedTime.Value).TotalSeconds < Constants.TradeRequestTimeoutSeconds) - // { - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_TRADE_RECENTLY_REQUESTED); - // return; - // } - // m_lastTradeRequestedTime = DateTime.Now; - // if (!m_api.TradeRequest((short)m_rend.Character.ID)) - // ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - // //todo: is this correct text? - // ((EOGame)Game).Hud.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_REQUESTED_TO_TRADE); - // } - //} + private void Trade() + { + // see: https://github.com/ethanmoffat/EndlessClient/issues/193 + //if (OldWorld.Instance.MainPlayer.ActiveCharacter.CurrentMap == OldWorld.Instance.JailMap) + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.JAIL_WARNING_CANNOT_TRADE), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + + if (_lastTradeRequestedTime != null && (DateTime.Now - _lastTradeRequestedTime.Value).TotalSeconds < Constants.TradeRequestTimeoutSeconds) + { + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_WARNING, EOResourceID.STATUS_LABEL_TRADE_RECENTLY_REQUESTED); + return; + } + + _lastTradeRequestedTime = DateTime.Now; + + _tradeActions.RequestTrade((short)_characterRenderer.Character.ID); + + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.STATUS_LABEL_TRADE_REQUESTED_TO_TRADE); + } private void PrivateMessage() { diff --git a/EndlessClient/Rendering/Factories/ContextMenuRendererFactory.cs b/EndlessClient/Rendering/Factories/ContextMenuRendererFactory.cs index 71af096e9..429d2d3fc 100644 --- a/EndlessClient/Rendering/Factories/ContextMenuRendererFactory.cs +++ b/EndlessClient/Rendering/Factories/ContextMenuRendererFactory.cs @@ -7,6 +7,7 @@ using EndlessClient.Services; using EOLib.Domain.Interact; using EOLib.Domain.Party; +using EOLib.Domain.Trade; using EOLib.Graphics; namespace EndlessClient.Rendering.Factories @@ -18,6 +19,7 @@ public class ContextMenuRendererFactory : IContextMenuRendererFactory private readonly IInGameDialogActions _inGameDialogActions; private readonly IPaperdollActions _paperdollActions; private readonly IPartyActions _partyActions; + private readonly ITradeActions _tradeActions; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IFriendIgnoreListService _friendIgnoreListService; private readonly IHudControlProvider _hudControlProvider; @@ -29,6 +31,7 @@ public class ContextMenuRendererFactory : IContextMenuRendererFactory IInGameDialogActions inGameDialogActions, IPaperdollActions paperdollActions, IPartyActions partyActions, + ITradeActions tradeActions, IStatusLabelSetter statusLabelSetter, IFriendIgnoreListService friendIgnoreListService, IHudControlProvider hudControlProvider, @@ -40,6 +43,7 @@ public class ContextMenuRendererFactory : IContextMenuRendererFactory _inGameDialogActions = inGameDialogActions; _paperdollActions = paperdollActions; _partyActions = partyActions; + _tradeActions = tradeActions; _statusLabelSetter = statusLabelSetter; _friendIgnoreListService = friendIgnoreListService; _hudControlProvider = hudControlProvider; @@ -54,6 +58,7 @@ public IContextMenuRenderer CreateContextMenuRenderer(ICharacterRenderer charact _inGameDialogActions, _paperdollActions, _partyActions, + _tradeActions, _statusLabelSetter, _friendIgnoreListService, _hudControlProvider, From f1c2cd941495937011b4130e6d504d17f98738cf Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 16 Sep 2022 10:31:51 -0700 Subject: [PATCH 12/17] Fix various minor display bugs in TradeDialog --- EndlessClient/Dialogs/TradeDialog.cs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/EndlessClient/Dialogs/TradeDialog.cs b/EndlessClient/Dialogs/TradeDialog.cs index aba0b07e9..6fd158544 100644 --- a/EndlessClient/Dialogs/TradeDialog.cs +++ b/EndlessClient/Dialogs/TradeDialog.cs @@ -158,9 +158,11 @@ public override void Initialize() public void Close() => Close(XNADialogResult.NO_BUTTON_PRESSED); + protected override void OnUnconditionalUpdateControl(GameTime gameTime) { var updateItemVisibility = false; + // player one offer will always be on the left; player two always on the right if (_tradeProvider.PlayerOneOffer != null && !_tradeProvider.PlayerOneOffer.Equals(_leftOffer)) { UpdateOffer(_tradeProvider.PlayerOneOffer, _leftOffer, _leftPlayerName, _leftPlayerStatus, _leftItems, -3); @@ -189,14 +191,18 @@ public override void Initialize() _rightScrollOffset = _rightScroll.ScrollOffset; } - if (_partnerItemChangeTick?.ElapsedMilliseconds > 1000) + if (_partnerItemChangeTick?.ElapsedMilliseconds > 1000 && _recentPartnerItemChanges > 0) { _recentPartnerItemChanges--; _partnerItemChangeTick = Stopwatch.StartNew(); } - SuppressClickDragEvent(!_inventoryPanel.NoItemsDragging()); + base.OnUnconditionalUpdateControl(gameTime); + } + protected override void OnUpdateControl(GameTime gameTime) + { + SuppressClickDragEvent(!_inventoryPanel.NoItemsDragging()); base.OnUpdateControl(gameTime); } @@ -207,7 +213,7 @@ public override void Initialize() { if (actualOffer.PlayerName != cachedOffer.PlayerName || actualOffer.Items.Count != cachedOffer.Items.Count) { - playerNameLabel.Text = $"{actualOffer.PlayerName}{(actualOffer.Items.Any() ? $"[{actualOffer.Items.Count}]" : "")}"; + playerNameLabel.Text = $"{char.ToUpper(actualOffer.PlayerName[0]) + actualOffer.PlayerName[1..]}{(actualOffer.Items.Any() ? $"[{actualOffer.Items.Count}]" : "")}"; } // todo: check if packets properly reset agrees to false when items change @@ -233,10 +239,10 @@ public override void Initialize() } } - if (!actualOffer.Items.ToHashSet().SetEquals(cachedOffer.Items)) + if (cachedOffer.Items == null || !actualOffer.Items.ToHashSet().SetEquals(cachedOffer.Items)) { - var added = actualOffer.Items.Except(cachedOffer.Items); - var removed = cachedOffer.Items.Where(i => !actualOffer.Items.Contains(i)); + var added = actualOffer.Items.Except(cachedOffer.Items ?? Enumerable.Empty()); + var removed = (cachedOffer.Items ?? Enumerable.Empty()).Where(i => !actualOffer.Items.Contains(i)); foreach (var addedItem in added) { @@ -262,7 +268,7 @@ public override void Initialize() foreach (var removedItem in removed) { - listItems.SingleOrNone(y => ((InventoryItem)y.Data).ItemID == removedItem.ItemID) + listItems.SingleOrNone(y => ((InventoryItem)y.Data).Equals(removedItem)) .MatchSome(listItem => { listItems.Remove(listItem); @@ -270,7 +276,7 @@ public override void Initialize() }); } - if (actualOffer.PlayerID != _characterProvider.MainCharacter.ID) + if (cachedOffer.Items != null && actualOffer.PlayerID != 0 && actualOffer.PlayerID != _characterProvider.MainCharacter.ID) { _partnerItemChangeTick = Stopwatch.StartNew(); _recentPartnerItemChanges++; @@ -283,7 +289,7 @@ public override void Initialize() // this will prevent the message from showing more than once per trade (I'm too lazy to find something more elegant) _recentPartnerItemChanges = -1000; } - else + else if ((_leftOffer == cachedOffer ? _rightOffer : _leftOffer).Agrees) { var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.TRADE_ABORTED_OFFER_CHANGED); dlg.ShowDialog(); From 363b619cfd58d190d58ead01b5ac456b7ef046d5 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 16 Sep 2022 10:32:10 -0700 Subject: [PATCH 13/17] Ensure equality of InventoryItem/TradeOffer is properly defined --- EOLib/Domain/Character/InventoryItem.cs | 2 +- EOLib/Domain/Trade/TradeOffer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EOLib/Domain/Character/InventoryItem.cs b/EOLib/Domain/Character/InventoryItem.cs index 5b3a7602b..adaa334b3 100644 --- a/EOLib/Domain/Character/InventoryItem.cs +++ b/EOLib/Domain/Character/InventoryItem.cs @@ -2,7 +2,7 @@ namespace EOLib.Domain.Character { - [Record] + [Record(Features.Default | Features.EquatableEquals | Features.ObjectEquals)] public sealed partial class InventoryItem { public short ItemID { get; } diff --git a/EOLib/Domain/Trade/TradeOffer.cs b/EOLib/Domain/Trade/TradeOffer.cs index 7c1928a63..0fe58a6ca 100644 --- a/EOLib/Domain/Trade/TradeOffer.cs +++ b/EOLib/Domain/Trade/TradeOffer.cs @@ -4,7 +4,7 @@ namespace EOLib.Domain.Trade { - [Record] + [Record(Features.Default | Features.EquatableEquals | Features.ObjectEquals)] public sealed partial class TradeOffer { public bool Agrees { get; } From 15e151430e0e94ac1ee942124742d3026c178c80 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 16 Sep 2022 10:33:16 -0700 Subject: [PATCH 14/17] Remove TradeSessionID (this is probably not what the mystery byte is for) --- EOLib/Domain/Trade/TradeActions.cs | 16 ++++------------ EOLib/Domain/Trade/TradeRepository.cs | 7 ------- .../PacketHandlers/Trade/TradeRequestHandler.cs | 13 +++---------- 3 files changed, 7 insertions(+), 29 deletions(-) diff --git a/EOLib/Domain/Trade/TradeActions.cs b/EOLib/Domain/Trade/TradeActions.cs index cae5ab222..73865603f 100644 --- a/EOLib/Domain/Trade/TradeActions.cs +++ b/EOLib/Domain/Trade/TradeActions.cs @@ -9,24 +9,16 @@ namespace EOLib.Domain.Trade public class TradeActions : ITradeActions { private readonly IPacketSendService _packetSendService; - private readonly ITradeRepository _tradeRepository; - private readonly Random _random; - public TradeActions(IPacketSendService packetSendService, - ITradeRepository tradeRepository) + public TradeActions(IPacketSendService packetSendService) { _packetSendService = packetSendService; - _tradeRepository = tradeRepository; - _random = new Random(); } public void RequestTrade(short characterID) { - var tradeId = (byte)(_random.Next(252) + 1); - _tradeRepository.TradeSessionID = tradeId; - var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Request) - .AddChar(tradeId) + .AddChar(6) .AddShort(characterID) .Build(); _packetSendService.SendPacket(packet); @@ -35,7 +27,7 @@ public void RequestTrade(short characterID) public void AcceptTradeRequest(short characterID) { var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Accept) - .AddChar(_tradeRepository.TradeSessionID) + .AddChar(6) .AddShort(characterID) .Build(); _packetSendService.SendPacket(packet); @@ -69,7 +61,7 @@ public void AgreeToTrade(bool agree) public void CancelTrade() { var packet = new PacketBuilder(PacketFamily.Trade, PacketAction.Close) - .AddChar(_tradeRepository.TradeSessionID) + .AddChar(6) .Build(); _packetSendService.SendPacket(packet); } diff --git a/EOLib/Domain/Trade/TradeRepository.cs b/EOLib/Domain/Trade/TradeRepository.cs index b298cdb5b..124ac54dc 100644 --- a/EOLib/Domain/Trade/TradeRepository.cs +++ b/EOLib/Domain/Trade/TradeRepository.cs @@ -6,8 +6,6 @@ namespace EOLib.Domain.Trade { public interface ITradeRepository : IResettable { - byte TradeSessionID { get; set; } - TradeOffer PlayerOneOffer { get; set; } TradeOffer PlayerTwoOffer { get; set; } @@ -15,8 +13,6 @@ public interface ITradeRepository : IResettable public interface ITradeProvider { - byte TradeSessionID { get; } - TradeOffer PlayerOneOffer { get; } TradeOffer PlayerTwoOffer { get; } @@ -25,8 +21,6 @@ public interface ITradeProvider [AutoMappedType(IsSingleton = true)] public class TradeRepository : ITradeRepository, ITradeProvider { - public byte TradeSessionID { get; set; } - public TradeOffer PlayerOneOffer { get; set; } public TradeOffer PlayerTwoOffer { get; set; } @@ -38,7 +32,6 @@ public TradeRepository() public void ResetState() { - TradeSessionID = 0; PlayerOneOffer = new TradeOffer(false, 0, string.Empty, new List()); PlayerTwoOffer = new TradeOffer(false, 0, string.Empty, new List()); } diff --git a/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs b/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs index fe881aa83..366600664 100644 --- a/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeRequestHandler.cs @@ -1,7 +1,6 @@ using AutomaticTypeMapper; using EOLib.Domain.Login; using EOLib.Domain.Notifiers; -using EOLib.Domain.Trade; using EOLib.Net; using EOLib.Net.Handlers; using System.Collections.Generic; @@ -14,7 +13,6 @@ namespace EOLib.PacketHandlers.Trade [AutoMappedType] public class TradeRequestHandler : InGameOnlyPacketHandler { - private readonly ITradeProvider _tradeProvider; private readonly IEnumerable _tradeEventNotifiers; public override PacketFamily Family => PacketFamily.Trade; @@ -22,25 +20,20 @@ public class TradeRequestHandler : InGameOnlyPacketHandler public override PacketAction Action => PacketAction.Request; public TradeRequestHandler(IPlayerInfoProvider playerInfoProvider, - ITradeProvider tradeProvider, IEnumerable tradeEventNotifiers) : base(playerInfoProvider) { - _tradeProvider = tradeProvider; _tradeEventNotifiers = tradeEventNotifiers; } public override bool HandlePacket(IPacket packet) { - var sessionId = packet.ReadChar(); + packet.ReadChar(); // ? var playerId = packet.ReadShort(); var name = packet.ReadEndString(); - if (sessionId == _tradeProvider.TradeSessionID) - { - foreach (var notifier in _tradeEventNotifiers) - notifier.NotifyTradeRequest(playerId, name); - } + foreach (var notifier in _tradeEventNotifiers) + notifier.NotifyTradeRequest(playerId, name); return true; } From 23158ccd61eebf1d2c8256e0a477c329bcb41c2d Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 16 Sep 2022 10:33:32 -0700 Subject: [PATCH 15/17] Ensure trade agree is setting agreement for the correct player --- EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs b/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs index 3ce81b33d..aebf1711d 100644 --- a/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeAgreeHandler.cs @@ -28,10 +28,10 @@ public class TradeAgreeHandler : InGameOnlyPacketHandler public override bool HandlePacket(IPacket packet) { - var otherPlayerId = packet.ReadShort(); + var mainPlayerId = packet.ReadShort(); var otherPlayerAgrees = packet.ReadChar() != 0; - _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == otherPlayerId) + _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == mainPlayerId) .Map(x => x.PlayerOneOffer = x.PlayerOneOffer.WithAgrees(otherPlayerAgrees)) .Or(() => _tradeRepository.PlayerTwoOffer = _tradeRepository.PlayerTwoOffer.WithAgrees(otherPlayerAgrees)); From 78a2a54e2aec0bc0d1400934195d82ea2ee57ec7 Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 16 Sep 2022 10:33:55 -0700 Subject: [PATCH 16/17] Ensure trade offer updates read the break bytes. Ensure weight never goes below zero after trade completes. --- EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs b/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs index 9d16266c2..43ae0e195 100644 --- a/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs +++ b/EOLib/PacketHandlers/Trade/TradeOfferUpdateHandler.cs @@ -34,6 +34,7 @@ public override bool HandlePacket(IPacket packet) { player1Items.Add(new InventoryItem(packet.ReadShort(), packet.ReadInt())); } + packet.ReadByte(); var player2Id = packet.ReadShort(); var player2Items = new List(); @@ -41,6 +42,7 @@ public override bool HandlePacket(IPacket packet) { player2Items.Add(new InventoryItem(packet.ReadShort(), packet.ReadInt())); } + packet.ReadByte(); _tradeRepository.SomeWhen(x => x.PlayerOneOffer.PlayerID == player1Id) .Match(some: x => @@ -77,6 +79,7 @@ public class TradeReplyHandler : TradeOfferUpdateHandler /// /// Trade completed /// + [AutoMappedType] public class TradeUseHandler : TradeOfferUpdateHandler { private readonly ICharacterRepository _characterRepository; @@ -141,6 +144,9 @@ public override bool HandlePacket(IPacket packet) stats = stats.WithNewStat(CharacterStat.Weight, stats[CharacterStat.Weight] + _eifFileProvider.EIFFile[newItem.ItemID].Weight * newItem.Amount); } + if (stats[CharacterStat.Weight] < 0) + stats = stats.WithNewStat(CharacterStat.Weight, 0); + _characterRepository.MainCharacter = _characterRepository.MainCharacter.WithStats(stats); foreach (var notifier in _tradeEventNotifiers) From dc5e49f15ac71c6732174b1bc6b8a57341abdffa Mon Sep 17 00:00:00 2001 From: Ethan Moffat Date: Fri, 16 Sep 2022 11:20:48 -0700 Subject: [PATCH 17/17] Remove erroneously added System.Windows.Documents using statement --- EndlessClient/HUD/Inventory/InventorySpaceValidator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs index a69af1f8a..66f4e2a55 100644 --- a/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs +++ b/EndlessClient/HUD/Inventory/InventorySpaceValidator.cs @@ -8,7 +8,6 @@ using Optional.Collections; using System.Collections.Generic; using System.Linq; -using System.Windows.Documents; namespace EndlessClient.HUD.Inventory {