Skip to content

Commit

Permalink
Implement Jukebox dialog UI
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanmoffat committed May 19, 2023
1 parent ba97243 commit a8deb83
Show file tree
Hide file tree
Showing 7 changed files with 217 additions and 21 deletions.
2 changes: 1 addition & 1 deletion EndlessClient/Controllers/MapInteractionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public void LeftClick(IMapCellState cellState)
if (unwalkableAction == UnwalkableTileAction.Jukebox)
{
_mapActions.OpenJukebox(cellState.Coordinate);
_inGameDialogActions.ShowJukeboxDialog();
_inGameDialogActions.ShowJukeboxDialog(cellState.Coordinate);
}
break;
}
Expand Down
10 changes: 6 additions & 4 deletions EndlessClient/Dialogs/Actions/InGameDialogActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using EOLib.Domain.Interact.Quest;
using EOLib.Domain.Interact.Shop;
using EOLib.Domain.Interact.Skill;
using EOLib.Domain.Map;
using EOLib.Localization;
using Optional;
using System;
Expand Down Expand Up @@ -332,11 +333,11 @@ public void ShowBoardDialog()
_statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_ACTION, EOResourceID.BOARD_TOWN_BOARD_NOW_VIEWED);
}

public void ShowJukeboxDialog()
public void ShowJukeboxDialog(MapCoordinate mapCoordinate)
{
_activeDialogRepository.JukeboxDialog.MatchNone(() =>
{
var dlg = _jukeboxDialogFactory.Create();
var dlg = _jukeboxDialogFactory.Create(mapCoordinate);
dlg.DialogClosed += (_, _) => _activeDialogRepository.JukeboxDialog = Option.None<JukeboxDialog>();
_activeDialogRepository.JukeboxDialog = Option.Some(dlg);

Expand All @@ -346,7 +347,8 @@ public void ShowJukeboxDialog()
});

// 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);
// the vanilla client uses [Action] for Board and [Information] for Jukebox, for some reason
_statusLabelSetter.SetStatusLabel(EOResourceID.STATUS_LABEL_TYPE_INFORMATION, EOResourceID.JUKEBOX_NOW_VIEWED);
}

private void UseDefaultDialogSounds(ScrollingListDialog dialog)
Expand Down Expand Up @@ -410,6 +412,6 @@ public interface IInGameDialogActions

void ShowBoardDialog();

void ShowJukeboxDialog();
void ShowJukeboxDialog(MapCoordinate mapCoordinate);
}
}
37 changes: 33 additions & 4 deletions EndlessClient/Dialogs/Factories/JukeboxDialogFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
using AutomaticTypeMapper;
using EndlessClient.Audio;
using EndlessClient.Dialogs.Services;
using EOLib.Domain.Interact.Jukebox;
using EOLib.Domain.Map;
using EOLib.Graphics;
using EOLib.Localization;

namespace EndlessClient.Dialogs.Factories
{
Expand All @@ -10,26 +14,51 @@ public class JukeboxDialogFactory : IJukeboxDialogFactory
private readonly INativeGraphicsManager _nativeGraphicsManager;
private readonly IEODialogButtonService _dialogButtonService;
private readonly IEODialogIconService _dialogIconService;
private readonly ILocalizedStringFinder _localizedStringFinder;
private readonly IDataFileProvider _dataFileProvider;
private readonly IEOMessageBoxFactory _messageBoxFactory;
private readonly IJukeboxActions _jukeboxActions;
private readonly IJukeboxRepository _jukeboxRepository;
private readonly ISfxPlayer _sfxPlayer;

public JukeboxDialogFactory(INativeGraphicsManager nativeGraphicsManager,
IEODialogButtonService dialogButtonService,
IEODialogIconService dialogIconService)
IEODialogIconService dialogIconService,
ILocalizedStringFinder localizedStringFinder,
IDataFileProvider dataFileProvider,
IEOMessageBoxFactory messageBoxFactory,
IJukeboxActions jukeboxActions,
IJukeboxRepository jukeboxRepository,
ISfxPlayer sfxPlayer)
{
_nativeGraphicsManager = nativeGraphicsManager;
_dialogButtonService = dialogButtonService;
_dialogIconService = dialogIconService;
_localizedStringFinder = localizedStringFinder;
_dataFileProvider = dataFileProvider;
_messageBoxFactory = messageBoxFactory;
_jukeboxActions = jukeboxActions;
_jukeboxRepository = jukeboxRepository;
_sfxPlayer = sfxPlayer;
}

public JukeboxDialog Create()
public JukeboxDialog Create(MapCoordinate mapCoordinate)
{
return new JukeboxDialog(_nativeGraphicsManager,
_dialogButtonService,
_dialogIconService);
_dialogIconService,
_localizedStringFinder,
_dataFileProvider,
_messageBoxFactory,
_jukeboxActions,
_jukeboxRepository,
_sfxPlayer,
mapCoordinate);
}
}

public interface IJukeboxDialogFactory
{
JukeboxDialog Create();
JukeboxDialog Create(MapCoordinate mapCoordinate);
}
}
149 changes: 147 additions & 2 deletions EndlessClient/Dialogs/JukeboxDialog.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,160 @@
using EndlessClient.Dialogs.Services;
using EndlessClient.Audio;
using EndlessClient.Dialogs.Factories;
using EndlessClient.Dialogs.Services;
using EOLib.Domain.Interact.Jukebox;
using EOLib.Domain.Map;
using EOLib.Graphics;
using EOLib.Localization;
using Microsoft.Xna.Framework;
using MonoGame.Extended.Input.InputListeners;
using Optional;
using System;
using System.Collections.Generic;
using XNAControls;

namespace EndlessClient.Dialogs
{
public class JukeboxDialog : ScrollingListDialog
{
private readonly IEODialogIconService _dialogIconService;
private readonly ILocalizedStringFinder _localizedStringFinder;
private readonly IEOMessageBoxFactory _messageBoxFactory;
private readonly IJukeboxActions _jukeboxActions;
private readonly IJukeboxRepository _jukeboxRepository;
private readonly ISfxPlayer _sfxPlayer;

private readonly MapCoordinate _jukeboxCoordinate;

private readonly IEDFFile _songNames;

private ListDialogItem _changeSongItem, _playSongItem;

private DateTime _openedTime;

private Option<string> _lastRequestedName;
private int _songIndex;

public JukeboxDialog(INativeGraphicsManager nativeGraphicsManager,
IEODialogButtonService dialogButtonService,
IEODialogIconService dialogIconService)
IEODialogIconService dialogIconService,
ILocalizedStringFinder localizedStringFinder,
IDataFileProvider dataFileProvider,
IEOMessageBoxFactory messageBoxFactory,
IJukeboxActions jukeboxActions,
IJukeboxRepository jukeboxRepository,
ISfxPlayer sfxPlayer,
MapCoordinate jukeboxCoordinate)
: base(nativeGraphicsManager, dialogButtonService, DialogType.Jukebox)
{
_dialogIconService = dialogIconService;
_localizedStringFinder = localizedStringFinder;
_messageBoxFactory = messageBoxFactory;
_jukeboxActions = jukeboxActions;
_jukeboxRepository = jukeboxRepository;
_sfxPlayer = sfxPlayer;
_jukeboxCoordinate = jukeboxCoordinate;

ListItemType = ListDialogItem.ListItemStyle.Large;
Buttons = ScrollingListDialogButtons.Cancel;

_songNames = dataFileProvider.DataFiles[DataFiles.JukeBoxSongs];
_openedTime = DateTime.Now;

Title = _localizedStringFinder.GetString(EOResourceID.JUKEBOX_IS_READY);
}

public override void Initialize()
{
_changeSongItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 0)
{
IconGraphic = _dialogIconService.IconSheet,
IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.JukeboxBrowse),
PrimaryText = _localizedStringFinder.GetString(EOResourceID.JUKEBOX_BROWSE_THROUGH_SONGS),
SubText = FormatSubtitle(_songNames.Data[_songIndex]),
ShowIconBackGround = false,
OffsetY = 60,
};
_changeSongItem.LeftClick += ChangeSongItem_Click;

_playSongItem = new ListDialogItem(this, ListDialogItem.ListItemStyle.Large, 1)
{
IconGraphic = _dialogIconService.IconSheet,
IconGraphicSource = _dialogIconService.GetDialogIconSource(DialogIcon.JukeboxPlay),
PrimaryText = _localizedStringFinder.GetString(EOResourceID.JUKEBOX_PLAY_SONG),
SubText = FormatSubtitle("25 gold"),
ShowIconBackGround = false,
OffsetY = 60,
};
_playSongItem.LeftClick += PlaySongItem_Click;

SetItemList(new List<ListDialogItem> { _changeSongItem, _playSongItem });

base.Initialize();
}

public override void Update(GameTime gameTime)
{
if ((DateTime.Now - _openedTime).TotalSeconds >= 96)
{
_jukeboxRepository.PlayingRequestName = Option.None<string>();
_openedTime = DateTime.Now.AddMinutes(100);
}

_jukeboxRepository.PlayingRequestName.MatchSome(
requestedName =>
{
if (_lastRequestedName.Map(x => !x.Equals(requestedName)).ValueOr(true))
{
_lastRequestedName = Option.Some(requestedName);

var titleString = _localizedStringFinder.GetString(EOResourceID.JUKEBOX_PLAYING_REQUEST);
if (!string.IsNullOrWhiteSpace(requestedName))
titleString += $" ({requestedName})";

Title = titleString;
}
});

base.Update(gameTime);
}

private void ChangeSongItem_Click(object sender, MouseEventArgs e)
{
_songIndex = (_songIndex + 1) % _songNames.Data.Count;
_changeSongItem.SubText = FormatSubtitle(_songNames.Data[_songIndex]);
}

private void PlaySongItem_Click(object sender, MouseEventArgs e)
{
if (_jukeboxRepository.PlayingRequestName.HasValue)
{
var dlg = _messageBoxFactory.CreateMessageBox(DialogResourceID.JUKEBOX_REQUESTED_RECENTLY);
dlg.ShowDialog();
return;
}

var confirmDlg = _messageBoxFactory.CreateMessageBox(
$"{_localizedStringFinder.GetString(EOResourceID.JUKEBOX_REQUEST_SONG_FOR)} 25 gold?",
_localizedStringFinder.GetString(EOResourceID.JUKEBOX_REQUEST_SONG),
EODialogButtons.OkCancel);

confirmDlg.DialogClosing += (_, e) =>
{
if (e.Result == XNADialogResult.OK)
{
_jukeboxActions.RequestSong(_jukeboxCoordinate, _songIndex);
_sfxPlayer.PlaySfx(SoundEffectID.BuySell);

Close(XNADialogResult.NO_BUTTON_PRESSED);
}
};

confirmDlg.ShowDialog();
}

private string FormatSubtitle(string additionalText)
{
return _localizedStringFinder.GetString(EOResourceID.DIALOG_WORD_CURRENT) + " : " + additionalText;
}
}
}
19 changes: 14 additions & 5 deletions EndlessClient/Dialogs/ScrollingListDialog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public ScrollingListDialog(INativeGraphicsManager nativeGraphicsManager,

_scrollBar = new ScrollBar(new Vector2(DialogType == DialogType.QuestProgressHistory ? 449 : 252, 44), new Vector2(16, GetScrollBarHeight(DialogType)), ScrollBarColors.LightOnMed, GraphicsManager)
{
Visible = DialogType != DialogType.Chest && DialogType != DialogType.BankAccountDialog,
Visible = DialogType != DialogType.Chest && DialogType != DialogType.BankAccountDialog && DialogType != DialogType.Jukebox,
};
_scrollBar.SetParentControl(this);
SetScrollWheelHandler(_scrollBar);
Expand Down Expand Up @@ -445,6 +445,7 @@ protected static Rectangle GetTitleDrawArea(DialogType size)
case DialogType.Chest: return new Rectangle(16, 13, 253, 19);
case DialogType.QuestProgressHistory:
return new Rectangle(18, 14, 452, 19);
case DialogType.Jukebox: return new Rectangle(24, 20, 263, 19);
case DialogType.NpcQuestDialog: return new Rectangle(16, 16, 255, 18);
case DialogType.BankAccountDialog: return new Rectangle(129, 20, 121, 16);
default: throw new NotImplementedException();
Expand All @@ -459,6 +460,7 @@ protected static int GetScrollBarHeight(DialogType size)
case DialogType.Chest:
case DialogType.QuestProgressHistory:
return 199;
case DialogType.Jukebox:
case DialogType.NpcQuestDialog:
case DialogType.BankAccountDialog: return 99;
default: throw new NotImplementedException();
Expand All @@ -471,8 +473,8 @@ private static int GetBackgroundTexture(DialogType size)
{
case DialogType.Shop: return 52;
case DialogType.Chest: return 51;
case DialogType.QuestProgressHistory:
return 59;
case DialogType.QuestProgressHistory: return 59;
case DialogType.Jukebox: return 60;
case DialogType.NpcQuestDialog: return 67;
case DialogType.BankAccountDialog: return 53;
default: throw new NotImplementedException();
Expand All @@ -487,6 +489,7 @@ private static int GetBackgroundTexture(DialogType size)
case DialogType.Chest: return null;
case DialogType.QuestProgressHistory:
return new Rectangle(0, 0, backgroundTexture.Width, backgroundTexture.Height / 2);
case DialogType.Jukebox:
case DialogType.NpcQuestDialog:
case DialogType.BankAccountDialog: return null;
default: throw new NotImplementedException();
Expand All @@ -501,7 +504,8 @@ private static Vector2 GetButton1Position(Rectangle dialogArea, Rectangle button
// buttons are centered on these dialogs
case DialogType.Shop:
case DialogType.Chest:
case DialogType.BankAccountDialog: return new Vector2((int)Math.Floor((dialogArea.Width - buttonArea.Width) / 2.0) - 48, yCoord);
case DialogType.BankAccountDialog:
case DialogType.Jukebox: return new Vector2((int)Math.Floor((dialogArea.Width - buttonArea.Width) / 2.0) - 48, yCoord);
// buttons are offset from center on these dialogs
case DialogType.QuestProgressHistory:
return new Vector2(288, yCoord);
Expand All @@ -518,7 +522,8 @@ private static Vector2 GetButton2Position(Rectangle dialogArea, Rectangle button
// buttons are centered on these dialogs
case DialogType.Shop:
case DialogType.Chest:
case DialogType.BankAccountDialog: return new Vector2((int)Math.Floor((dialogArea.Width - buttonArea.Width) / 2.0) + 48, yCoord);
case DialogType.BankAccountDialog:
case DialogType.Jukebox: return new Vector2((int)Math.Floor((dialogArea.Width - buttonArea.Width) / 2.0) + 48, yCoord);
// buttons are offset from center on these dialogs
case DialogType.QuestProgressHistory:
return new Vector2(380, yCoord);
Expand All @@ -537,6 +542,10 @@ private static Vector2 GetButtonCenterPosition(Rectangle dialogArea, Rectangle b
if (dialogSize == DialogType.BankAccountDialog)
return new Vector2(92, 191);

// jukebox dialog has a button built in to the graphic that needs to be covered up...
if (dialogSize == DialogType.Jukebox)
return new Vector2(92, 158);

var yCoord = GetButtonYCoordinate(dialogArea);
return new Vector2((dialogArea.Width - buttonArea.Width) / 2, yCoord);
}
Expand Down
3 changes: 2 additions & 1 deletion EndlessClient/HUD/UserInterfaceActions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using AutomaticTypeMapper;
using EndlessClient.Dialogs.Actions;
using EOLib.Domain.Map;
using EOLib.Domain.Notifiers;
using EOLib.Net;
using System.Collections.Generic;
Expand All @@ -23,7 +24,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;
case PacketFamily.JukeBox: _inGameDialogActions.ShowJukeboxDialog(MapCoordinate.Zero); break;
}
}

Expand Down
18 changes: 14 additions & 4 deletions EndlessClient/Input/UnwalkableTileActionsHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,20 @@ public void HandleUnwalkableTileActions(IReadOnlyList<UnwalkableTileAction> unwa
_mapActions.OpenLocker(cellState.Coordinate);
_inGameDialogActions.ShowLockerDialog();
break;
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;
case UnwalkableTileAction.Chair:
_characterActions.SitInChair();
break;
case UnwalkableTileAction.Door:
cellState.Warp.MatchSome(w => _mapActions.OpenDoor(w));
break;
case UnwalkableTileAction.Board:
_mapActions.OpenBoard(cellState.TileSpec);
_inGameDialogActions.ShowBoardDialog();
break;
case UnwalkableTileAction.Jukebox:
_mapActions.OpenJukebox(cellState.Coordinate);
_inGameDialogActions.ShowJukeboxDialog(cellState.Coordinate);
break;
}
}
}
Expand Down

0 comments on commit a8deb83

Please sign in to comment.