diff --git a/EOLib/Domain/Interact/MapNPCActions.cs b/EOLib/Domain/Interact/MapNPCActions.cs index 89147fbac..eb04fcc91 100644 --- a/EOLib/Domain/Interact/MapNPCActions.cs +++ b/EOLib/Domain/Interact/MapNPCActions.cs @@ -1,8 +1,10 @@ -using EOLib.Net; +using AutomaticTypeMapper; +using EOLib.Net; using EOLib.Net.Communication; namespace EOLib.Domain.Interact { + [AutoMappedType] public class MapNPCActions : IMapNPCActions { private readonly IPacketSendService _packetSendService; diff --git a/EndlessClient/Controllers/MapInteractionController.cs b/EndlessClient/Controllers/MapInteractionController.cs index 921c05d72..c6bff34a6 100644 --- a/EndlessClient/Controllers/MapInteractionController.cs +++ b/EndlessClient/Controllers/MapInteractionController.cs @@ -72,7 +72,7 @@ public class MapInteractionController : IMapInteractionController public void LeftClick(IMapCellState cellState, IMouseCursorRenderer mouseRenderer) { - if (!InventoryPanel.NoItemsDragging()) + if (!InventoryPanel.NoItemsDragging() || cellState.Character.HasValue || cellState.NPC.HasValue) { return; } @@ -91,7 +91,6 @@ public void LeftClick(IMapCellState cellState, IMouseCursorRenderer mouseRendere else HandlePickupResult(_mapActions.PickUpItem(item), item); } - else if (cellState.NPC.HasValue) { /* TODO: spell cast */ } else if (cellState.Sign.HasValue) { var sign = cellState.Sign.ValueOr(Sign.None); @@ -99,17 +98,18 @@ public void LeftClick(IMapCellState cellState, IMouseCursorRenderer mouseRendere messageBox.ShowDialog(); } else if (cellState.Chest.HasValue) { /* TODO: chest interaction */ } - else if (cellState.Character.HasValue) { /* TODO: character spell cast */ } else if (cellState.InBounds) { mouseRenderer.AnimateClick(); _hudControlProvider.GetComponent(HudControlIdentifier.CharacterAnimator) .StartMainCharacterWalkAnimation(Option.Some(cellState.Coordinate)); } + // todo: board, jukebox _userInputTimeRepository.LastInputTime = DateTime.Now; } + // todo: move to new controller for character interaction public void RightClick(IMapCellState cellState) { if (!cellState.Character.HasValue) diff --git a/EndlessClient/Controllers/NPCInteractionController.cs b/EndlessClient/Controllers/NPCInteractionController.cs new file mode 100644 index 000000000..86c96e295 --- /dev/null +++ b/EndlessClient/Controllers/NPCInteractionController.cs @@ -0,0 +1,43 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Actions; +using EOLib.Domain.Interact; +using EOLib.Domain.NPC; +using EOLib.IO.Repositories; + +namespace EndlessClient.Controllers +{ + [AutoMappedType] + public class NPCInteractionController : INPCInteractionController + { + private readonly IMapNPCActions _mapNpcActions; + private readonly IInGameDialogActions _inGameDialogActions; + private readonly IENFFileProvider _enfFileProvider; + + public NPCInteractionController(IMapNPCActions mapNpcActions, + IInGameDialogActions inGameDialogActions, + IENFFileProvider enfFileProvider) + { + _mapNpcActions = mapNpcActions; + _inGameDialogActions = inGameDialogActions; + _enfFileProvider = enfFileProvider; + } + + public void ShowNPCDialog(INPC npc) + { + var data = _enfFileProvider.ENFFile[npc.ID]; + + switch(data.Type) + { + case EOLib.IO.NPCType.Shop: + _mapNpcActions.RequestShop(npc.Index); + _inGameDialogActions.ShowShopDialog(); + break; + } + } + } + + public interface INPCInteractionController + { + void ShowNPCDialog(INPC npc); + } +} diff --git a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs index 7a12e94e7..7772524bb 100644 --- a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs @@ -11,14 +11,17 @@ public class InGameDialogActions : IInGameDialogActions private readonly IFriendIgnoreListDialogFactory _friendIgnoreListDialogFactory; private readonly IPaperdollDialogFactory _paperdollDialogFactory; private readonly IActiveDialogRepository _activeDialogRepository; + private readonly IShopDialogFactory _shopDialogFactory; public InGameDialogActions(IFriendIgnoreListDialogFactory friendIgnoreListDialogFactory, IPaperdollDialogFactory paperdollDialogFactory, - IActiveDialogRepository activeDialogRepository) + IActiveDialogRepository activeDialogRepository, + IShopDialogFactory shopDialogFactory) { _friendIgnoreListDialogFactory = friendIgnoreListDialogFactory; _paperdollDialogFactory = paperdollDialogFactory; _activeDialogRepository = activeDialogRepository; + _shopDialogFactory = shopDialogFactory; } public void ShowFriendListDialog() @@ -56,6 +59,18 @@ public void ShowPaperdollDialog(ICharacter character, bool isMainCharacter) dlg.Show(); }); } + + public void ShowShopDialog() + { + _activeDialogRepository.ShopDialog.MatchNone(() => + { + var dlg = _shopDialogFactory.Create(); + dlg.DialogClosed += (_, _) => _activeDialogRepository.ShopDialog = Option.None(); + _activeDialogRepository.ShopDialog = Option.Some(dlg); + + dlg.Show(); + }); + } } public interface IInGameDialogActions @@ -65,5 +80,7 @@ public interface IInGameDialogActions void ShowIgnoreListDialog(); void ShowPaperdollDialog(ICharacter character, bool isMainCharacter); + + void ShowShopDialog(); } } diff --git a/EndlessClient/Dialogs/ActiveDialogRepository.cs b/EndlessClient/Dialogs/ActiveDialogRepository.cs index 99d81e9d8..97da40ac4 100644 --- a/EndlessClient/Dialogs/ActiveDialogRepository.cs +++ b/EndlessClient/Dialogs/ActiveDialogRepository.cs @@ -13,6 +13,8 @@ public interface IActiveDialogProvider : IDisposable Option PaperdollDialog { get; } + Option ShopDialog { get; } + IReadOnlyList> ActiveDialogs { get; } } @@ -20,7 +22,9 @@ public interface IActiveDialogRepository : IDisposable { Option FriendIgnoreDialog { get; set; } - Option PaperdollDialog { get; set; } + Option PaperdollDialog { get; set; } + + Option ShopDialog { get; set; } IReadOnlyList> ActiveDialogs { get; } } @@ -32,6 +36,8 @@ public class ActiveDialogRepository : IActiveDialogRepository, IActiveDialogProv public Option PaperdollDialog { get; set; } + public Option ShopDialog { get; set; } + IReadOnlyList> ActiveDialogs { get @@ -40,6 +46,7 @@ IReadOnlyList> ActiveDialogs { FriendIgnoreDialog.Map(d => (IXNADialog)d), PaperdollDialog.Map(d => (IXNADialog)d), + ShopDialog.Map(d => (IXNADialog)d), }.ToList(); } } @@ -55,6 +62,7 @@ public void Dispose() FriendIgnoreDialog = Option.None(); PaperdollDialog = Option.None(); + ShopDialog = Option.None(); } } } diff --git a/EndlessClient/Dialogs/Factories/FriendIgnoreListDialogFactory.cs b/EndlessClient/Dialogs/Factories/FriendIgnoreListDialogFactory.cs index c4a97e689..215377f7e 100644 --- a/EndlessClient/Dialogs/Factories/FriendIgnoreListDialogFactory.cs +++ b/EndlessClient/Dialogs/Factories/FriendIgnoreListDialogFactory.cs @@ -53,7 +53,7 @@ public ScrollingListDialog Create(bool isFriendList) { var textFileLines = _friendIgnoreListService.LoadList(isFriendList ? Constants.FriendListFile : Constants.IgnoreListFile); - var dialog = new ScrollingListDialog(_gameStateProvider, _nativeGraphicsManager, _dialogButtonService) + var dialog = new ScrollingListDialog(_nativeGraphicsManager, _dialogButtonService) { Buttons = ScrollingListDialogButtons.AddCancel, ListItemType = ListDialogItem.ListItemStyle.Small, diff --git a/EndlessClient/Dialogs/Factories/ShopDialogFactory.cs b/EndlessClient/Dialogs/Factories/ShopDialogFactory.cs new file mode 100644 index 000000000..5ec1e7836 --- /dev/null +++ b/EndlessClient/Dialogs/Factories/ShopDialogFactory.cs @@ -0,0 +1,69 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Services; +using EndlessClient.GameExecution; +using EndlessClient.HUD.Inventory; +using EOLib.Domain.Character; +using EOLib.Domain.Interact.Shop; +using EOLib.Graphics; +using EOLib.IO.Repositories; +using EOLib.Localization; + +namespace EndlessClient.Dialogs.Factories +{ + [AutoMappedType] + public class ShopDialogFactory : IShopDialogFactory + { + private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IItemTransferDialogFactory _itemTransferDialogFactory; + private readonly IEODialogButtonService _dialogButtonService; + private readonly IEODialogIconService _dialogIconService; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly IShopDataProvider _shopDataProvider; + private readonly ICharacterInventoryProvider _characterInventoryProvider; + private readonly IEIFFileProvider _eifFileProvider; + private readonly IInventorySpaceValidator _inventorySpaceValidator; + + public ShopDialogFactory(INativeGraphicsManager nativeGraphicsManager, + IEOMessageBoxFactory messageBoxFactory, + IItemTransferDialogFactory itemTransferDialogFactory, + IEODialogButtonService dialogButtonService, + IEODialogIconService dialogIconService, + ILocalizedStringFinder localizedStringFinder, + IShopDataProvider shopDataProvider, + ICharacterInventoryProvider characterInventoryProvider, + IEIFFileProvider eifFileProvider, + IInventorySpaceValidator inventorySpaceValidator) + { + _nativeGraphicsManager = nativeGraphicsManager; + _messageBoxFactory = messageBoxFactory; + _itemTransferDialogFactory = itemTransferDialogFactory; + _dialogButtonService = dialogButtonService; + _dialogIconService = dialogIconService; + _localizedStringFinder = localizedStringFinder; + _shopDataProvider = shopDataProvider; + _characterInventoryProvider = characterInventoryProvider; + _eifFileProvider = eifFileProvider; + _inventorySpaceValidator = inventorySpaceValidator; + } + + public ShopDialog Create() + { + return new ShopDialog(_nativeGraphicsManager, + _messageBoxFactory, + _itemTransferDialogFactory, + _dialogButtonService, + _dialogIconService, + _localizedStringFinder, + _shopDataProvider, + _characterInventoryProvider, + _eifFileProvider, + _inventorySpaceValidator); + } + } + + public interface IShopDialogFactory + { + ShopDialog Create(); + } +} diff --git a/EndlessClient/Dialogs/ListDialogItem.cs b/EndlessClient/Dialogs/ListDialogItem.cs index b7243b52c..57daecdeb 100644 --- a/EndlessClient/Dialogs/ListDialogItem.cs +++ b/EndlessClient/Dialogs/ListDialogItem.cs @@ -10,6 +10,12 @@ namespace EndlessClient.Dialogs { public class ListDialogItem : XNAControl { + public enum ListItemStyle + { + Small, + Large + } + private int _index; private int _xOffset, _yOffset; @@ -85,17 +91,13 @@ public string SubText public Texture2D IconGraphic { get; set; } + public Rectangle? IconGraphicSource { get; set; } + public bool ShowIconBackGround { get; set; } public event EventHandler RightClick; public event EventHandler LeftClick; - public enum ListItemStyle - { - Small, - Large - } - public ListDialogItem(ScrollingListDialog parent, ListItemStyle style, int listIndex = -1) { _parentList = parent; @@ -248,25 +250,24 @@ protected override void OnDrawControl(GameTime gameTime) if (Style == ListItemStyle.Large) { - var offset = new Vector2(OffsetX + 14, OffsetY + 36 * Index); - if (ShowIconBackGround) { - _spriteBatch.Draw(_gfxPadThing, DrawPositionWithParentOffset + offset + GetCoordsFromGraphic(_gfxPadThing), Color.White); + _spriteBatch.Draw(_gfxPadThing, DrawPositionWithParentOffset + GetCoordsFromGraphic(_gfxPadThing.Bounds), Color.White); } if (IconGraphic != null) { - _spriteBatch.Draw(IconGraphic, DrawPositionWithParentOffset + offset + GetCoordsFromGraphic(IconGraphic), Color.White); + var graphicOffset = IconGraphicSource.HasValue ? GetCoordsFromGraphic(IconGraphicSource.Value) : GetCoordsFromGraphic(IconGraphic.Bounds); + _spriteBatch.Draw(IconGraphic, DrawPositionWithParentOffset + graphicOffset, IconGraphicSource, Color.White); } } _spriteBatch.End(); } - private static Vector2 GetCoordsFromGraphic(Texture2D sourceTexture) + private static Vector2 GetCoordsFromGraphic(Rectangle sourceTextureArea) { - return new Vector2((float)Math.Round((64 - sourceTexture.Width) / 2f), (float)Math.Round((36 - sourceTexture.Height) / 2f)); + return new Vector2((float)Math.Round((56 - sourceTextureArea.Width) / 2f), (float)Math.Round((36 - sourceTextureArea.Height) / 2f)); } protected override void Dispose(bool disposing) diff --git a/EndlessClient/Dialogs/Old/ShopDialog.cs b/EndlessClient/Dialogs/Old/ShopDialog.cs deleted file mode 100644 index 15fd5bed9..000000000 --- a/EndlessClient/Dialogs/Old/ShopDialog.cs +++ /dev/null @@ -1,371 +0,0 @@ -using System.Collections.Generic; -using EndlessClient.Old; -using EndlessClient.Rendering; -using EOLib.Domain.Character; -using EOLib.Graphics; -using EOLib.IO; -using EOLib.Localization; -using EOLib.Net.API; -using Microsoft.Xna.Framework.Graphics; -using XNAControls.Old; - -namespace EndlessClient.Dialogs.Old -{ - public class ShopDialog : OldScrollingListDialog - { - /* Process for this: - * 1. Click shopkeeper, calls Show() - * 2. Show constructs instance and sends packet - * 3. When packet response is received, data is populated in dialog - * 4. Dialog 'closing' event resets Instance to null - */ - - /* STATIC INTERFACE */ - public static ShopDialog Instance { get; private set; } - - public static void Show(PacketAPI api, OldNPCRenderer shopKeeper) - { - if (Instance != null) - return; - - Instance = new ShopDialog(api, shopKeeper.NPC.Data.ID); - - //request from server is based on the map index - //if (!api.RequestShop(shopKeeper.NPC.Index)) - //{ - // Instance.Close(); - // Instance = null; - // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - //} - } - - private enum ShopState - { - None, - Initial, - Buying, - Selling, - Crafting - } - - public int ID { get; private set; } - - private ShopState m_state; - //private List m_tradeItems; - //private List m_craftItems; - - private static Texture2D BuyIcon, SellIcon, CraftIcon; - - private ShopDialog(PacketAPI api, int id) - : base(api) - { - Buttons = ScrollingListDialogButtons.Cancel; - ListItemType = OldListDialogItem.ListItemStyle.Large; - - ID = id; - DialogClosing += (o, e) => - { - if (e.Result == XNADialogResult.Cancel) - { - Instance = null; - ID = 0; - } - else if (e.Result == XNADialogResult.Back) - { - e.CancelClose = true; - _setState(ShopState.Initial); - } - }; - m_state = ShopState.None; - - //note - may need to lock around these. - //other note - no good way to dispose static textures like this - if (BuyIcon == null || SellIcon == null || CraftIcon == null) - { - BuyIcon = _getDlgIcon(ListIcon.Buy); - SellIcon = _getDlgIcon(ListIcon.Sell); - CraftIcon = _getDlgIcon(ListIcon.Craft); - } - } - - //public void SetShopData(int id, string Name, List tradeItems, List craftItems) - //{ - // if (Instance == null || this != Instance || ID != id) return; - // Title = Name; - - // m_tradeItems = tradeItems; - // m_craftItems = craftItems; - - // _setState(ShopState.Initial); - //} - - private void _setState(ShopState newState) - { - ShopState old = m_state; - - if (old == newState) return; - - //int buyNumInt = m_tradeItems.FindAll(x => x.Buy > 0).Count; - //int sellNumInt = m_tradeItems.FindAll(x => OldWorld.Instance.MainPlayer.ActiveCharacter.Inventory.FindIndex(item => item.ItemID == x.ID) >= 0 && x.Sell > 0).Count; - - //if (newState == ShopState.Buying && buyNumInt <= 0) - //{ - // EOMessageBox.Show(DialogResourceID.SHOP_NOTHING_IS_FOR_SALE, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - // return; - //} - - //if (newState == ShopState.Selling && sellNumInt <= 0) - //{ - // EOMessageBox.Show(DialogResourceID.SHOP_NOT_BUYING_YOUR_ITEMS, EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - // return; - //} - - ClearItemList(); - switch (newState) - { - case ShopState.Initial: - { - //string buyNum = - // $"{m_tradeItems.FindAll(x => x.Buy > 0).Count} {OldWorld.GetString(EOResourceID.DIALOG_SHOP_ITEMS_IN_STORE)}"; - //string sellNum = $"{sellNumInt} {OldWorld.GetString(EOResourceID.DIALOG_SHOP_ITEMS_ACCEPTED)}"; - //string craftNum = - // $"{m_craftItems.Count} {OldWorld.GetString(EOResourceID.DIALOG_SHOP_ITEMS_ACCEPTED)}"; - - //OldListDialogItem buy = new OldListDialogItem(this, OldListDialogItem.ListItemStyle.Large, 0) - //{ - // Text = OldWorld.GetString(EOResourceID.DIALOG_SHOP_BUY_ITEMS), - // SubText = buyNum, - // IconGraphic = BuyIcon, - // OffsetY = 45 - //}; - //buy.OnLeftClick += (o, e) => _setState(ShopState.Buying); - //buy.OnRightClick += (o, e) => _setState(ShopState.Buying); - //buy.ShowItemBackGround = false; - //AddItemToList(buy, false); - //OldListDialogItem sell = new OldListDialogItem(this, OldListDialogItem.ListItemStyle.Large, 1) - //{ - // Text = OldWorld.GetString(EOResourceID.DIALOG_SHOP_SELL_ITEMS), - // SubText = sellNum, - // IconGraphic = SellIcon, - // OffsetY = 45 - //}; - //sell.OnLeftClick += (o, e) => _setState(ShopState.Selling); - //sell.OnRightClick += (o, e) => _setState(ShopState.Selling); - //sell.ShowItemBackGround = false; - //AddItemToList(sell, false); - //if (m_craftItems.Count > 0) - //{ - // OldListDialogItem craft = new OldListDialogItem(this, OldListDialogItem.ListItemStyle.Large, 2) - // { - // Text = OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_ITEMS), - // SubText = craftNum, - // IconGraphic = CraftIcon, - // OffsetY = 45 - // }; - // craft.OnLeftClick += (o, e) => _setState(ShopState.Crafting); - // craft.OnRightClick += (o, e) => _setState(ShopState.Crafting); - // craft.ShowItemBackGround = false; - // AddItemToList(craft, false); - //} - _setButtons(ScrollingListDialogButtons.Cancel); - } - break; - case ShopState.Buying: - case ShopState.Selling: - { - //re-use the logic for Buying/Selling: it is almost identical - bool buying = newState == ShopState.Buying; - - List itemList = new List(); - //foreach (ShopItem si in m_tradeItems) - //{ - // if (si.ID <= 0 || (buying && si.Buy <= 0) || - // (!buying && (si.Sell <= 0 || OldWorld.Instance.MainPlayer.ActiveCharacter.Inventory.FindIndex(inv => inv.ItemID == si.ID) < 0))) - // continue; - - // ShopItem localItem = si; - // var rec = OldWorld.Instance.EIF[si.ID]; - // string secondary = string.Format("{2}: {0} {1}", buying ? si.Buy : si.Sell, - // rec.Type == ItemType.Armor ? "(" + (rec.Gender == 0 ? OldWorld.GetString(EOResourceID.FEMALE) : OldWorld.GetString(EOResourceID.MALE)) + ")" : "", - // OldWorld.GetString(EOResourceID.DIALOG_SHOP_PRICE)); - - // OldListDialogItem nextItem = new OldListDialogItem(this, OldListDialogItem.ListItemStyle.Large) - // { - // Text = rec.Name, - // SubText = secondary, - // IconGraphic = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.Items, 2 * rec.Graphic - 1, true), - // OffsetY = 45 - // }; - // nextItem.OnLeftClick += (o, e) => _buySellItem(localItem); - // nextItem.OnRightClick += (o, e) => _buySellItem(localItem); - - // itemList.Add(nextItem); - //} - SetItemList(itemList); - _setButtons(ScrollingListDialogButtons.BackCancel); - } - break; - case ShopState.Crafting: - { - //List itemList = new List(m_craftItems.Count); - //foreach (CraftItem ci in m_craftItems) - //{ - // if (ci.Ingredients.Count <= 0) continue; - - // CraftItem localItem = ci; - // var rec = OldWorld.Instance.EIF[ci.ID]; - // string secondary = string.Format("{2}: {0} {1}", ci.Ingredients.Count, - // rec.Type == ItemType.Armor ? "(" + (rec.Gender == 0 ? OldWorld.GetString(EOResourceID.FEMALE) : OldWorld.GetString(EOResourceID.MALE)) + ")" : "", - // OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_INGREDIENTS)); - - // OldListDialogItem nextItem = new OldListDialogItem(this, OldListDialogItem.ListItemStyle.Large) - // { - // Text = rec.Name, - // SubText = secondary, - // IconGraphic = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.Items, 2 * rec.Graphic - 1, true), - // OffsetY = 45 - // }; - // nextItem.OnLeftClick += (o, e) => _craftItem(localItem); - // nextItem.OnRightClick += (o, e) => _craftItem(localItem); - - // itemList.Add(nextItem); - //} - //SetItemList(itemList); - _setButtons(ScrollingListDialogButtons.BackCancel); - } - break; - } - - m_state = newState; - } - - private void _buySellItem(object item) - { - //if (m_state != ShopState.Buying && m_state != ShopState.Selling) - // return; - //bool isBuying = m_state == ShopState.Buying; - - //InventoryItem ii = OldWorld.Instance.MainPlayer.ActiveCharacter.Inventory.Find(x => (isBuying ? x.ItemID == 1 : x.ItemID == item.ID)); - //var rec = OldWorld.Instance.EIF[item.ID]; - //if (isBuying) - //{ - // if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) - // { - // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), - // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - // return; - // } - - // if (rec.Weight + OldWorld.Instance.MainPlayer.ActiveCharacter.Weight > - // OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight) - // { - // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_WEIGHT), - // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - // return; - // } - - // if (ii.Amount < item.Buy) - // { - // EOMessageBox.Show(DialogResourceID.WARNING_YOU_HAVE_NOT_ENOUGH, " gold.", EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - // return; - // } - //} - //else if (ii.Amount == 0) - // return; //can't sell if amount of item is 0 - - ////special case: no need for prompting if selling an item with count == 1 in inventory - //if (!isBuying && ii.Amount == 1) - //{ - // string _message = - // $"{OldWorld.GetString(EOResourceID.DIALOG_WORD_SELL)} 1 {rec.Name} {OldWorld.GetString(EOResourceID.DIALOG_WORD_FOR)} {item.Sell} gold?"; - // EOMessageBox.Show(_message, OldWorld.GetString(EOResourceID.DIALOG_SHOP_SELL_ITEMS), EODialogButtons.OkCancel, - // EOMessageBoxStyle.SmallDialogSmallHeader, (oo, ee) => - // { - // if (ee.Result == XNADialogResult.OK && !m_api.SellItem((short)item.ID, 1)) - // { - // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - // } - // }); - //} - //else - //{ - // ItemTransferDialog dlg = new ItemTransferDialog(rec.Name, ItemTransferDialog.TransferType.ShopTransfer, - // isBuying ? item.MaxBuy : ii.Amount, isBuying ? EOResourceID.DIALOG_TRANSFER_BUY : EOResourceID.DIALOG_TRANSFER_SELL); - // dlg.DialogClosing += (o, e) => - // { - // if (e.Result == XNADialogResult.OK) - // { - // string _message = - // $"{OldWorld.GetString(isBuying ? EOResourceID.DIALOG_WORD_BUY : EOResourceID.DIALOG_WORD_SELL)} {dlg.SelectedAmount} {rec.Name} {OldWorld.GetString(EOResourceID.DIALOG_WORD_FOR)} {(isBuying ? item.Buy : item.Sell)*dlg.SelectedAmount} gold?"; - - // EOMessageBox.Show(_message, - // OldWorld.GetString(isBuying ? EOResourceID.DIALOG_SHOP_BUY_ITEMS : EOResourceID.DIALOG_SHOP_SELL_ITEMS), - // EODialogButtons.OkCancel, EOMessageBoxStyle.SmallDialogSmallHeader, (oo, ee) => - // { - // if (ee.Result == XNADialogResult.OK) - // { - // //only actually do the buy/sell if the user then clicks "OK" in the second prompt - // if (isBuying && !m_api.BuyItem((short)item.ID, dlg.SelectedAmount) || - // !isBuying && !m_api.SellItem((short)item.ID, dlg.SelectedAmount)) - // { - // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - // } - // } - // }); - // } - // }; - //} - } - - private void _craftItem(object item) - { - //if (m_state != ShopState.Crafting) - // return; - - //var craftItemRec = OldWorld.Instance.EIF[item.ID]; - //// ReSharper disable once LoopCanBeConvertedToQuery - //foreach (var ingredient in item.Ingredients) - //{ - // if (OldWorld.Instance.MainPlayer.ActiveCharacter.Inventory.FindIndex(_item => _item.ItemID == ingredient.Item1 && _item.Amount >= ingredient.Item2) < 0) - // { - // string _message = OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_MISSING_INGREDIENTS) + "\n\n"; - // foreach (var ingred in item.Ingredients) - // { - // var localRec = OldWorld.Instance.EIF[ingred.Item1]; - // _message += $"+ {ingred.Item2} {localRec.Name}\n"; - // } - // string _caption = - // $"{OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_INGREDIENTS)} {OldWorld.GetString(EOResourceID.DIALOG_WORD_FOR)} {craftItemRec.Name}"; - // EOMessageBox.Show(_message, _caption, EODialogButtons.Cancel, EOMessageBoxStyle.LargeDialogSmallHeader); - // return; - // } - //} - - //if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) - //{ - // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), - // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), - // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); - // return; - //} - - //string _message2 = OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_PUT_INGREDIENTS_TOGETHER) + "\n\n"; - //foreach (var ingred in item.Ingredients) - //{ - // var localRec = OldWorld.Instance.EIF[ingred.Item1]; - // _message2 += $"+ {ingred.Item2} {localRec.Name}\n"; - //} - //string _caption2 = - // $"{OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_INGREDIENTS)} {OldWorld.GetString(EOResourceID.DIALOG_WORD_FOR)} {craftItemRec.Name}"; - //EOMessageBox.Show(_message2, _caption2, EODialogButtons.OkCancel, EOMessageBoxStyle.LargeDialogSmallHeader, (o, e) => - //{ - // if (e.Result == XNADialogResult.OK && !m_api.CraftItem((short)item.ID)) - // { - // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - // } - //}); - } - } -} diff --git a/EndlessClient/Dialogs/ScrollingListDialog.cs b/EndlessClient/Dialogs/ScrollingListDialog.cs index d1bea287e..24c494869 100644 --- a/EndlessClient/Dialogs/ScrollingListDialog.cs +++ b/EndlessClient/Dialogs/ScrollingListDialog.cs @@ -1,12 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using EndlessClient.Dialogs.Services; -using EndlessClient.GameExecution; +using EndlessClient.Dialogs.Services; using EndlessClient.UIControls; using EOLib; using EOLib.Graphics; using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using System.Linq; using XNAControls; namespace EndlessClient.Dialogs @@ -32,6 +31,9 @@ public class ScrollingListDialog : BaseEODialog private ScrollingListDialogButtons _buttons; + // cancel button debounce + private bool _otherClicked; + public IReadOnlyList NamesList => _listItems.Select(item => item.PrimaryText).ToList(); public string Title @@ -48,6 +50,7 @@ public ListDialogItem.ListItemStyle ListItemType set { _listItemType = value; + ItemsToShow = _listItemType == ListDialogItem.ListItemStyle.Large ? 5 : 12; _scrollBar.LinesToRender = ItemsToShow; } } @@ -80,10 +83,9 @@ static ScrollingListDialog() _cancelButtonCenteredPosition = new Vector2(96, 252); } - public ScrollingListDialog(IGameStateProvider gameStateProvider, - INativeGraphicsManager nativeGraphicsManager, + public ScrollingListDialog(INativeGraphicsManager nativeGraphicsManager, IEODialogButtonService dialogButtonService) - : base(gameStateProvider) + : base(isInGame: true) { _listItems = new List(); @@ -104,30 +106,35 @@ static ScrollingListDialog() dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Add), dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.Add)) { - Visible = false + Visible = false, + UpdateOrder = 1, }; _add.SetParentControl(this); _add.OnClick += (o, e) => AddAction?.Invoke(o, e); + AddAction += (_, _) => _otherClicked = true; _back = new XNAButton(dialogButtonService.SmallButtonSheet, new Vector2(48, 252), dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Back), dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.Back)) { - Visible = false + Visible = false, + UpdateOrder = 1, }; _back.SetParentControl(this); _back.OnClick += (o, e) => BackAction?.Invoke(o, e); + BackAction += (_, _) => _otherClicked = true; _cancel = new XNAButton(dialogButtonService.SmallButtonSheet, _cancelButtonRightPosition, dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Cancel), dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.Cancel)) { - Visible = true + Visible = true, + UpdateOrder = 2, }; _cancel.SetParentControl(this); - _cancel.OnClick += (_, _) => Close(XNADialogResult.Cancel); + _cancel.OnClick += (_, _) => { if (!_otherClicked) { Close(XNADialogResult.Cancel); } }; ItemsToShow = ListItemType == ListDialogItem.ListItemStyle.Large ? 5 : 12; @@ -215,8 +222,6 @@ public override void Initialize() protected override void OnUpdateControl(GameTime gameTime) { - base.OnUpdateControl(gameTime); - ChildControlClickHandled = false; if (_listItems.Count > _scrollBar.LinesToRender) @@ -245,6 +250,10 @@ protected override void OnUpdateControl(GameTime gameTime) { _listItems.ForEach(_item => _item.Visible = true); } + + base.OnUpdateControl(gameTime); + + _otherClicked = false; } } } diff --git a/EndlessClient/Dialogs/ShopDialog.cs b/EndlessClient/Dialogs/ShopDialog.cs new file mode 100644 index 000000000..89053c3ac --- /dev/null +++ b/EndlessClient/Dialogs/ShopDialog.cs @@ -0,0 +1,361 @@ +using EndlessClient.Dialogs.Factories; +using EndlessClient.Dialogs.Services; +using EndlessClient.HUD.Inventory; +using EOLib.Domain.Character; +using EOLib.Domain.Interact.Shop; +using EOLib.Graphics; +using EOLib.IO.Repositories; +using EOLib.Localization; +using Microsoft.Xna.Framework; +using Optional; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace EndlessClient.Dialogs +{ + public class ShopDialog : ScrollingListDialog + { + private enum ShopState + { + None, + Initial, + Buying, + Selling, + Crafting + } + + private readonly IEOMessageBoxFactory _messageBoxFactory; + private readonly IItemTransferDialogFactory _itemTransferDialogFactory; + private readonly IEODialogIconService _dialogIconService; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly IShopDataProvider _shopDataProvider; + private readonly ICharacterInventoryProvider _characterInventoryProvider; + private readonly IEIFFileProvider _eifFileProvider; + private readonly IInventorySpaceValidator _inventorySpaceValidator; + private IReadOnlyList _buyItems, _sellItems; + private IReadOnlyList _craftItems; + + private ShopState _state; + + private Option _cachedShopId; + + public ShopDialog(INativeGraphicsManager nativeGraphicsManager, + IEOMessageBoxFactory messageBoxFactory, + IItemTransferDialogFactory itemTransferDialogFactory, + IEODialogButtonService dialogButtonService, + IEODialogIconService dialogIconService, + ILocalizedStringFinder localizedStringFinder, + IShopDataProvider shopDataProvider, + ICharacterInventoryProvider characterInventoryProvider, + IEIFFileProvider eifFileProvider, + IInventorySpaceValidator inventorySpaceValidator) + : base(nativeGraphicsManager, dialogButtonService) + { + _messageBoxFactory = messageBoxFactory; + _itemTransferDialogFactory = itemTransferDialogFactory; + _dialogIconService = dialogIconService; + _localizedStringFinder = localizedStringFinder; + _shopDataProvider = shopDataProvider; + _characterInventoryProvider = characterInventoryProvider; + _eifFileProvider = eifFileProvider; + _inventorySpaceValidator = inventorySpaceValidator; + + Buttons = ScrollingListDialogButtons.Cancel; + ListItemType = ListDialogItem.ListItemStyle.Large; + + BackAction += (_, _) => SetState(ShopState.Initial); + } + + protected override void OnUpdateControl(GameTime gameTime) + { + _cachedShopId.MatchNone(() => + { + _shopDataProvider.ShopID.SomeWhen(x => x > 0) + .MatchSome(x => + { + _cachedShopId = Option.Some(_shopDataProvider.ShopID); + + Title = _shopDataProvider.ShopName; + + _buyItems = _shopDataProvider.TradeItems.Where(x => x.Buy > 0).ToList(); + _sellItems = _shopDataProvider.TradeItems.Where(x => x.Sell > 0 && _characterInventoryProvider.ItemInventory.Any(inv => inv.ItemID == x.ID && inv.Amount > 0)).ToList(); + _craftItems = _shopDataProvider.CraftItems; + + SetState(ShopState.Initial); + }); + }); + + base.OnUpdateControl(gameTime); + } + + private void SetState(ShopState state) + { + if (_state == state || state == ShopState.None) + return; + + if (state == ShopState.Buying && _buyItems.Count == 0) + { + var msg = _messageBoxFactory.CreateMessageBox(DialogResourceID.SHOP_NOTHING_IS_FOR_SALE); + msg.ShowDialog(); + return; + } + + if (state == ShopState.Selling && _sellItems.Count == 0) + { + var msg = _messageBoxFactory.CreateMessageBox(DialogResourceID.SHOP_NOT_BUYING_YOUR_ITEMS); + msg.ShowDialog(); + return; + } + + ClearItemList(); + + switch (state) + { + case ShopState.Initial: + { + var buyItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large) + { + PrimaryText = _localizedStringFinder.GetString(EOResourceID.DIALOG_SHOP_BUY_ITEMS), + SubText = $"{_buyItems.Count} {_localizedStringFinder.GetString(EOResourceID.DIALOG_SHOP_ITEMS_IN_STORE)}", + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.Buy), + ShowIconBackGround = false, + OffsetY = 45, + }; + buyItem.LeftClick += (_, _) => SetState(ShopState.Buying); + buyItem.Initialize(); + + var sellItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large) + { + PrimaryText = _localizedStringFinder.GetString(EOResourceID.DIALOG_SHOP_SELL_ITEMS), + SubText = $"{_sellItems.Count} {_localizedStringFinder.GetString(EOResourceID.DIALOG_SHOP_ITEMS_ACCEPTED)}", + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.Sell), + ShowIconBackGround = false, + OffsetY = 45, + }; + sellItem.LeftClick += (_, _) => SetState(ShopState.Selling); + sellItem.Initialize(); + + var craftItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large) + { + PrimaryText = _localizedStringFinder.GetString(EOResourceID.DIALOG_SHOP_CRAFT_ITEMS), + SubText = $"{_craftItems.Count} {_localizedStringFinder.GetString(EOResourceID.DIALOG_SHOP_ITEMS_ACCEPTED)}", + IconGraphic = _dialogIconService.IconSheet, + IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.Craft), + ShowIconBackGround = false, + OffsetY = 45, + }; + craftItem.LeftClick += (_, _) => SetState(ShopState.Crafting); + craftItem.Initialize(); + + AddItemToList(buyItem, sortList: false); + AddItemToList(sellItem, sortList: false); + AddItemToList(craftItem, sortList: false); + + Buttons = ScrollingListDialogButtons.Cancel; + } + break; + + case ShopState.Buying: + case ShopState.Selling: + { + var buying = state == ShopState.Buying; + var items = new List(); + foreach (var item in buying ? _buyItems : _sellItems) + { + var data = _eifFileProvider.EIFFile[item.ID]; + var genderExtra = data.Type == EOLib.IO.ItemType.Armor ? $"({_localizedStringFinder.GetString(EOResourceID.FEMALE - data.Gender)})" : string.Empty; + var subText = $"{_localizedStringFinder.GetString(EOResourceID.DIALOG_SHOP_PRICE)}: {(buying ? item.Buy : item.Sell)} {genderExtra}"; + + var listItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large) + { + PrimaryText = data.Name, + SubText = subText, + IconGraphic = GraphicsManager.TextureFromResource(GFXTypes.Items, 2 * data.Graphic - 1, transparent: true), + OffsetY = 45 + }; + listItem.LeftClick += TradeItem; + listItem.RightClick += TradeItem; + listItem.Initialize(); + + items.Add(listItem); + } + + SetItemList(items); + Buttons = ScrollingListDialogButtons.BackCancel; + } + break; + + case ShopState.Crafting: + { + var items = new List(); + foreach (var item in _craftItems.Where(x => x.Ingredients.Count > 0)) + { + var data = _eifFileProvider.EIFFile[item.ID]; + var genderExtra = data.Type == EOLib.IO.ItemType.Armor ? $"({_localizedStringFinder.GetString(EOResourceID.FEMALE - data.Gender)})" : string.Empty; + var subText = $"{_localizedStringFinder.GetString(EOResourceID.DIALOG_SHOP_CRAFT_INGREDIENTS)}: {item.Ingredients.Count} {genderExtra}"; + + var listItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large) + { + PrimaryText = data.Name, + SubText = subText, + IconGraphic = GraphicsManager.TextureFromResource(GFXTypes.Items, 2 * data.Graphic - 1, transparent: true), + OffsetY = 45 + }; + listItem.LeftClick += CraftItem; + listItem.RightClick += CraftItem; + listItem.Initialize(); + + items.Add(listItem); + } + + SetItemList(items); + Buttons = ScrollingListDialogButtons.BackCancel; + } + break; + } + + _state = state; + } + + private void TradeItem(object sender, EventArgs e) + { + var listItemIndex = ((ListDialogItem)sender).Index; + var buying = _state == ShopState.Buying; + + var shopItem = (buying ? _buyItems : _sellItems)[listItemIndex]; + + //if (m_state != ShopState.Buying && m_state != ShopState.Selling) + // return; + //bool isBuying = m_state == ShopState.Buying; + + //InventoryItem ii = OldWorld.Instance.MainPlayer.ActiveCharacter.Inventory.Find(x => (isBuying ? x.ItemID == 1 : x.ItemID == item.ID)); + //var rec = OldWorld.Instance.EIF[item.ID]; + //if (isBuying) + //{ + // if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) + // { + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // return; + // } + + // if (rec.Weight + OldWorld.Instance.MainPlayer.ActiveCharacter.Weight > + // OldWorld.Instance.MainPlayer.ActiveCharacter.MaxWeight) + // { + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_WEIGHT), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // return; + // } + + // if (ii.Amount < item.Buy) + // { + // EOMessageBox.Show(DialogResourceID.WARNING_YOU_HAVE_NOT_ENOUGH, " gold.", EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // return; + // } + //} + //else if (ii.Amount == 0) + // return; //can't sell if amount of item is 0 + + ////special case: no need for prompting if selling an item with count == 1 in inventory + //if (!isBuying && ii.Amount == 1) + //{ + // string _message = + // $"{OldWorld.GetString(EOResourceID.DIALOG_WORD_SELL)} 1 {rec.Name} {OldWorld.GetString(EOResourceID.DIALOG_WORD_FOR)} {item.Sell} gold?"; + // EOMessageBox.Show(_message, OldWorld.GetString(EOResourceID.DIALOG_SHOP_SELL_ITEMS), EODialogButtons.OkCancel, + // EOMessageBoxStyle.SmallDialogSmallHeader, (oo, ee) => + // { + // if (ee.Result == XNADialogResult.OK && !m_api.SellItem((short)item.ID, 1)) + // { + // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + // } + // }); + //} + //else + //{ + // ItemTransferDialog dlg = new ItemTransferDialog(rec.Name, ItemTransferDialog.TransferType.ShopTransfer, + // isBuying ? item.MaxBuy : ii.Amount, isBuying ? EOResourceID.DIALOG_TRANSFER_BUY : EOResourceID.DIALOG_TRANSFER_SELL); + // dlg.DialogClosing += (o, e) => + // { + // if (e.Result == XNADialogResult.OK) + // { + // string _message = + // $"{OldWorld.GetString(isBuying ? EOResourceID.DIALOG_WORD_BUY : EOResourceID.DIALOG_WORD_SELL)} {dlg.SelectedAmount} {rec.Name} {OldWorld.GetString(EOResourceID.DIALOG_WORD_FOR)} {(isBuying ? item.Buy : item.Sell)*dlg.SelectedAmount} gold?"; + + // EOMessageBox.Show(_message, + // OldWorld.GetString(isBuying ? EOResourceID.DIALOG_SHOP_BUY_ITEMS : EOResourceID.DIALOG_SHOP_SELL_ITEMS), + // EODialogButtons.OkCancel, EOMessageBoxStyle.SmallDialogSmallHeader, (oo, ee) => + // { + // if (ee.Result == XNADialogResult.OK) + // { + // //only actually do the buy/sell if the user then clicks "OK" in the second prompt + // if (isBuying && !m_api.BuyItem((short)item.ID, dlg.SelectedAmount) || + // !isBuying && !m_api.SellItem((short)item.ID, dlg.SelectedAmount)) + // { + // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + // } + // } + // }); + // } + // }; + //} + } + + private void CraftItem(object sender, EventArgs e) + { + var listItemIndex = ((ListDialogItem)sender).Index; + + var craftItem = _craftItems[listItemIndex]; + + //if (m_state != ShopState.Crafting) + // return; + + //var craftItemRec = OldWorld.Instance.EIF[item.ID]; + //// ReSharper disable once LoopCanBeConvertedToQuery + //foreach (var ingredient in item.Ingredients) + //{ + // if (OldWorld.Instance.MainPlayer.ActiveCharacter.Inventory.FindIndex(_item => _item.ItemID == ingredient.Item1 && _item.Amount >= ingredient.Item2) < 0) + // { + // string _message = OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_MISSING_INGREDIENTS) + "\n\n"; + // foreach (var ingred in item.Ingredients) + // { + // var localRec = OldWorld.Instance.EIF[ingred.Item1]; + // _message += $"+ {ingred.Item2} {localRec.Name}\n"; + // } + // string _caption = + // $"{OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_INGREDIENTS)} {OldWorld.GetString(EOResourceID.DIALOG_WORD_FOR)} {craftItemRec.Name}"; + // EOMessageBox.Show(_message, _caption, EODialogButtons.Cancel, EOMessageBoxStyle.LargeDialogSmallHeader); + // return; + // } + //} + + //if (!EOGame.Instance.Hud.InventoryFits((short)item.ID)) + //{ + // EOMessageBox.Show(OldWorld.GetString(EOResourceID.DIALOG_TRANSFER_NOT_ENOUGH_SPACE), + // OldWorld.GetString(EOResourceID.STATUS_LABEL_TYPE_WARNING), + // EODialogButtons.Ok, EOMessageBoxStyle.SmallDialogSmallHeader); + // return; + //} + + //string _message2 = OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_PUT_INGREDIENTS_TOGETHER) + "\n\n"; + //foreach (var ingred in item.Ingredients) + //{ + // var localRec = OldWorld.Instance.EIF[ingred.Item1]; + // _message2 += $"+ {ingred.Item2} {localRec.Name}\n"; + //} + //string _caption2 = + // $"{OldWorld.GetString(EOResourceID.DIALOG_SHOP_CRAFT_INGREDIENTS)} {OldWorld.GetString(EOResourceID.DIALOG_WORD_FOR)} {craftItemRec.Name}"; + //EOMessageBox.Show(_message2, _caption2, EODialogButtons.OkCancel, EOMessageBoxStyle.LargeDialogSmallHeader, (o, e) => + //{ + // if (e.Result == XNADialogResult.OK && !m_api.CraftItem((short)item.ID)) + // { + // EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); + // } + //}); + } + } +} diff --git a/EndlessClient/Old/OldWorld.cs b/EndlessClient/Old/OldWorld.cs index 4b40f90ec..2a4ff2a59 100644 --- a/EndlessClient/Old/OldWorld.cs +++ b/EndlessClient/Old/OldWorld.cs @@ -284,7 +284,6 @@ public void Remap() public static void IgnoreDialogs(XNAControl control) { control.IgnoreDialog(typeof(ChestDialog)); - control.IgnoreDialog(typeof(ShopDialog)); control.IgnoreDialog(typeof(BankAccountDialog)); control.IgnoreDialog(typeof(LockerDialog)); control.IgnoreDialog(typeof(TradeDialog)); diff --git a/EndlessClient/Rendering/MouseCursorRenderer.cs b/EndlessClient/Rendering/MouseCursorRenderer.cs index 5d14b39e7..d9c51f0a9 100644 --- a/EndlessClient/Rendering/MouseCursorRenderer.cs +++ b/EndlessClient/Rendering/MouseCursorRenderer.cs @@ -290,7 +290,7 @@ private void CheckForClicks(IMapCellState cellState) var currentMouseState = _userInputProvider.CurrentMouseState; var previousMouseState = _userInputProvider.PreviousMouseState; - // todo: some left clicks should be on the graphic itself instead of based on the grid where the cursor is (NPC, map sign, board, etc.) + // todo: some left clicks should be on the graphic itself instead of based on the grid where the cursor is (map sign, board, etc.) if (currentMouseState.LeftButton == ButtonState.Released && previousMouseState.LeftButton == ButtonState.Pressed) { diff --git a/EndlessClient/Rendering/NPC/NPCRenderer.cs b/EndlessClient/Rendering/NPC/NPCRenderer.cs index 9fd8b09a0..d6bfe02bb 100644 --- a/EndlessClient/Rendering/NPC/NPCRenderer.cs +++ b/EndlessClient/Rendering/NPC/NPCRenderer.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using EndlessClient.Controllers; using EndlessClient.GameExecution; using EndlessClient.Rendering.Character; using EndlessClient.Rendering.Chat; @@ -31,6 +32,7 @@ public class NPCRenderer : DrawableGameComponent, INPCRenderer private readonly IRenderOffsetCalculator _renderOffsetCalculator; private readonly IHealthBarRendererFactory _healthBarRendererFactory; private readonly IChatBubbleFactory _chatBubbleFactory; + private readonly INPCInteractionController _npcInteractionController; private readonly Rectangle _baseTextureFrameRectangle; private readonly int _readonlyTopPixel, _readonlyBottomPixel; private readonly bool _hasStandingAnimation; @@ -72,6 +74,7 @@ public class NPCRenderer : DrawableGameComponent, INPCRenderer IRenderOffsetCalculator renderOffsetCalculator, IHealthBarRendererFactory healthBarRendererFactory, IChatBubbleFactory chatBubbleFactory, + INPCInteractionController npcInteractionController, INPC initialNPC) : base((Game)endlessGameProvider.Game) { @@ -83,6 +86,7 @@ public class NPCRenderer : DrawableGameComponent, INPCRenderer _renderOffsetCalculator = renderOffsetCalculator; _healthBarRendererFactory = healthBarRendererFactory; _chatBubbleFactory = chatBubbleFactory; + _npcInteractionController = npcInteractionController; _baseTextureFrameRectangle = GetStandingFrameRectangle(); _readonlyTopPixel = GetTopPixel(); _readonlyBottomPixel = GetBottomPixel(); @@ -134,6 +138,13 @@ public override void Update(GameTime gameTime) _nameLabel.Visible = DrawArea.Contains(_currentMouseState.Position) && !_healthBarRenderer.Visible && !_isDying; _nameLabel.DrawPosition = GetNameLabelPosition(); + if (DrawArea.ContainsPoint(_currentMouseState.X, _currentMouseState.Y) && + _currentMouseState.LeftButton == ButtonState.Released && + _previousMouseState.LeftButton == ButtonState.Pressed) + { + _npcInteractionController.ShowNPCDialog(NPC); + } + _effectRenderer.Update(); _healthBarRenderer.Update(gameTime); diff --git a/EndlessClient/Rendering/NPC/NPCRendererFactory.cs b/EndlessClient/Rendering/NPC/NPCRendererFactory.cs index cae337355..a67f1e404 100644 --- a/EndlessClient/Rendering/NPC/NPCRendererFactory.cs +++ b/EndlessClient/Rendering/NPC/NPCRendererFactory.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using EndlessClient.Controllers; using EndlessClient.GameExecution; using EndlessClient.Rendering.Character; using EndlessClient.Rendering.Chat; @@ -21,6 +22,7 @@ public class NPCRendererFactory : INPCRendererFactory private readonly IRenderOffsetCalculator _renderOffsetCalculator; private readonly IHealthBarRendererFactory _healthBarRendererFactory; private readonly IChatBubbleFactory _chatBubbleFactory; + private readonly INPCInteractionController _npcInteractionController; public NPCRendererFactory(INativeGraphicsManager nativeGraphicsManager, IEndlessGameProvider endlessGameProvider, @@ -29,7 +31,8 @@ public class NPCRendererFactory : INPCRendererFactory INPCSpriteSheet npcSpriteSheet, IRenderOffsetCalculator renderOffsetCalculator, IHealthBarRendererFactory healthBarRendererFactory, - IChatBubbleFactory chatBubbleFactory) + IChatBubbleFactory chatBubbleFactory, + INPCInteractionController npcInteractionController) { _nativeGraphicsManager = nativeGraphicsManager; _endlessGameProvider = endlessGameProvider; @@ -39,6 +42,7 @@ public class NPCRendererFactory : INPCRendererFactory _renderOffsetCalculator = renderOffsetCalculator; _healthBarRendererFactory = healthBarRendererFactory; _chatBubbleFactory = chatBubbleFactory; + _npcInteractionController = npcInteractionController; } public INPCRenderer CreateRendererFor(INPC npc) @@ -51,6 +55,7 @@ public INPCRenderer CreateRendererFor(INPC npc) _renderOffsetCalculator, _healthBarRendererFactory, _chatBubbleFactory, + _npcInteractionController, npc); } } diff --git a/EndlessClient/Rendering/OldNPCRenderer.cs b/EndlessClient/Rendering/OldNPCRenderer.cs index 6c9504022..364fe132d 100644 --- a/EndlessClient/Rendering/OldNPCRenderer.cs +++ b/EndlessClient/Rendering/OldNPCRenderer.cs @@ -332,7 +332,6 @@ private void HandleLeftClick() PacketAPI api = ((EOGame)Game).API; switch (NPC.Data.Type) { - case NPCType.Shop: ShopDialog.Show(api, this); break; case NPCType.Inn: break; case NPCType.Bank: BankAccountDialog.Show(api, NPC.Index); break; case NPCType.Barber: break;