diff --git a/EOLib/Domain/Jukebox/JukeboxActions.cs b/EOLib/Domain/Interact/Jukebox/JukeboxActions.cs similarity index 96% rename from EOLib/Domain/Jukebox/JukeboxActions.cs rename to EOLib/Domain/Interact/Jukebox/JukeboxActions.cs index 254b9c8b4..c87ae58be 100644 --- a/EOLib/Domain/Jukebox/JukeboxActions.cs +++ b/EOLib/Domain/Interact/Jukebox/JukeboxActions.cs @@ -1,5 +1,6 @@ using AutomaticTypeMapper; using EOLib.Domain.Character; +using EOLib.Domain.Map; using EOLib.IO; using EOLib.IO.Repositories; using EOLib.Net; @@ -7,7 +8,7 @@ using Optional.Collections; using System; -namespace EOLib.Domain.Jukebox +namespace EOLib.Domain.Interact.Jukebox { [AutoMappedType] public class JukeboxActions : IJukeboxActions diff --git a/EOLib/Domain/Interact/Board/BoardMapEntity.cs b/EOLib/Domain/Interact/TileSpecMapEntity.cs similarity index 59% rename from EOLib/Domain/Interact/Board/BoardMapEntity.cs rename to EOLib/Domain/Interact/TileSpecMapEntity.cs index 641cfff48..832cd1c01 100644 --- a/EOLib/Domain/Interact/Board/BoardMapEntity.cs +++ b/EOLib/Domain/Interact/TileSpecMapEntity.cs @@ -1,10 +1,10 @@ using Amadevus.RecordGenerator; using EOLib.IO.Map; -namespace EOLib.Domain.Interact.Board +namespace EOLib.Domain.Interact { [Record] - public sealed partial class BoardMapEntity : IMapEntity + public sealed partial class TileSpecMapEntity : IMapEntity { public int X { get; } diff --git a/EOLib/Domain/Map/MapActions.cs b/EOLib/Domain/Map/MapActions.cs index c2115ca73..742548cbd 100644 --- a/EOLib/Domain/Map/MapActions.cs +++ b/EOLib/Domain/Map/MapActions.cs @@ -91,6 +91,16 @@ public void OpenBoard(TileSpec boardSpec) _packetSendService.SendPacket(packet); } + + public void OpenJukebox(MapCoordinate location) + { + var packet = new PacketBuilder(PacketFamily.JukeBox, PacketAction.Open) + .AddChar(location.X) + .AddChar(location.Y) + .Build(); + + _packetSendService.SendPacket(packet); + } } public interface IMapActions @@ -106,5 +116,7 @@ public interface IMapActions void OpenLocker(MapCoordinate location); void OpenBoard(TileSpec boardSpec); + + void OpenJukebox(MapCoordinate location); } } diff --git a/EndlessClient/Controllers/BardController.cs b/EndlessClient/Controllers/BardController.cs index dd84763a9..c7796dbfa 100644 --- a/EndlessClient/Controllers/BardController.cs +++ b/EndlessClient/Controllers/BardController.cs @@ -2,7 +2,7 @@ using EndlessClient.Rendering.Character; using EOLib.Domain.Character; using EOLib.Domain.Extensions; -using EOLib.Domain.Jukebox; +using EOLib.Domain.Interact.Jukebox; namespace EndlessClient.Controllers { diff --git a/EndlessClient/Controllers/MapInteractionController.cs b/EndlessClient/Controllers/MapInteractionController.cs index aff398bd8..bf78134aa 100644 --- a/EndlessClient/Controllers/MapInteractionController.cs +++ b/EndlessClient/Controllers/MapInteractionController.cs @@ -160,7 +160,11 @@ public void LeftClick(IMapCellState cellState) } break; case TileSpec.Jukebox: - // todo + if (unwalkableAction == UnwalkableTileAction.Jukebox) + { + _mapActions.OpenJukebox(cellState.Coordinate); + _inGameDialogActions.ShowJukeboxDialog(); + } break; } } diff --git a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs index 7e526a723..9de600b3a 100644 --- a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs @@ -34,6 +34,7 @@ public class InGameDialogActions : IInGameDialogActions private readonly IScrollingListDialogFactory _scrollingListDialogFactory; private readonly ITradeDialogFactory _tradeDialogFactory; private readonly IBoardDialogFactory _boardDialogFactory; + private readonly IJukeboxDialogFactory _jukeboxDialogFactory; private readonly ISfxPlayer _sfxPlayer; private readonly IStatusLabelSetter _statusLabelSetter; private readonly IShopDialogFactory _shopDialogFactory; @@ -57,6 +58,7 @@ public class InGameDialogActions : IInGameDialogActions IScrollingListDialogFactory scrollingListDialogFactory, ITradeDialogFactory tradeDialogFactory, IBoardDialogFactory boardDialogFactory, + IJukeboxDialogFactory jukeboxDialogFactory, ISfxPlayer sfxPlayer, IStatusLabelSetter statusLabelSetter) { @@ -76,6 +78,7 @@ public class InGameDialogActions : IInGameDialogActions _scrollingListDialogFactory = scrollingListDialogFactory; _tradeDialogFactory = tradeDialogFactory; _boardDialogFactory = boardDialogFactory; + _jukeboxDialogFactory = jukeboxDialogFactory; _sfxPlayer = sfxPlayer; _statusLabelSetter = statusLabelSetter; _shopDialogFactory = shopDialogFactory; @@ -329,6 +332,23 @@ public void ShowBoardDialog() _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.BOARD_TOWN_BOARD_NOW_VIEWED); } + public void ShowJukeboxDialog() + { + _activeDialogRepository.JukeboxDialog.MatchNone(() => + { + var dlg = _jukeboxDialogFactory.Create(); + dlg.DialogClosed += (_, _) => _activeDialogRepository.JukeboxDialog = Option.None(); + _activeDialogRepository.JukeboxDialog = Option.Some(dlg); + + dlg.Show(); + + UseDefaultDialogSounds(dlg); + }); + + // the vanilla client shows the status label any time the server sends the BOARD_OPEN packet + _statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.JUKEBOX_NOW_VIEWED); + } + private void UseDefaultDialogSounds(ScrollingListDialog dialog) { UseDefaultDialogSounds((BaseEODialog)dialog); @@ -389,5 +409,7 @@ public interface IInGameDialogActions void CloseTradeDialog(); void ShowBoardDialog(); + + void ShowJukeboxDialog(); } } diff --git a/EndlessClient/Dialogs/ActiveDialogRepository.cs b/EndlessClient/Dialogs/ActiveDialogRepository.cs index 28bf61d2b..b54d2e27a 100644 --- a/EndlessClient/Dialogs/ActiveDialogRepository.cs +++ b/EndlessClient/Dialogs/ActiveDialogRepository.cs @@ -39,6 +39,8 @@ public interface IActiveDialogProvider : IDisposable Option BoardDialog { get; } + Option JukeboxDialog { get; } + IReadOnlyList> ActiveDialogs { get; } } @@ -74,6 +76,8 @@ public interface IActiveDialogRepository : IDisposable Option BoardDialog { get; set; } + Option JukeboxDialog { get; set; } + IReadOnlyList> ActiveDialogs { get; } } @@ -110,6 +114,8 @@ public class ActiveDialogRepository : IActiveDialogRepository, IActiveDialogProv public Option BoardDialog { get; set; } + public Option JukeboxDialog { get; set; } + IReadOnlyList> ActiveDialogs { get @@ -131,6 +137,7 @@ IReadOnlyList> ActiveDialogs TradeDialog.Map(Map), MessageBox.Map(Map), BoardDialog.Map(Map), + JukeboxDialog.Map(Map), }.ToList(); static IXNADialog Map(object d) @@ -164,6 +171,7 @@ public void Dispose() TradeDialog = Option.None(); MessageBox = Option.None(); BoardDialog = Option.None(); + JukeboxDialog = Option.None(); } } } diff --git a/EndlessClient/Dialogs/Factories/JukeboxDialogFactory.cs b/EndlessClient/Dialogs/Factories/JukeboxDialogFactory.cs new file mode 100644 index 000000000..d68c7576b --- /dev/null +++ b/EndlessClient/Dialogs/Factories/JukeboxDialogFactory.cs @@ -0,0 +1,35 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Services; +using EOLib.Graphics; + +namespace EndlessClient.Dialogs.Factories +{ + [AutoMappedType] + public class JukeboxDialogFactory : IJukeboxDialogFactory + { + private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly IEODialogButtonService _dialogButtonService; + private readonly IEODialogIconService _dialogIconService; + + public JukeboxDialogFactory(INativeGraphicsManager nativeGraphicsManager, + IEODialogButtonService dialogButtonService, + IEODialogIconService dialogIconService) + { + _nativeGraphicsManager = nativeGraphicsManager; + _dialogButtonService = dialogButtonService; + _dialogIconService = dialogIconService; + } + + public JukeboxDialog Create() + { + return new JukeboxDialog(_nativeGraphicsManager, + _dialogButtonService, + _dialogIconService); + } + } + + public interface IJukeboxDialogFactory + { + JukeboxDialog Create(); + } +} diff --git a/EndlessClient/Dialogs/JukeboxDialog.cs b/EndlessClient/Dialogs/JukeboxDialog.cs new file mode 100644 index 000000000..3851ada64 --- /dev/null +++ b/EndlessClient/Dialogs/JukeboxDialog.cs @@ -0,0 +1,15 @@ +using EndlessClient.Dialogs.Services; +using EOLib.Graphics; + +namespace EndlessClient.Dialogs +{ + public class JukeboxDialog : ScrollingListDialog + { + public JukeboxDialog(INativeGraphicsManager nativeGraphicsManager, + IEODialogButtonService dialogButtonService, + IEODialogIconService dialogIconService) + : base(nativeGraphicsManager, dialogButtonService, DialogType.Jukebox) + { + } + } +} diff --git a/EndlessClient/Dialogs/ScrollingListDialog.cs b/EndlessClient/Dialogs/ScrollingListDialog.cs index e7163b9e1..c8fdae453 100644 --- a/EndlessClient/Dialogs/ScrollingListDialog.cs +++ b/EndlessClient/Dialogs/ScrollingListDialog.cs @@ -50,6 +50,9 @@ public enum DialogType FriendIgnore = Shop, Locker = Shop, Message = Shop, + Guild = Shop, + Inn = Shop, + LawBob = Shop, // large no scroll Chest, @@ -63,6 +66,9 @@ public enum DialogType // small no scroll BankAccountDialog, + + Jukebox, + Barber, } public class ScrollingListDialog : BaseEODialog diff --git a/EndlessClient/Dialogs/Services/EODialogIconService.cs b/EndlessClient/Dialogs/Services/EODialogIconService.cs index b704b213b..67f625185 100644 --- a/EndlessClient/Dialogs/Services/EODialogIconService.cs +++ b/EndlessClient/Dialogs/Services/EODialogIconService.cs @@ -9,11 +9,14 @@ public enum DialogIcon { Buy = 0, Sell, + JukeboxBrowse = Sell, BankDeposit, BankWithdraw, Craft, BankLockerUpgrade, + JukeboxPlay = 8, + Learn = 20, Forget = 21, } diff --git a/EndlessClient/HUD/ServerMessageActions.cs b/EndlessClient/HUD/UserInterfaceActions.cs similarity index 92% rename from EndlessClient/HUD/ServerMessageActions.cs rename to EndlessClient/HUD/UserInterfaceActions.cs index 135be9ea7..390f07f33 100644 --- a/EndlessClient/HUD/ServerMessageActions.cs +++ b/EndlessClient/HUD/UserInterfaceActions.cs @@ -23,6 +23,7 @@ public void NotifyPacketDialog(PacketFamily packetFamily) case PacketFamily.Locker: _inGameDialogActions.ShowLockerDialog(); break; case PacketFamily.Chest: _inGameDialogActions.ShowChestDialog(); break; case PacketFamily.Board: _inGameDialogActions.ShowBoardDialog(); break; + case PacketFamily.JukeBox: _inGameDialogActions.ShowJukeboxDialog(); break; } } diff --git a/EndlessClient/Input/UnwalkableTileActions.cs b/EndlessClient/Input/UnwalkableTileActions.cs index 3bd5fec9e..c376059bb 100644 --- a/EndlessClient/Input/UnwalkableTileActions.cs +++ b/EndlessClient/Input/UnwalkableTileActions.cs @@ -20,6 +20,7 @@ public enum UnwalkableTileAction Locker, Character, Board, + Jukebox, } [AutoMappedType] @@ -177,8 +178,8 @@ private UnwalkableTileAction HandleWalkToTileSpec(IMapCellState cellState) case TileSpec.Board7: case TileSpec.Board8: return UnwalkableTileAction.Board; - case TileSpec.Jukebox: //todo: jukebox - break; + case TileSpec.Jukebox: + return UnwalkableTileAction.Jukebox; } return UnwalkableTileAction.None; diff --git a/EndlessClient/Input/UnwalkableTileActionsHandler.cs b/EndlessClient/Input/UnwalkableTileActionsHandler.cs index de17c4f76..68bee9f90 100644 --- a/EndlessClient/Input/UnwalkableTileActionsHandler.cs +++ b/EndlessClient/Input/UnwalkableTileActionsHandler.cs @@ -39,6 +39,7 @@ public void HandleUnwalkableTileActions(IReadOnlyList unwa case UnwalkableTileAction.Chair: _characterActions.SitInChair(); break; case UnwalkableTileAction.Door: cellState.Warp.MatchSome(w => _mapActions.OpenDoor(w)); break; case UnwalkableTileAction.Board: _mapActions.OpenBoard(cellState.TileSpec); break; + case UnwalkableTileAction.Jukebox: _mapActions.OpenJukebox(cellState.Coordinate); break; } } } diff --git a/EndlessClient/Rendering/Map/ClickDispatcher.cs b/EndlessClient/Rendering/Map/ClickDispatcher.cs index aaec45ff0..546dbfe2e 100644 --- a/EndlessClient/Rendering/Map/ClickDispatcher.cs +++ b/EndlessClient/Rendering/Map/ClickDispatcher.cs @@ -6,7 +6,7 @@ using EndlessClient.Rendering.NPC; using EOLib.Domain.Character; using EOLib.Domain.Extensions; -using EOLib.Domain.Interact.Board; +using EOLib.Domain.Interact; using EOLib.Domain.Map; using EOLib.IO.Map; using Microsoft.Xna.Framework; @@ -111,8 +111,9 @@ private bool CheckForEntityClicks(MouseEventArgs eventArgs) entities.AddRange(_currentMapProvider.CurrentMap.Signs); entities.AddRange(_currentMapProvider.CurrentMap .GetTileSpecs(TileSpec.Board1, TileSpec.Board2, TileSpec.Board3, TileSpec.Board4, - TileSpec.Board5, TileSpec.Board6, TileSpec.Board7, TileSpec.Board8) - .Select(x => new BoardMapEntity(x.X, x.Y))); + TileSpec.Board5, TileSpec.Board6, TileSpec.Board7, TileSpec.Board8, + TileSpec.Jukebox) + .Select(x => new TileSpecMapEntity(x.X, x.Y))); entities.Sort((a, b) => { @@ -156,7 +157,7 @@ private bool DispatchClickToEntity(IMapEntity entity, MouseEventArgs eventArgs) DomainCharacter c => HandleCharacterClick(c, eventArgs.Button), DomainNPC n => eventArgs.Button == MouseButton.Left && HandleNPCClick(n, eventArgs.Position), SignMapEntity s => eventArgs.Button == MouseButton.Left && HandleSignClick(s), - BoardMapEntity b => eventArgs.Button == MouseButton.Left && HandleBoardClick(b), + TileSpecMapEntity ts => eventArgs.Button == MouseButton.Left && HandleTileSpecClick(ts), _ => throw new ArgumentException() }; } @@ -167,7 +168,7 @@ private Rectangle GetEntityBounds(IMapEntity entity) { DomainCharacter c => GetCharacterRendererArea(c.ID), DomainNPC n => GetNPCRendererArea(n.Index), - SignMapEntity or BoardMapEntity => GetObjectBounds(entity), + SignMapEntity or TileSpecMapEntity => GetObjectBounds(entity), _ => throw new ArgumentException() }; } @@ -242,12 +243,12 @@ private bool HandleSignClick(SignMapEntity s) return true; } - private bool HandleBoardClick(BoardMapEntity b) + private bool HandleTileSpecClick(TileSpecMapEntity ts) { var cellState = new MapCellState { - Coordinate = new MapCoordinate(b.X, b.Y), - TileSpec = _currentMapProvider.CurrentMap.Tiles[b.Y, b.X] + Coordinate = new MapCoordinate(ts.X, ts.Y), + TileSpec = _currentMapProvider.CurrentMap.Tiles[ts.Y, ts.X] }; _mapInteractionController.LeftClick(cellState);