diff --git a/EOLib/Domain/Character/CharacterSessionRepository.cs b/EOLib/Domain/Character/CharacterSessionRepository.cs new file mode 100644 index 000000000..fee709c83 --- /dev/null +++ b/EOLib/Domain/Character/CharacterSessionRepository.cs @@ -0,0 +1,52 @@ +using AutomaticTypeMapper; +using System; + +namespace EOLib.Domain.Character +{ + public interface ICharacterSessionRepository : IResettable + { + DateTime SessionStartTime { get; set; } + + int BestKillExp { get; set; } + + int LastKillExp { get; set; } + + int TodayTotalExp { get; set; } + } + + public interface ICharacterSessionProvider : IResettable + { + DateTime SessionStartTime { get; } + + int BestKillExp { get; } + + int LastKillExp { get; } + + int TodayTotalExp { get; } + } + + [AutoMappedType(IsSingleton = true)] + public class CharacterSessionRepository : ICharacterSessionRepository, ICharacterSessionProvider + { + public DateTime SessionStartTime { get; set; } + + public int BestKillExp { get; set; } + + public int LastKillExp { get; set; } + + public int TodayTotalExp { get; set; } + + public CharacterSessionRepository() + { + ResetState(); + } + + public void ResetState() + { + SessionStartTime = DateTime.Now; + BestKillExp = 0; + LastKillExp = 0; + TodayTotalExp = 0; + } + } +} diff --git a/EOLib/Domain/Character/CharacterStat.cs b/EOLib/Domain/Character/CharacterStat.cs index 55fbb42db..a67dbe094 100644 --- a/EOLib/Domain/Character/CharacterStat.cs +++ b/EOLib/Domain/Character/CharacterStat.cs @@ -30,6 +30,6 @@ public enum CharacterStat Charisma, Weight, - MaxWeight + MaxWeight, } } diff --git a/EOLib/Domain/Interact/MapNPCActions.cs b/EOLib/Domain/Interact/MapNPCActions.cs index 4eafbf762..ad7f3a441 100644 --- a/EOLib/Domain/Interact/MapNPCActions.cs +++ b/EOLib/Domain/Interact/MapNPCActions.cs @@ -1,4 +1,5 @@ using AutomaticTypeMapper; +using EOLib.Domain.Interact.Quest; using EOLib.Domain.NPC; using EOLib.IO.Repositories; using EOLib.Net; @@ -11,12 +12,15 @@ public class MapNPCActions : IMapNPCActions { private readonly IPacketSendService _packetSendService; private readonly IENFFileProvider _enfFileProvider; + private readonly IQuestDataRepository _questDataRepository; public MapNPCActions(IPacketSendService packetSendService, - IENFFileProvider enfFileProvider) + IENFFileProvider enfFileProvider, + IQuestDataRepository questDataRepository) { _packetSendService = packetSendService; _enfFileProvider = enfFileProvider; + _questDataRepository = questDataRepository; } public void RequestShop(INPC npc) @@ -30,6 +34,8 @@ public void RequestShop(INPC npc) public void RequestQuest(INPC npc) { + _questDataRepository.RequestedNPC = npc; + var data = _enfFileProvider.ENFFile[npc.ID]; var packet = new PacketBuilder(PacketFamily.Quest, PacketAction.Use) diff --git a/EOLib/Domain/Interact/Quest/BookIcon.cs b/EOLib/Domain/Interact/Quest/BookIcon.cs new file mode 100644 index 000000000..3b97ae8da --- /dev/null +++ b/EOLib/Domain/Interact/Quest/BookIcon.cs @@ -0,0 +1,10 @@ +namespace EOLib.Domain.Interact.Quest +{ + public enum BookIcon : byte + { + Item = 3, + Talk = 5, + Kill = 8, + Step = 10 + } +} diff --git a/EOLib/Domain/Interact/Quest/QuestActions.cs b/EOLib/Domain/Interact/Quest/QuestActions.cs index 0be5b3df5..0a1f57865 100644 --- a/EOLib/Domain/Interact/Quest/QuestActions.cs +++ b/EOLib/Domain/Interact/Quest/QuestActions.cs @@ -35,10 +35,21 @@ public void RespondToQuestDialog(DialogReply reply, byte linkId = 0) _packetSendService.SendPacket(packet); }); } + + public void RequestQuestHistory(QuestPage page) + { + var packet = new PacketBuilder(PacketFamily.Quest, PacketAction.List) + .AddChar((byte)page) + .Build(); + + _packetSendService.SendPacket(packet); + } } public interface IQuestActions { void RespondToQuestDialog(DialogReply reply, byte linkId = 0); + + void RequestQuestHistory(QuestPage page); } } diff --git a/EOLib/Domain/Interact/Quest/QuestDataRepository.cs b/EOLib/Domain/Interact/Quest/QuestDataRepository.cs index e6ae8083f..07722cc0b 100644 --- a/EOLib/Domain/Interact/Quest/QuestDataRepository.cs +++ b/EOLib/Domain/Interact/Quest/QuestDataRepository.cs @@ -1,6 +1,7 @@ using AutomaticTypeMapper; using EOLib.Domain.NPC; using Optional; +using System.Collections.Generic; namespace EOLib.Domain.Interact.Quest { @@ -9,6 +10,10 @@ public interface IQuestDataRepository : IResettable INPC RequestedNPC { get; set; } Option QuestDialogData { get; set; } + + List QuestProgress { get; set; } + + List QuestHistory { get; set; } } public interface IQuestDataProvider : IResettable @@ -16,6 +21,10 @@ public interface IQuestDataProvider : IResettable INPC RequestedNPC { get; } Option QuestDialogData { get; } + + IReadOnlyList QuestProgress { get; } + + IReadOnlyList QuestHistory { get; } } [AutoMappedType(IsSingleton = true)] @@ -25,6 +34,14 @@ public class QuestDataRepository : IQuestDataProvider, IQuestDataRepository public Option QuestDialogData { get; set; } + public List QuestProgress { get; set; } + + public List QuestHistory { get; set; } + + IReadOnlyList IQuestDataProvider.QuestProgress => QuestProgress; + + IReadOnlyList IQuestDataProvider.QuestHistory => QuestHistory; + public QuestDataRepository() { ResetState(); @@ -32,7 +49,10 @@ public QuestDataRepository() public void ResetState() { + RequestedNPC = null; QuestDialogData = Option.None(); + QuestProgress = new List(); + QuestHistory = new List(); } } } diff --git a/EOLib/Domain/Interact/Quest/QuestPage.cs b/EOLib/Domain/Interact/Quest/QuestPage.cs new file mode 100644 index 000000000..ea47fc00f --- /dev/null +++ b/EOLib/Domain/Interact/Quest/QuestPage.cs @@ -0,0 +1,8 @@ +namespace EOLib.Domain.Interact.Quest +{ + public enum QuestPage + { + Progress = 1, + History + } +} diff --git a/EOLib/Domain/Interact/Quest/QuestProgressData.cs b/EOLib/Domain/Interact/Quest/QuestProgressData.cs new file mode 100644 index 000000000..3428e8218 --- /dev/null +++ b/EOLib/Domain/Interact/Quest/QuestProgressData.cs @@ -0,0 +1,103 @@ +using System; + +namespace EOLib.Domain.Interact.Quest +{ + public class QuestProgressData : IQuestProgressData + { + public string Name { get; private set; } + + public string Description { get; private set; } + + public BookIcon Icon { get; private set; } + + public int IconIndex + { + get + { + //these are probably wrong. can't really tell what it's supposed to be from original + switch (Icon) + { + case BookIcon.Item: + return 2; + case BookIcon.Talk: + return 1; + case BookIcon.Kill: + return 3; + case BookIcon.Step: + return 4; + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + public short Progress { get; private set; } + + public short Target { get; private set; } + + public QuestProgressData() { } + + private QuestProgressData(string name, + string description, + BookIcon icon, + short progress, + short target) + { + Name = name; + Description = description; + Icon = icon; + Progress = progress; + Target = target; + } + + public IQuestProgressData WithName(string name) + { + return new QuestProgressData(name, Description, Icon, Progress, Target); + } + + public IQuestProgressData WithDescription(string description) + { + return new QuestProgressData(Name, description, Icon, Progress, Target); + } + + public IQuestProgressData WithIcon(BookIcon icon) + { + return new QuestProgressData(Name, Description, icon, Progress, Target); + } + + public IQuestProgressData WithProgress(short progress) + { + return new QuestProgressData(Name, Description, Icon, progress, Target); + } + + public IQuestProgressData WithTarget(short target) + { + return new QuestProgressData(Name, Description, Icon, Progress, target); + } + } + + public interface IQuestProgressData + { + string Name { get; } + + string Description { get; } + + BookIcon Icon { get; } + + int IconIndex { get; } + + short Progress { get; } + + short Target { get; } + + IQuestProgressData WithName(string name); + + IQuestProgressData WithDescription(string description); + + IQuestProgressData WithIcon(BookIcon icon); + + IQuestProgressData WithProgress(short progress); + + IQuestProgressData WithTarget(short target); + } +} diff --git a/EOLib/Domain/Login/LoginActions.cs b/EOLib/Domain/Login/LoginActions.cs index b670bb7d9..469f110b8 100644 --- a/EOLib/Domain/Login/LoginActions.cs +++ b/EOLib/Domain/Login/LoginActions.cs @@ -28,6 +28,7 @@ public class LoginActions : ILoginActions private readonly INewsRepository _newsRepository; private readonly ICharacterInventoryRepository _characterInventoryRepository; private readonly IPaperdollRepository _paperdollRepository; + private readonly ICharacterSessionRepository _characterSessionRepository; public LoginActions(IPacketSendService packetSendService, IPacketTranslator loginPacketTranslator, @@ -40,7 +41,8 @@ public class LoginActions : ILoginActions ILoginFileChecksumRepository loginFileChecksumRepository, INewsRepository newsRepository, ICharacterInventoryRepository characterInventoryRepository, - IPaperdollRepository paperdollRepository) + IPaperdollRepository paperdollRepository, + ICharacterSessionRepository characterSessionRepository) { _packetSendService = packetSendService; _loginPacketTranslator = loginPacketTranslator; @@ -54,6 +56,7 @@ public class LoginActions : ILoginActions _newsRepository = newsRepository; _characterInventoryRepository = characterInventoryRepository; _paperdollRepository = paperdollRepository; + _characterSessionRepository = characterSessionRepository; } public bool LoginParametersAreValid(ILoginParameters parameters) @@ -185,6 +188,7 @@ public async Task CompleteCharacterLogin(short sessionID) _currentMapStateRepository.MapItems = new HashSet(data.MapItems); _playerInfoRepository.PlayerIsInGame = true; + _characterSessionRepository.ResetState(); return CharacterLoginReply.RequestCompleted; } diff --git a/EOLib/Net/API/PacketAPI.cs b/EOLib/Net/API/PacketAPI.cs index f0c22ad66..d978f60c2 100644 --- a/EOLib/Net/API/PacketAPI.cs +++ b/EOLib/Net/API/PacketAPI.cs @@ -27,7 +27,6 @@ public PacketAPI(EOClient client) _createMusicMembers(); _createPartyMembers(); _createNPCMembers(); - _createQuestMembers(); _createSpellMembers(); _createStatSkillMembers(); _createTradeMembers(); diff --git a/EOLib/Net/API/Quest.cs b/EOLib/Net/API/Quest.cs deleted file mode 100644 index 84d5a1d1b..000000000 --- a/EOLib/Net/API/Quest.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System; -using System.Collections.Generic; -using EOLib.Net.Handlers; - -namespace EOLib.Net.API -{ - public enum DialogReply : byte - { - Ok = 1, - Link - } - - public enum QuestPage : byte - { - Progress = 1, - History - } - - public enum BookIcon : byte - { - Item = 3, - Talk = 5, - Kill = 8, - Step = 10 - } - - /// - /// State object for quest transactions with server - /// - public struct QuestState - { - private readonly short _npcIndex; - private readonly short _questID; - private readonly short _dialogID; - private readonly short _sessionID; - - public short SessionID => _sessionID; - public short DialogID => _dialogID; - public short QuestID => _questID; - public short NPCIndex => _npcIndex; - public short VendorID => _npcIndex; -//re-used - - public QuestState(short session, short dialogID, short questID, short npcIndex) - { - _sessionID = session; - _dialogID = dialogID; - _questID = questID; - _npcIndex = npcIndex; - } - } - - /// - /// Data regarding in-progress quests - /// - public struct InProgressQuestData - { - private readonly string _name; - private readonly string _description; - private readonly BookIcon _icon; - private readonly short _progress; - private readonly short _target; - - public string Name => _name; - public string Description => _description; - public BookIcon Icon => _icon; - - public int IconIndex - { - get - { - //these are probably wrong. can't really tell what it's supposed to be from original - switch (Icon) - { - case BookIcon.Item: - return 2; - case BookIcon.Talk: - return 1; - case BookIcon.Kill: - return 3; - case BookIcon.Step: - return 4; - default: - throw new ArgumentOutOfRangeException(); - } - } - } - - public short Progress => _progress; - - public short Target => _target; - - internal InProgressQuestData(OldPacket pkt) - { - _name = pkt.GetBreakString(); - _description = pkt.GetBreakString(); - _icon = (BookIcon) pkt.GetShort(); - _progress = pkt.GetShort(); - _target = pkt.GetShort(); - if (pkt.GetByte() != 255) - throw new ArgumentException("Malformed quest packet", nameof(pkt)); - } - } - - public delegate void QuestDialogEvent(QuestState stateInfo, Dictionary dialogNames, List pages, Dictionary links); - - public delegate void ViewQuestProgressEvent(short numQuests, List questInfo); - - public delegate void ViewQuestHistoryEvent(short numQuests, List completedQuestNames); - - partial class PacketAPI - { - public event ViewQuestProgressEvent OnViewQuestProgress; - public event ViewQuestHistoryEvent OnViewQuestHistory; - - private void _createQuestMembers() - { - m_client.AddPacketHandler(new FamilyActionPair(PacketFamily.Quest, PacketAction.List), _handleQuestList, true); - } - - public bool RequestQuestHistory(QuestPage page) - { - if (!Initialized || !m_client.ConnectedAndInitialized) - return false; - - OldPacket pkt = new OldPacket(PacketFamily.Quest, PacketAction.List); - pkt.AddChar((byte) page); - - return m_client.SendPacket(pkt); - } - - private void _handleQuestList(OldPacket pkt) - { - QuestPage page = (QuestPage) pkt.GetChar(); - short numQuests = pkt.GetShort(); - - switch (page) - { - case QuestPage.Progress: - var dataCollection = new List(numQuests); - while (pkt.ReadPos != pkt.Length) - dataCollection.Add(new InProgressQuestData(pkt)); - - if (OnViewQuestProgress != null) - OnViewQuestProgress(numQuests, dataCollection); - - break; - case QuestPage.History: - var completedNames = new List(numQuests); - while (pkt.ReadPos != pkt.Length) - completedNames.Add(pkt.GetBreakString()); - - if (OnViewQuestHistory != null) - OnViewQuestHistory(numQuests, completedNames); - - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - } -} diff --git a/EOLib/PacketHandlers/NPCLeaveMapHandler.cs b/EOLib/PacketHandlers/NPCLeaveMapHandler.cs index d4aa52bd7..5b83aafbf 100644 --- a/EOLib/PacketHandlers/NPCLeaveMapHandler.cs +++ b/EOLib/PacketHandlers/NPCLeaveMapHandler.cs @@ -16,6 +16,7 @@ public class NPCLeaveMapHandler : InGameOnlyPacketHandler { protected readonly ICurrentMapStateRepository _currentMapStateRepository; protected readonly ICharacterRepository _characterRepository; + private readonly ICharacterSessionRepository _characterSessionRepository; private readonly IEnumerable _npcAnimationNotifiers; private readonly IEnumerable _mainCharacterEventNotifiers; @@ -26,12 +27,14 @@ public class NPCLeaveMapHandler : InGameOnlyPacketHandler public NPCLeaveMapHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, + ICharacterSessionRepository characterSessionRepository, IEnumerable npcAnimationNotifiers, IEnumerable mainCharacterEventNotifiers) : base(playerInfoProvider) { _currentMapStateRepository = currentMapStateRepository; _characterRepository = characterRepository; + _characterSessionRepository = characterSessionRepository; _npcAnimationNotifiers = npcAnimationNotifiers; _mainCharacterEventNotifiers = mainCharacterEventNotifiers; } @@ -79,7 +82,11 @@ public override bool HandlePacket(IPacket packet) notifier.NotifyGainedExp(expDifference); UpdateCharacterStat(CharacterStat.Experience, playerExp); - //todo: update last kill, best kill, and today exp + + _characterSessionRepository.LastKillExp = expDifference; + if (expDifference > _characterSessionRepository.BestKillExp) + _characterSessionRepository.BestKillExp = expDifference; + _characterSessionRepository.TodayTotalExp += expDifference; } if (droppedItemID > 0) @@ -153,9 +160,10 @@ public class NPCDieFromSpellCastHandler : NPCLeaveMapHandler public NPCDieFromSpellCastHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, + ICharacterSessionRepository characterSessionRepository, IEnumerable npcAnimationNotifiers, IEnumerable mainCharacterEventNotifiers) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, + : base(playerInfoProvider, currentMapStateRepository, characterRepository, characterSessionRepository, npcAnimationNotifiers, mainCharacterEventNotifiers) { } } } diff --git a/EOLib/PacketHandlers/PlayerLevelUpHandler.cs b/EOLib/PacketHandlers/PlayerLevelUpHandler.cs index 9e1345fbe..3a55a335a 100644 --- a/EOLib/PacketHandlers/PlayerLevelUpHandler.cs +++ b/EOLib/PacketHandlers/PlayerLevelUpHandler.cs @@ -20,10 +20,11 @@ public class PlayerLevelUpHandler : NPCLeaveMapHandler public PlayerLevelUpHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, + ICharacterSessionRepository characterSessionRepository, IEnumerable npcAnimationNotifiers, IEnumerable mainCharacterEventNotifiers, IEnumerable emoteNotifiers) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, + : base(playerInfoProvider, currentMapStateRepository, characterRepository, characterSessionRepository, npcAnimationNotifiers, mainCharacterEventNotifiers) { _emoteNotifiers = emoteNotifiers; @@ -67,10 +68,11 @@ public class PlayerLevelUpFromSpellCastHandler : PlayerLevelUpHandler public PlayerLevelUpFromSpellCastHandler(IPlayerInfoProvider playerInfoProvider, ICurrentMapStateRepository currentMapStateRepository, ICharacterRepository characterRepository, + ICharacterSessionRepository characterSessionRepository, IEnumerable npcAnimationNotifiers, IEnumerable mainCharacterEventNotifiers, IEnumerable emoteNotifiers) - : base(playerInfoProvider, currentMapStateRepository, characterRepository, + : base(playerInfoProvider, currentMapStateRepository, characterRepository, characterSessionRepository, npcAnimationNotifiers, mainCharacterEventNotifiers, emoteNotifiers) { } } } diff --git a/EOLib/PacketHandlers/Quest/QuestListHandler.cs b/EOLib/PacketHandlers/Quest/QuestListHandler.cs new file mode 100644 index 000000000..504c0b224 --- /dev/null +++ b/EOLib/PacketHandlers/Quest/QuestListHandler.cs @@ -0,0 +1,72 @@ +using AutomaticTypeMapper; +using EOLib.Domain.Interact.Quest; +using EOLib.Domain.Login; +using EOLib.Net; +using EOLib.Net.Handlers; +using System.Collections.Generic; + +namespace EOLib.PacketHandlers.Quest +{ + [AutoMappedType] + public class QuestListHandler : InGameOnlyPacketHandler + { + private readonly IQuestDataRepository _questDataRepository; + + public override PacketFamily Family => PacketFamily.Quest; + + public override PacketAction Action => PacketAction.List; + + public QuestListHandler(IPlayerInfoProvider playerInfoProvider, + IQuestDataRepository questDataRepository) + : base(playerInfoProvider) + { + _questDataRepository = questDataRepository; + } + + public override bool HandlePacket(IPacket packet) + { + var page = (QuestPage)packet.ReadChar(); + var numQuests = packet.ReadShort(); + + switch (page) + { + case QuestPage.Progress: + { + var progress = new List(numQuests); + + for (int i = 0; packet.ReadPosition < packet.Length && i < numQuests; i++) + { + var progressData = new QuestProgressData() + .WithName(packet.ReadBreakString()) + .WithDescription(packet.ReadBreakString()) + .WithIcon((BookIcon)packet.ReadShort()) + .WithProgress(packet.ReadShort()) + .WithTarget(packet.ReadShort()); + + progress.Add(progressData); + + if (packet.ReadByte() != 255) + return false; + } + + _questDataRepository.QuestProgress = progress; + } + break; + case QuestPage.History: + { + var completedQuests = new List(numQuests); + + for (int i = 0; packet.ReadPosition < packet.Length && i < numQuests; i++) + completedQuests.Add(packet.ReadBreakString()); + + _questDataRepository.QuestHistory = completedQuests; + } + break; + default: + return false; + } + + return true; + } + } +} diff --git a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs index 20382a4e9..9faa41c78 100644 --- a/EndlessClient/Dialogs/Actions/InGameDialogActions.cs +++ b/EndlessClient/Dialogs/Actions/InGameDialogActions.cs @@ -15,6 +15,8 @@ public class InGameDialogActions : IInGameDialogActions, INPCInteractionNotifier { private readonly IFriendIgnoreListDialogFactory _friendIgnoreListDialogFactory; private readonly IPaperdollDialogFactory _paperdollDialogFactory; + private readonly ISessionExpDialogFactory _sessionExpDialogFactory; + private readonly IQuestStatusDialogFactory _questStatusDialogFactory; private readonly IActiveDialogRepository _activeDialogRepository; private readonly IShopDataRepository _shopDataRepository; private readonly IQuestDataRepository _questDataRepository; @@ -23,14 +25,18 @@ public class InGameDialogActions : IInGameDialogActions, INPCInteractionNotifier public InGameDialogActions(IFriendIgnoreListDialogFactory friendIgnoreListDialogFactory, IPaperdollDialogFactory paperdollDialogFactory, + ISessionExpDialogFactory sessionExpDialogFactory, + IQuestStatusDialogFactory questStatusDialogFactory, + IShopDialogFactory shopDialogFactory, + IQuestDialogFactory questDialogFactory, IActiveDialogRepository activeDialogRepository, IShopDataRepository shopDataRepository, - IQuestDataRepository questDataRepository, - IShopDialogFactory shopDialogFactory, - IQuestDialogFactory questDialogFactory) + IQuestDataRepository questDataRepository) { _friendIgnoreListDialogFactory = friendIgnoreListDialogFactory; _paperdollDialogFactory = paperdollDialogFactory; + _sessionExpDialogFactory = sessionExpDialogFactory; + _questStatusDialogFactory = questStatusDialogFactory; _activeDialogRepository = activeDialogRepository; _shopDataRepository = shopDataRepository; _questDataRepository = questDataRepository; @@ -62,6 +68,30 @@ public void ShowIgnoreListDialog() }); } + public void ShowSessionExpDialog() + { + _activeDialogRepository.SessionExpDialog.MatchNone(() => + { + var dlg = _sessionExpDialogFactory.Create(); + dlg.DialogClosed += (_, _) => _activeDialogRepository.SessionExpDialog = Option.None(); + _activeDialogRepository.SessionExpDialog = Option.Some(dlg); + + dlg.Show(); + }); + } + + public void ShowQuestStatusDialog() + { + _activeDialogRepository.QuestStatusDialog.MatchNone(() => + { + var dlg = _questStatusDialogFactory.Create(); + dlg.DialogClosed += (_, _) => _activeDialogRepository.QuestStatusDialog = Option.None(); + _activeDialogRepository.QuestStatusDialog = Option.Some(dlg); + + dlg.Show(); + }); + } + public void ShowPaperdollDialog(ICharacter character, bool isMainCharacter) { _activeDialogRepository.PaperdollDialog.MatchNone(() => @@ -126,6 +156,10 @@ public interface IInGameDialogActions void ShowIgnoreListDialog(); + void ShowSessionExpDialog(); + + void ShowQuestStatusDialog(); + void ShowPaperdollDialog(ICharacter character, bool isMainCharacter); void ShowShopDialog(); diff --git a/EndlessClient/Dialogs/ActiveDialogRepository.cs b/EndlessClient/Dialogs/ActiveDialogRepository.cs index bab7fc4ec..bd7bf1060 100644 --- a/EndlessClient/Dialogs/ActiveDialogRepository.cs +++ b/EndlessClient/Dialogs/ActiveDialogRepository.cs @@ -11,6 +11,10 @@ public interface IActiveDialogProvider : IDisposable { Option FriendIgnoreDialog { get; } + Option SessionExpDialog { get; } + + Option QuestStatusDialog { get; } + Option PaperdollDialog { get; } Option ShopDialog { get; } @@ -24,6 +28,10 @@ public interface IActiveDialogRepository : IDisposable { Option FriendIgnoreDialog { get; set; } + Option SessionExpDialog { get; set; } + + Option QuestStatusDialog { get; set; } + Option PaperdollDialog { get; set; } Option ShopDialog { get; set; } @@ -38,6 +46,10 @@ public class ActiveDialogRepository : IActiveDialogRepository, IActiveDialogProv { public Option FriendIgnoreDialog { get; set; } + public Option SessionExpDialog { get; set; } + + public Option QuestStatusDialog { get; set; } + public Option PaperdollDialog { get; set; } public Option ShopDialog { get; set; } @@ -51,6 +63,8 @@ IReadOnlyList> ActiveDialogs return new[] { FriendIgnoreDialog.Map(d => (IXNADialog)d), + SessionExpDialog.Map(d => (IXNADialog)d), + QuestStatusDialog.Map(d => (IXNADialog)d), PaperdollDialog.Map(d => (IXNADialog)d), ShopDialog.Map(d => (IXNADialog)d), QuestDialog.Map(d => (IXNADialog)d), @@ -68,6 +82,8 @@ public void Dispose() dlg.MatchSome(d => d.Dispose()); FriendIgnoreDialog = Option.None(); + SessionExpDialog = Option.None(); + QuestStatusDialog = Option.None(); PaperdollDialog = Option.None(); ShopDialog = Option.None(); QuestDialog = Option.None(); diff --git a/EndlessClient/Dialogs/Factories/QuestStatusDialogFactory.cs b/EndlessClient/Dialogs/Factories/QuestStatusDialogFactory.cs new file mode 100644 index 000000000..ecdb3f1c2 --- /dev/null +++ b/EndlessClient/Dialogs/Factories/QuestStatusDialogFactory.cs @@ -0,0 +1,46 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Services; +using EOLib.Domain.Character; +using EOLib.Domain.Interact.Quest; +using EOLib.Graphics; +using EOLib.Localization; + +namespace EndlessClient.Dialogs.Factories +{ + [AutoMappedType] + public class QuestStatusDialogFactory : IQuestStatusDialogFactory + { + private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly IEODialogButtonService _dialogButtonService; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly IQuestDataProvider _questDataProvider; + private readonly ICharacterProvider _characterProvider; + + public QuestStatusDialogFactory(INativeGraphicsManager nativeGraphicsManager, + IEODialogButtonService dialogButtonService, + ILocalizedStringFinder localizedStringFinder, + IQuestDataProvider questDataProvider, + ICharacterProvider characterProvider) + { + _nativeGraphicsManager = nativeGraphicsManager; + _dialogButtonService = dialogButtonService; + _localizedStringFinder = localizedStringFinder; + _questDataProvider = questDataProvider; + _characterProvider = characterProvider; + } + + public QuestStatusDialog Create() + { + return new QuestStatusDialog(_nativeGraphicsManager, + _dialogButtonService, + _localizedStringFinder, + _questDataProvider, + _characterProvider); + } + } + + public interface IQuestStatusDialogFactory + { + QuestStatusDialog Create(); + } +} diff --git a/EndlessClient/Dialogs/Factories/SessionExpDialogFactory.cs b/EndlessClient/Dialogs/Factories/SessionExpDialogFactory.cs new file mode 100644 index 000000000..6eb6e954c --- /dev/null +++ b/EndlessClient/Dialogs/Factories/SessionExpDialogFactory.cs @@ -0,0 +1,49 @@ +using AutomaticTypeMapper; +using EndlessClient.Dialogs.Services; +using EOLib.Domain.Character; +using EOLib.Graphics; +using EOLib.Localization; + +namespace EndlessClient.Dialogs.Factories +{ + [AutoMappedType] + public class SessionExpDialogFactory : ISessionExpDialogFactory + { + private readonly INativeGraphicsManager _nativeGraphicsManager; + private readonly IEODialogButtonService _dialogButtonService; + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly ICharacterProvider _characterProvider; + private readonly IExperienceTableProvider _expTableProvider; + private readonly ICharacterSessionProvider _characterSessionProvider; + + public SessionExpDialogFactory(INativeGraphicsManager nativeGraphicsManager, + IEODialogButtonService dialogButtonService, + ILocalizedStringFinder localizedStringFinder, + ICharacterProvider characterProvider, + IExperienceTableProvider expTableProvider, + ICharacterSessionProvider characterSessionProvider) + { + _nativeGraphicsManager = nativeGraphicsManager; + _dialogButtonService = dialogButtonService; + _localizedStringFinder = localizedStringFinder; + _characterProvider = characterProvider; + _expTableProvider = expTableProvider; + _characterSessionProvider = characterSessionProvider; + } + + public SessionExpDialog Create() + { + return new SessionExpDialog(_nativeGraphicsManager, + _dialogButtonService, + _localizedStringFinder, + _characterProvider, + _expTableProvider, + _characterSessionProvider); + } + } + + public interface ISessionExpDialogFactory + { + SessionExpDialog Create(); + } +} diff --git a/EndlessClient/Dialogs/ListDialogItem.cs b/EndlessClient/Dialogs/ListDialogItem.cs index b98267dff..993f9f281 100644 --- a/EndlessClient/Dialogs/ListDialogItem.cs +++ b/EndlessClient/Dialogs/ListDialogItem.cs @@ -19,8 +19,8 @@ public enum ListItemStyle private int _index; private int _xOffset, _yOffset; - private IXNALabel _primaryText; - private IXNALabel _subText; + protected IXNALabel _primaryText; + protected IXNALabel _subText; private readonly Texture2D _gfxPadThing; private readonly Texture2D _backgroundColor; @@ -244,7 +244,7 @@ protected override void OnDrawControl(GameTime gameTime) _spriteBatch.Begin(); if (_drawBackground) { - _spriteBatch.Draw(_backgroundColor, DrawAreaWithParentOffset, Color.FromNonPremultiplied(255, 255, 255, 64)); + _spriteBatch.Draw(_backgroundColor, DrawAreaWithParentOffset, Color.FromNonPremultiplied(255, 255, 255, 16)); } if (Style == ListItemStyle.Large) diff --git a/EndlessClient/Dialogs/Old/QuestHistoryDialogListItem.cs b/EndlessClient/Dialogs/Old/QuestHistoryDialogListItem.cs deleted file mode 100644 index 899e9b531..000000000 --- a/EndlessClient/Dialogs/Old/QuestHistoryDialogListItem.cs +++ /dev/null @@ -1,75 +0,0 @@ -using EndlessClient.Old; -using EOLib; -using EOLib.Graphics; -using EOLib.Localization; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using XNAControls.Old; - -namespace EndlessClient.Dialogs.Old -{ - public class QuestHistoryDialogListItem : OldListDialogItem - { - public string QuestName - { - get { return Text; } - set { Text = value; } - } - - private readonly Texture2D m_iconTexture; - - private static readonly Vector2 m_firstIconLocation = new Vector2(6, 0); - private static readonly Vector2 m_signalLocation = new Vector2(270, 0); - - private readonly bool _constructorFinished; - - public QuestHistoryDialogListItem(OldScrollingListDialog parent, int index = -1) - : base(parent, ListItemStyle.Small, index) - { - m_iconTexture = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 68, true); - - _setSize(427, 16); - - m_primaryText.DrawLocation = new Vector2(m_primaryText.DrawLocation.X + 25, m_primaryText.DrawLocation.Y); - m_secondaryText = new XNALabel(new Rectangle(290, (int)m_primaryText.DrawLocation.Y, 1, 1), Constants.FontSize08pt5) - { - AutoSize = true, - BackColor = m_primaryText.BackColor, - ForeColor = m_primaryText.ForeColor, - Text = OldWorld.GetString(EOResourceID.QUEST_COMPLETED) - }; - m_secondaryText.SetParent(this); - - _constructorFinished = true; - } - - public override void Draw(GameTime gameTime) - { - if (!Visible || !_constructorFinished) return; - - SpriteBatch.Begin(); - - SpriteBatch.Draw(m_iconTexture, - m_firstIconLocation + new Vector2(17 + OffsetX + xOff, OffsetY + yOff + (DrawArea.Height * Index)), - GetIconSourceRectangle(), Color.White); - SpriteBatch.Draw(m_iconTexture, - m_signalLocation + new Vector2(17 + OffsetX + xOff, OffsetY + yOff + (DrawArea.Height * Index)), - GetSignalSourceRectangle(), Color.White); - - SpriteBatch.End(); - - base.Draw(gameTime); - } - - private static Rectangle GetIconSourceRectangle() - { - //always show 'completed' icon - return new Rectangle(75, 0, 15, 15); - } - - private static Rectangle GetSignalSourceRectangle() - { - return new Rectangle(0, 15, 15, 15); - } - } -} diff --git a/EndlessClient/Dialogs/Old/QuestProgressDialog.cs b/EndlessClient/Dialogs/Old/QuestProgressDialog.cs deleted file mode 100644 index a70a9ec4a..000000000 --- a/EndlessClient/Dialogs/Old/QuestProgressDialog.cs +++ /dev/null @@ -1,212 +0,0 @@ -using System; -using System.Collections.Generic; -using EndlessClient.Dialogs.Services; -using EndlessClient.Old; -using EOLib; -using EOLib.Graphics; -using EOLib.Localization; -using EOLib.Net.API; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using XNAControls.Old; - -namespace EndlessClient.Dialogs.Old -{ - public class QuestProgressDialog : OldScrollingListDialog - { - public static QuestProgressDialog Instance { get; private set; } - - public static void Show(PacketAPI api) - { - if (Instance != null) - Instance.Close(null, XNADialogResult.NO_BUTTON_PRESSED); - - Instance = new QuestProgressDialog(api); - - if (!api.RequestQuestHistory(QuestPage.Progress)) - { - Instance.Close(null, XNADialogResult.NO_BUTTON_PRESSED); - EOGame.Instance.DoShowLostConnectionDialogAndReturnToMainMenu(); - } - } - - //controls - private readonly XNAButton m_history, m_progress; - - //state fields - private bool _historyRequested; - private short _numQuests; - private List _questInfo; - private List _completedQuests; - - private QuestProgressDialog(PacketAPI api) - : base(api) - { - DialogClosing += (o, e) => - { - Instance = null; - }; - - _setupBGTexture(); - - m_history = new XNAButton(smallButtonSheet, new Vector2(288, 252), _getSmallButtonOut(SmallButton.History), _getSmallButtonOver(SmallButton.History)); - m_history.SetParent(this); - m_history.OnClick += _historyClick; - - m_progress = new XNAButton(smallButtonSheet, new Vector2(288, 252), _getSmallButtonOut(SmallButton.Progress), _getSmallButtonOver(SmallButton.Progress)) - { - Visible = false - }; - m_progress.SetParent(this); - m_progress.OnClick += _progressClick; - - var ok = new XNAButton(smallButtonSheet, new Vector2(380, 252), _getSmallButtonOut(SmallButton.Ok), _getSmallButtonOver(SmallButton.Ok)); - ok.SetParent(this); - ok.OnClick += (o, e) => Close(ok, XNADialogResult.OK); - - dlgButtons.AddRange(new[] { m_history, ok }); - - m_titleText = new XNALabel(new Rectangle(18, 14, 452, 19), Constants.FontSize08pt5) - { - AutoSize = false, - TextAlign = LabelAlignment.MiddleLeft, - ForeColor = ColorConstants.LightGrayText, - Text = " " - }; - m_titleText.SetParent(this); - - m_scrollBar.DrawLocation = new Vector2(449, 44); - SmallItemStyleMaxItemDisplay = 10; - ListItemType = OldListDialogItem.ListItemStyle.Small; - } - - private void _setupBGTexture() - { - Texture2D wholeBgText = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 59); - Texture2D bgText = new Texture2D(Game.GraphicsDevice, wholeBgText.Width, wholeBgText.Height / 2); - Color[] data = new Color[bgText.Width * bgText.Height]; - - wholeBgText.GetData(0, new Rectangle(0, 0, bgText.Width, bgText.Height), data, 0, data.Length); - bgText.SetData(data); - - _setBackgroundTexture(bgText); - } - - public void SetInProgressDisplayData(short numQuests, List questInfo) - { - ClearItemList(); - _numQuests = numQuests; - _questInfo = questInfo; - _setTitleProgress(); - _setMessageProgress(); - } - - public void SetHistoryDisplayData(short numQuests, List completedQuestNames) - { - ClearItemList(); - _numQuests = numQuests; - _completedQuests = completedQuestNames; - _setTitleHistory(); - _setMessageHistory(); - } - - private void _setTitleProgress() - { - m_titleText.Text = - $"{OldWorld.Instance.MainPlayer.ActiveCharacter.Name}'s {OldWorld.GetString(EOResourceID.QUEST_PROGRESS)}"; - } - - private void _setTitleHistory() - { - m_titleText.Text = - $"{OldWorld.Instance.MainPlayer.ActiveCharacter.Name}'s {OldWorld.GetString(EOResourceID.QUEST_HISTORY)}"; - } - - private void _setMessageProgress() - { - if (_questInfo.Count == 0) - { - AddItemToList(new QuestProgressDialogListItem(this, 0) - { - QuestName = OldWorld.GetString(EOResourceID.QUEST_DID_NOT_START_ANY), - QuestStep = " ", - ShowIcons = false, - QuestProgress = " " - }, false); - - return; - } - - int ndx = 0; - foreach (var quest in _questInfo) - { - var nextItem = new QuestProgressDialogListItem(this, ndx++) - { - QuestName = quest.Name, - QuestStep = quest.Description, - QuestContextIcon = quest.IconIndex, - QuestProgress = quest.Target > 0 ? $"{quest.Progress} / {quest.Target}" : "n / a" - }; - AddItemToList(nextItem, false); - } - } - - private void _setMessageHistory() - { - if (_completedQuests.Count == 0) - { - AddItemToList(new QuestProgressDialogListItem(this, 0) - { - QuestName = OldWorld.GetString(EOResourceID.QUEST_DID_NOT_FINISH_ANY), - QuestStep = " ", - ShowIcons = false, - QuestProgress = " " - }, false); - - return; - } - - int ndx = 0; - foreach (string quest in _completedQuests) - { - AddItemToList(new QuestHistoryDialogListItem(this, ndx++) { QuestName = quest }, false); - } - } - - private void _historyClick(object sender, EventArgs e) - { - m_progress.Visible = true; - m_history.Visible = false; - - dlgButtons.Remove(m_history); - dlgButtons.Insert(0, m_progress); - - m_scrollBar.ScrollToTop(); - - if (!_historyRequested) - { - if (!m_api.RequestQuestHistory(QuestPage.History)) - { - Close(null, XNADialogResult.NO_BUTTON_PRESSED); - ((EOGame)Game).DoShowLostConnectionDialogAndReturnToMainMenu(); - } - _historyRequested = true; - } - else - SetHistoryDisplayData(_numQuests, _completedQuests); - } - - private void _progressClick(object sender, EventArgs e) - { - m_progress.Visible = false; - m_history.Visible = true; - - dlgButtons.Remove(m_progress); - dlgButtons.Insert(0, m_history); - - m_scrollBar.ScrollToTop(); - - SetInProgressDisplayData(_numQuests, _questInfo); - } - } -} diff --git a/EndlessClient/Dialogs/Old/QuestProgressDialogListItem.cs b/EndlessClient/Dialogs/Old/QuestProgressDialogListItem.cs deleted file mode 100644 index 41a0e8f89..000000000 --- a/EndlessClient/Dialogs/Old/QuestProgressDialogListItem.cs +++ /dev/null @@ -1,107 +0,0 @@ -using EndlessClient.Old; -using EOLib; -using EOLib.Graphics; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using XNAControls.Old; - -namespace EndlessClient.Dialogs.Old -{ - public class QuestProgressDialogListItem : OldListDialogItem - { - public int QuestContextIcon { get; set; } - - public string QuestName - { - get { return Text; } - set { Text = value; } - } - - public string QuestStep - { - get { return SubText; } - set { SubText = value; } - } - - private readonly XNALabel m_progress; - public string QuestProgress - { - get { return m_progress.Text; } - set { m_progress.Text = value; } - } - - public bool ShowIcons { private get; set; } - - private readonly Texture2D m_iconTexture; - - private static readonly Vector2 m_firstIconLocation = new Vector2(6, 0); - private static readonly Vector2 m_secondIconLocation = new Vector2(151, 0); - private static readonly Vector2 m_signalLocation = new Vector2(334, 0); - - private readonly bool _constructorFinished; - - public QuestProgressDialogListItem(OldScrollingListDialog parent, int index = -1) - : base(parent, ListItemStyle.Small, index) - { - m_iconTexture = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 68, true); - ShowIcons = true; - - _setSize(427, 16); - - m_primaryText.DrawLocation = new Vector2(m_primaryText.DrawLocation.X + 25, m_primaryText.DrawLocation.Y); - m_secondaryText = new XNALabel(new Rectangle(169, (int)m_primaryText.DrawLocation.Y, 1, 1), Constants.FontSize08pt5) - { - AutoSize = true, - BackColor = m_primaryText.BackColor, - ForeColor = m_primaryText.ForeColor, - Text = " " - }; - m_secondaryText.SetParent(this); - m_progress = new XNALabel(new Rectangle(353, (int)m_primaryText.DrawLocation.Y, 1, 1), Constants.FontSize08pt5) - { - AutoSize = true, - BackColor = m_primaryText.BackColor, - ForeColor = m_primaryText.ForeColor, - Text = " " - }; - m_progress.SetParent(this); - - _constructorFinished = true; - } - - public override void Draw(GameTime gameTime) - { - if (!Visible || !_constructorFinished) return; - - - if (ShowIcons) - { - SpriteBatch.Begin(); - - SpriteBatch.Draw(m_iconTexture, - m_firstIconLocation + new Vector2(17 + OffsetX + xOff, OffsetY + yOff + (DrawArea.Height * Index)), - GetIconSourceRectangle(0), Color.White); - SpriteBatch.Draw(m_iconTexture, - m_secondIconLocation + new Vector2(17 + OffsetX + xOff, OffsetY + yOff + (DrawArea.Height * Index)), - GetIconSourceRectangle(QuestContextIcon), Color.White); - SpriteBatch.Draw(m_iconTexture, - m_signalLocation + new Vector2(17 + OffsetX + xOff, OffsetY + yOff + (DrawArea.Height * Index)), - GetSignalSourceRectangle(), Color.White); - - SpriteBatch.End(); - } - - base.Draw(gameTime); - } - - private static Rectangle GetIconSourceRectangle(int index) - { - return new Rectangle(index * 15, 0, 15, 15); - } - - private static Rectangle GetSignalSourceRectangle() - { - return new Rectangle(0, 15, 15, 15); - } - } -} diff --git a/EndlessClient/Dialogs/Old/SessionExpDialog.cs b/EndlessClient/Dialogs/Old/SessionExpDialog.cs deleted file mode 100644 index d36f37ab9..000000000 --- a/EndlessClient/Dialogs/Old/SessionExpDialog.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using EndlessClient.Dialogs.Services; -using EndlessClient.Old; -using EOLib; -using EOLib.Graphics; -using EOLib.Localization; -using EOLib.Net.API; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; -using XNAControls.Old; - -namespace EndlessClient.Dialogs.Old -{ - public class SessionExpDialog : EODialogBase - { - private static SessionExpDialog inst; - public new static void Show() - { - if (inst != null) return; - - inst = new SessionExpDialog(); - inst.DialogClosing += (o, e) => inst = null; - } - - private readonly Texture2D m_icons; - private readonly Rectangle m_signal; - private readonly Rectangle m_icon; - - private SessionExpDialog() - : base((PacketAPI)null) - { - bgTexture = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 61); - _setSize(bgTexture.Width, bgTexture.Height); - - m_icons = ((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 68, true); - m_signal = new Rectangle(0, 15, 15, 15); - m_icon = new Rectangle(0, 0, 15, 15); - - XNAButton okButton = new XNAButton(smallButtonSheet, new Vector2(98, 214), _getSmallButtonOut(SmallButton.Ok), _getSmallButtonOver(SmallButton.Ok)); - okButton.OnClick += (sender, args) => Close(okButton, XNADialogResult.OK); - okButton.SetParent(this); - - XNALabel title = new XNALabel(new Rectangle(20, 17, 1, 1), Constants.FontSize08pt5) - { - AutoSize = false, - Text = OldWorld.GetString(EOResourceID.DIALOG_TITLE_PERFORMANCE), - ForeColor = ColorConstants.LightGrayText - }; - title.SetParent(this); - - XNALabel[] leftSide = new XNALabel[8], rightSide = new XNALabel[8]; - for (int i = 48; i <= 160; i += 16) - { - leftSide[(i - 48) / 16] = new XNALabel(new Rectangle(38, i, 1, 1), Constants.FontSize08pt5) - { - AutoSize = false, - ForeColor = ColorConstants.LightGrayText - }; - leftSide[(i - 48) / 16].SetParent(this); - rightSide[(i - 48) / 16] = new XNALabel(new Rectangle(158, i, 1, 1), Constants.FontSize08pt5) - { - AutoSize = false, - ForeColor = ColorConstants.LightGrayText - }; - rightSide[(i - 48) / 16].SetParent(this); - } - - leftSide[0].Text = OldWorld.GetString(EOResourceID.DIALOG_PERFORMANCE_TOTALEXP); - leftSide[1].Text = OldWorld.GetString(EOResourceID.DIALOG_PERFORMANCE_NEXT_LEVEL); - leftSide[2].Text = OldWorld.GetString(EOResourceID.DIALOG_PERFORMANCE_EXP_NEEDED); - leftSide[3].Text = OldWorld.GetString(EOResourceID.DIALOG_PERFORMANCE_TODAY_EXP); - leftSide[4].Text = OldWorld.GetString(EOResourceID.DIALOG_PERFORMANCE_TOTAL_AVG); - leftSide[5].Text = OldWorld.GetString(EOResourceID.DIALOG_PERFORMANCE_TODAY_AVG); - leftSide[6].Text = OldWorld.GetString(EOResourceID.DIALOG_PERFORMANCE_BEST_KILL); - leftSide[7].Text = OldWorld.GetString(EOResourceID.DIALOG_PERFORMANCE_LAST_KILL); - OldCharacter c = OldWorld.Instance.MainPlayer.ActiveCharacter; - rightSide[0].Text = $"{c.Stats.Experience}"; - rightSide[1].Text = $"{OldWorld.Instance.exp_table[c.Stats.Level + 1]}"; - rightSide[2].Text = $"{OldWorld.Instance.exp_table[c.Stats.Level + 1] - c.Stats.Experience}"; - rightSide[3].Text = $"{c.TodayExp}"; - rightSide[4].Text = $"{(int) (c.Stats.Experience/(c.Stats.Usage/60.0))}"; - int sessionTime = (int)(DateTime.Now - EOGame.Instance.Hud.SessionStartTime).TotalMinutes; - rightSide[5].Text = $"{(sessionTime > 0 ? (c.TodayExp/sessionTime) : 0)}"; - rightSide[6].Text = $"{c.TodayBestKill}"; - rightSide[7].Text = $"{c.TodayLastKill}"; - - Array.ForEach(leftSide, lbl => lbl.ResizeBasedOnText()); - Array.ForEach(rightSide, lbl => lbl.ResizeBasedOnText()); - - Center(Game.GraphicsDevice); - DrawLocation = new Vector2(DrawLocation.X, 15); - endConstructor(false); - } - - public override void Draw(GameTime gt) - { - //base draw logic handles drawing the background + child controls - base.Draw(gt); - - SpriteBatch.Begin(); - //icons next to labels - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 22, DrawAreaWithOffset.Y + 48), m_icon, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 22, DrawAreaWithOffset.Y + 64), m_icon, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 22, DrawAreaWithOffset.Y + 80), m_icon, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 22, DrawAreaWithOffset.Y + 96), m_icon, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 22, DrawAreaWithOffset.Y + 112), m_icon, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 22, DrawAreaWithOffset.Y + 128), m_icon, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 22, DrawAreaWithOffset.Y + 144), m_icon, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 22, DrawAreaWithOffset.Y + 160), m_icon, Color.White); - - //signal next to exp labels - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 142, DrawAreaWithOffset.Y + 48), m_signal, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 142, DrawAreaWithOffset.Y + 64), m_signal, Color.White); - SpriteBatch.Draw(m_icons, new Vector2(DrawAreaWithOffset.X + 142, DrawAreaWithOffset.Y + 80), m_signal, Color.White); - SpriteBatch.End(); - } - } -} diff --git a/EndlessClient/Dialogs/PaperdollDialog.cs b/EndlessClient/Dialogs/PaperdollDialog.cs index b9ef8ea6f..1f631c489 100644 --- a/EndlessClient/Dialogs/PaperdollDialog.cs +++ b/EndlessClient/Dialogs/PaperdollDialog.cs @@ -40,7 +40,6 @@ public class PaperdollDialog : BaseEODialog private readonly IStatusLabelSetter _statusLabelSetter; private readonly bool _isMainCharacter; private readonly Texture2D _characterIconSheet; - private readonly Texture2D _background; private Option _characterIconSourceRect; private readonly InventoryPanel _inventoryPanel; @@ -87,12 +86,8 @@ public class PaperdollDialog : BaseEODialog _childItems = new List(); - _background = _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 49); - SetSize(_background.Width, _background.Height / 2); - - // this needs to be set for CenterInGameView to work properly - // todo: fix - BackgroundTexture = new Texture2D(GraphicsDevice, DrawArea.Width, DrawArea.Height); + BackgroundTexture = _nativeGraphicsManager.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, new Vector2(276, 253), @@ -161,9 +156,9 @@ protected override void OnUpdateControl(GameTime gameTime) protected override void OnDrawControl(GameTime gameTime) { - _spriteBatch.Begin(); + base.OnDrawControl(gameTime); - _spriteBatch.Draw(_background, DrawAreaWithParentOffset, new Rectangle(0, DrawArea.Height * Character.RenderProperties.Gender, DrawArea.Width, DrawArea.Height), Color.White); + _spriteBatch.Begin(); _characterIconSourceRect.MatchSome(sourceRect => { @@ -176,16 +171,6 @@ protected override void OnDrawControl(GameTime gameTime) }); _spriteBatch.End(); - - base.OnDrawControl(gameTime); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - BackgroundTexture.Dispose(); - - base.Dispose(disposing); } private void UpdateDisplayedData(IPaperdollData paperdollData) diff --git a/EndlessClient/Dialogs/QuestDialog.cs b/EndlessClient/Dialogs/QuestDialog.cs index fa5ddabd2..fd53c5132 100644 --- a/EndlessClient/Dialogs/QuestDialog.cs +++ b/EndlessClient/Dialogs/QuestDialog.cs @@ -30,7 +30,7 @@ public class QuestDialog : ScrollingListDialog IQuestDataProvider questDataProvider, IENFFileProvider enfFileProvider, IContentProvider contentProvider) - : base(nativeGraphicsManager, dialogButtonService, dialogSize: ScrollingListDialogSize.SmallDialog) + : base(nativeGraphicsManager, dialogButtonService, dialogSize: ScrollingListDialogSize.Small) { _questActions = questActions; _questDataProvider = questDataProvider; diff --git a/EndlessClient/Dialogs/QuestStatusDialog.cs b/EndlessClient/Dialogs/QuestStatusDialog.cs new file mode 100644 index 000000000..a7f9c3f34 --- /dev/null +++ b/EndlessClient/Dialogs/QuestStatusDialog.cs @@ -0,0 +1,131 @@ +using EndlessClient.Dialogs.Services; +using EOLib.Domain.Character; +using EOLib.Domain.Interact.Quest; +using EOLib.Graphics; +using EOLib.Localization; +using Microsoft.Xna.Framework; +using System.Collections.Generic; + +namespace EndlessClient.Dialogs +{ + public class QuestStatusDialog : ScrollingListDialog + { + private readonly ILocalizedStringFinder _localizedStringFinder; + private readonly IQuestDataProvider _questDataProvider; + private readonly ICharacterProvider _characterProvider; + + + private IReadOnlyList _cachedProgress = new List(); + private IReadOnlyList _cachedHistory = new List(); + + private QuestPage _page; + + public QuestStatusDialog(INativeGraphicsManager nativeGraphicsManager, + IEODialogButtonService dialogButtonService, + ILocalizedStringFinder localizedStringFinder, + IQuestDataProvider questDataProvider, + ICharacterProvider characterProvider) + : base(nativeGraphicsManager, dialogButtonService, ScrollingListDialogSize.Medium) + { + ListItemType = ListDialogItem.ListItemStyle.Small; + Buttons = ScrollingListDialogButtons.HistoryOk; + _localizedStringFinder = localizedStringFinder; + _questDataProvider = questDataProvider; + _characterProvider = characterProvider; + HistoryAction += (_, _) => ShowHistory(); + ProgressAction += (_, _) => ShowProgress(); + + _page = QuestPage.Progress; + } + + protected override void OnUpdateControl(GameTime gameTime) + { + if (_questDataProvider.QuestHistory != _cachedHistory) + { + _cachedHistory = _questDataProvider.QuestHistory; + if (_page == QuestPage.History) + ShowHistory(); + } + else if (_questDataProvider.QuestProgress != _cachedProgress) + { + _cachedProgress = _questDataProvider.QuestProgress; + if (_page == QuestPage.Progress) + ShowProgress(); + } + + base.OnUpdateControl(gameTime); + } + + private void ShowHistory() + { + ClearItemList(); + SetTitle(QuestPage.History); + + if (_cachedHistory.Count == 0) + { + AddItemToList( + new QuestStatusListDialogItem(this, QuestPage.History) + { + QuestName = _localizedStringFinder.GetString(EOResourceID.QUEST_DID_NOT_FINISH_ANY), + ShowIcons = false + }, + sortList: false); + } + + foreach (var questName in _cachedHistory) + { + var nextItem = new QuestStatusListDialogItem(this, QuestPage.History) + { + QuestName = questName, + QuestProgress = _localizedStringFinder.GetString(EOResourceID.QUEST_COMPLETED), + }; + AddItemToList(nextItem, sortList: false); + } + + _scrollBar.ScrollToTop(); + Buttons = ScrollingListDialogButtons.ProgressOk; + } + + private void ShowProgress() + { + ClearItemList(); + SetTitle(QuestPage.Progress); + + if (_cachedProgress.Count == 0) + { + AddItemToList( + new QuestStatusListDialogItem(this, QuestPage.Progress) + { + QuestName = _localizedStringFinder.GetString(EOResourceID.QUEST_DID_NOT_START_ANY), + ShowIcons = false, + }, + sortList: false); + } + + foreach (var quest in _cachedProgress) + { + var nextItem = new QuestStatusListDialogItem(this, QuestPage.Progress) + { + QuestName = quest.Name, + QuestStep = quest.Description, + Icon = (QuestStatusListDialogItem.QuestStatusIcon)quest.IconIndex, + QuestProgress = quest.Target > 0 ? $"{quest.Progress} / {quest.Target}" : "n / a" + }; + AddItemToList(nextItem, sortList: false); + } + + _scrollBar.ScrollToTop(); + Buttons = ScrollingListDialogButtons.HistoryOk; + } + + private void SetTitle(QuestPage page) + { + var resource = page == QuestPage.Progress + ? EOResourceID.QUEST_PROGRESS + : EOResourceID.QUEST_HISTORY; + var description = _localizedStringFinder.GetString(resource); + + Title = $"{_characterProvider.MainCharacter.Name}'s {description}"; + } + } +} diff --git a/EndlessClient/Dialogs/QuestStatusListDialogItem.cs b/EndlessClient/Dialogs/QuestStatusListDialogItem.cs new file mode 100644 index 000000000..1a28d1c41 --- /dev/null +++ b/EndlessClient/Dialogs/QuestStatusListDialogItem.cs @@ -0,0 +1,132 @@ +using EOLib; +using EOLib.Domain.Interact.Quest; +using EOLib.Graphics; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using XNAControls; + +namespace EndlessClient.Dialogs +{ + public class QuestStatusListDialogItem : ListDialogItem + { + public enum QuestStatusIcon + { + None = 0, + Talk = 1, + Item = 2, + Kill = 3, + Step = 4, + Complete = 5 + }; + + private static readonly Vector2 _firstIconPosition = new Vector2(6, 0); + private static readonly Vector2 _secondIconPosition = new Vector2(151, 0); + private readonly Vector2 _signalPosition; + + private readonly IXNALabel _progress; + private readonly Texture2D _iconTexture; + private readonly QuestPage _page; + + public QuestStatusIcon Icon { get; set; } + + public string QuestName + { + get => PrimaryText; + set => PrimaryText = value; + } + + public string QuestStep + { + get => SubText; + set => SubText = value; + } + + public string QuestProgress + { + get => _progress.Text; + set => _progress.Text = value; + } + + public bool ShowIcons { get; set; } + + public QuestStatusListDialogItem(QuestStatusDialog parent, QuestPage page) + : base(parent, ListItemStyle.Small) + { + _iconTexture = parent.GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 68, true); + ShowIcons = true; + + SetSize(427, 16); + + _primaryText.DrawPosition += new Vector2(25, 0); + _subText.DrawPosition = new Vector2(169, _primaryText.DrawPosition.Y); + ((DrawableGameComponent)_subText).Visible = true; + + PrimaryText = " "; + SubText = " "; + + _progress = new XNALabel(Constants.FontSize09) + { + DrawPosition = new Vector2(page == QuestPage.Progress ? 353 : 289, _primaryText.DrawPosition.Y), + AutoSize = true, + BackColor = _primaryText.BackColor, + ForeColor = _primaryText.ForeColor, + Text = " ", + Visible = true, + }; + + _signalPosition = page == QuestPage.Progress + ? new Vector2(334, 0) + : new Vector2(270, 0); + + Icon = page == QuestPage.Progress + ? QuestStatusIcon.None + : QuestStatusIcon.Complete; + _page = page; + } + + public override void Initialize() + { + _progress.Initialize(); + _progress.SetParentControl(this); + + base.Initialize(); + } + + protected override void OnDrawControl(GameTime gameTime) + { + base.OnDrawControl(gameTime); + + if (ShowIcons) + { + _spriteBatch.Begin(); + + _spriteBatch.Draw(_iconTexture, + DrawPositionWithParentOffset + _firstIconPosition, + GetIconSourceRectangle(_page == QuestPage.Progress ? QuestStatusIcon.None : QuestStatusIcon.Complete), Color.White); + + if (_page == QuestPage.Progress) + { + _spriteBatch.Draw(_iconTexture, + DrawPositionWithParentOffset + _secondIconPosition, + GetIconSourceRectangle(Icon), Color.White); + } + + _spriteBatch.Draw(_iconTexture, + DrawPositionWithParentOffset + _signalPosition, + GetSignalSourceRectangle(), Color.White); + + _spriteBatch.End(); + } + } + + private static Rectangle GetIconSourceRectangle(QuestStatusIcon index) + { + return new Rectangle((int)index * 15, 0, 15, 15); + } + + private static Rectangle GetSignalSourceRectangle() + { + return new Rectangle(0, 15, 15, 15); + } + } +} diff --git a/EndlessClient/Dialogs/ScrollingListDialog.cs b/EndlessClient/Dialogs/ScrollingListDialog.cs index 2d8c34f5b..6d3a86b7f 100644 --- a/EndlessClient/Dialogs/ScrollingListDialog.cs +++ b/EndlessClient/Dialogs/ScrollingListDialog.cs @@ -3,6 +3,7 @@ using EOLib; using EOLib.Graphics; using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; using System.Linq; @@ -13,25 +14,33 @@ namespace EndlessClient.Dialogs [Flags] public enum ScrollingListDialogButtons { - Add = 1, - Cancel = 2, - Back = 4, - Next = 8, - Ok = 16, - DualButtons = 32, - // todo: if enum values are ever added to this, the logic in ScrollingListDialog.Buttons needs to be updated - AddCancel = DualButtons | Add | Cancel, - BackCancel = DualButtons | Back | Cancel, - BackOk = DualButtons | Back | Ok, - CancelOk = DualButtons | Cancel | Ok, - BackNext = DualButtons | Back | Next, - CancelNext = DualButtons | Cancel | Next, + None = 0x00, + Add = 0x01, + Cancel = 0x02, + Back = 0x04, + Next = 0x08, + Ok = 0x10, + History = 0x20, + Progress = 0x40, + DualButtons = 0x80, + + AddCancel = DualButtons | Add | Cancel, + BackCancel = DualButtons | Back | Cancel, + BackOk = DualButtons | Back | Ok, + CancelOk = DualButtons | Cancel | Ok, + BackNext = DualButtons | Back | Next, + CancelNext = DualButtons | Cancel | Next, + HistoryOk = DualButtons | History | Ok, + ProgressOk = DualButtons | Progress | Ok, } public enum ScrollingListDialogSize { - LargeDialog, - SmallDialog, + // todo: exp dialog adds another one. Maybe need to name these after the specific dialogs they represent + Large, // standard dialog with large list items (chest, locker, shop) + Medium, // quest progress/history dialog + MediumWithHeader, // todo: implement boards + Small, // npc quest dialog } public class ScrollingListDialog : BaseEODialog @@ -44,6 +53,7 @@ public class ScrollingListDialog : BaseEODialog protected readonly XNAButton _add, _back, _cancel; protected readonly XNAButton _next, _ok; + protected readonly XNAButton _history, _progress; protected readonly Vector2 _button1Position, _button2Position, _buttonCenterPosition; @@ -60,18 +70,32 @@ public string Title set => _titleText.Text = value; } - public int ItemsToShow { get; set; } + public int ItemsToShow + { + get + { + if (ListItemType == ListDialogItem.ListItemStyle.Large) + return 5; + + switch (DialogSize) + { + case ScrollingListDialogSize.Large: return 12; + case ScrollingListDialogSize.Medium: return 10; + case ScrollingListDialogSize.Small: return 6; + default: throw new NotImplementedException(); + } + } + } public ListDialogItem.ListItemStyle ListItemType { get => _listItemType; set { - if (value == ListDialogItem.ListItemStyle.Large && DialogSize == ScrollingListDialogSize.SmallDialog) + if (value == ListDialogItem.ListItemStyle.Large && DialogSize == ScrollingListDialogSize.Small) throw new InvalidOperationException("Can't use large ListDialogItem with small scrolling dialog"); _listItemType = value; - ItemsToShow = _listItemType == ListDialogItem.ListItemStyle.Large ? 5 : DialogSize == ScrollingListDialogSize.SmallDialog ? 6 : 12; _scrollBar.LinesToRender = ItemsToShow; } } @@ -87,6 +111,8 @@ public ScrollingListDialogButtons Buttons _next.Visible = Buttons.HasFlag(ScrollingListDialogButtons.Next); _ok.Visible = Buttons.HasFlag(ScrollingListDialogButtons.Ok); _cancel.Visible = Buttons.HasFlag(ScrollingListDialogButtons.Cancel); + _history.Visible = Buttons.HasFlag(ScrollingListDialogButtons.History); + _progress.Visible = Buttons.HasFlag(ScrollingListDialogButtons.Progress); if (Buttons.HasFlag(ScrollingListDialogButtons.DualButtons)) { @@ -101,6 +127,8 @@ public ScrollingListDialogButtons Buttons { _back.DrawPosition = _button1Position; _cancel.DrawPosition = _button1Position; + _history.DrawPosition = _button1Position; + _progress.DrawPosition = _button1Position; _next.DrawPosition = _button2Position; _ok.DrawPosition = _button2Position; @@ -127,35 +155,40 @@ public ScrollingListDialogButtons Buttons public event EventHandler NextAction; + public event EventHandler HistoryAction; + + public event EventHandler ProgressAction; + public bool ChildControlClickHandled { get; set; } public ScrollingListDialog(INativeGraphicsManager nativeGraphicsManager, IEODialogButtonService dialogButtonService, - ScrollingListDialogSize dialogSize = ScrollingListDialogSize.LargeDialog) + ScrollingListDialogSize dialogSize = ScrollingListDialogSize.Large) : base(isInGame: true) { + // todo: implement boards + if (dialogSize == ScrollingListDialogSize.MediumWithHeader) + throw new NotImplementedException(); + GraphicsManager = nativeGraphicsManager; DialogSize = dialogSize; - var isLargeDialog = DialogSize == ScrollingListDialogSize.LargeDialog; - _listItems = new List(); _titleText = new XNALabel(Constants.FontSize09) { - DrawArea = isLargeDialog ? new Rectangle(16, 13, 253, 19) : new Rectangle(16, 16, 255, 18), + DrawArea = GetTitleDrawArea(DialogSize), AutoSize = false, TextAlign = LabelAlignment.MiddleLeft, ForeColor = ColorConstants.LightGrayText }; _titleText.SetParentControl(this); - _scrollBar = new ScrollBar(new Vector2(252, 44), new Vector2(16, isLargeDialog ? 199 : 99), ScrollBarColors.LightOnMed, GraphicsManager); + _scrollBar = new ScrollBar(new Vector2(DialogSize == ScrollingListDialogSize.Medium ? 449 : 252, 44), new Vector2(16, GetScrollBarHeight(DialogSize)), ScrollBarColors.LightOnMed, GraphicsManager); _scrollBar.SetParentControl(this); - BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, isLargeDialog ? 52 : 67); - - var yCoord = isLargeDialog ? 252 : 152; + BackgroundTexture = GraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, GetBackgroundTexture(DialogSize)); + BackgroundTextureSource = GetBackgroundSourceRectangle(BackgroundTexture, DialogSize); _add = new XNAButton(dialogButtonService.SmallButtonSheet, Vector2.Zero, dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Add), @@ -190,6 +223,28 @@ public ScrollingListDialogButtons Buttons _next.OnClick += (o, e) => NextAction?.Invoke(o, e); NextAction += (_, _) => _otherClicked = true; + _history = new XNAButton(dialogButtonService.SmallButtonSheet, Vector2.Zero, + dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.History), + dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.History)) + { + Visible = false, + UpdateOrder = 1, + }; + _history.SetParentControl(this); + _history.OnClick += (o, e) => HistoryAction?.Invoke(o, e); + HistoryAction += (_, _) => _otherClicked = true; + + _progress = new XNAButton(dialogButtonService.SmallButtonSheet, Vector2.Zero, + dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Progress), + dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.Progress)) + { + Visible = false, + UpdateOrder = 1, + }; + _progress.SetParentControl(this); + _progress.OnClick += (o, e) => ProgressAction?.Invoke(o, e); + ProgressAction += (_, _) => _otherClicked = true; + _ok = new XNAButton(dialogButtonService.SmallButtonSheet, Vector2.Zero, dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Ok), dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.Ok)) @@ -210,11 +265,9 @@ public ScrollingListDialogButtons Buttons _cancel.SetParentControl(this); _cancel.OnClick += (_, _) => { if (!_otherClicked) { Close(XNADialogResult.Cancel); } }; - ItemsToShow = ListItemType == ListDialogItem.ListItemStyle.Large ? 5 : DialogSize == ScrollingListDialogSize.SmallDialog ? 6 : 12; - - _button1Position = new Vector2(isLargeDialog ? 48 : 89, yCoord); - _button2Position = new Vector2(isLargeDialog ? 144 : 183, yCoord); - _buttonCenterPosition = new Vector2(96, yCoord); + _button1Position = GetButton1Position(DialogSize); + _button2Position = GetButton2Position(DialogSize); + _buttonCenterPosition = GetButtonCenterPosition(DrawArea, _ok.DrawArea, DialogSize); Buttons = ScrollingListDialogButtons.AddCancel; @@ -237,6 +290,8 @@ public void SetItemList(List itemList) _listItems[i].Index = i; if (i > _scrollBar.LinesToRender) _listItems[i].Visible = false; + + _listItems[i].Initialize(); } } @@ -250,6 +305,8 @@ public void AddItemToList(ListDialogItem item, bool sortList) for (int i = 0; i < _listItems.Count; ++i) _listItems[i].Index = i; + item.Initialize(); + _scrollBar.UpdateDimensions(_listItems.Count); } @@ -334,5 +391,77 @@ protected override void OnUpdateControl(GameTime gameTime) _otherClicked = false; } + + private static Rectangle GetTitleDrawArea(ScrollingListDialogSize size) + { + switch(size) + { + case ScrollingListDialogSize.Large: return new Rectangle(16, 13, 253, 19); + case ScrollingListDialogSize.Medium: return new Rectangle(18, 14, 452, 19); + case ScrollingListDialogSize.Small: return new Rectangle(16, 16, 255, 18); + default: throw new NotImplementedException(); + } + } + + private static int GetScrollBarHeight(ScrollingListDialogSize size) + { + switch (size) + { + case ScrollingListDialogSize.Large: + case ScrollingListDialogSize.Medium: return 199; + case ScrollingListDialogSize.Small: return 99; + default: throw new NotImplementedException(); + } + } + + private static int GetBackgroundTexture(ScrollingListDialogSize size) + { + switch (size) + { + case ScrollingListDialogSize.Large: return 52; + case ScrollingListDialogSize.Medium: return 59; + case ScrollingListDialogSize.Small: return 67; + default: throw new NotImplementedException(); + } + } + + private static Rectangle? GetBackgroundSourceRectangle(Texture2D backgroundTexture, ScrollingListDialogSize size) + { + switch (size) + { + case ScrollingListDialogSize.Large: return null; + case ScrollingListDialogSize.Medium: return new Rectangle(0, 0, backgroundTexture.Width, backgroundTexture.Height / 2); + case ScrollingListDialogSize.Small: return null; + default: throw new NotImplementedException(); + } + } + + private static Vector2 GetButton1Position(ScrollingListDialogSize size) + { + switch (size) + { + case ScrollingListDialogSize.Large: return new Vector2(48, 252); + case ScrollingListDialogSize.Medium: return new Vector2(288, 252); + case ScrollingListDialogSize.Small: return new Vector2(89, 152); + default: throw new NotImplementedException(); + } + } + + private static Vector2 GetButton2Position(ScrollingListDialogSize size) + { + switch (size) + { + case ScrollingListDialogSize.Large: return new Vector2(144, 252); + case ScrollingListDialogSize.Medium: return new Vector2(380, 252); + case ScrollingListDialogSize.Small: return new Vector2(183, 152); + default: throw new NotImplementedException(); + } + } + + private static Vector2 GetButtonCenterPosition(Rectangle dialogArea, Rectangle buttonArea, ScrollingListDialogSize size) + { + var yCoord = GetButton1Position(size).Y; + return new Vector2((dialogArea.Width - buttonArea.Width) / 2, yCoord); + } } } diff --git a/EndlessClient/Dialogs/SessionExpDialog.cs b/EndlessClient/Dialogs/SessionExpDialog.cs new file mode 100644 index 000000000..917e06635 --- /dev/null +++ b/EndlessClient/Dialogs/SessionExpDialog.cs @@ -0,0 +1,124 @@ +using System; +using EndlessClient.Dialogs.Services; +using EOLib; +using EOLib.Domain.Character; +using EOLib.Graphics; +using EOLib.Localization; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using XNAControls; + +namespace EndlessClient.Dialogs +{ + public class SessionExpDialog : BaseEODialog + { + private static readonly Rectangle _signalSource; + private static readonly Rectangle _iconSource; + + private readonly Texture2D _icons; + + static SessionExpDialog() + { + _signalSource = new Rectangle(0, 15, 15, 15); + _iconSource = new Rectangle(0, 0, 15, 15); + } + + public SessionExpDialog(INativeGraphicsManager nativeGraphicsManager, + IEODialogButtonService dialogButtonService, + ILocalizedStringFinder localizedStringFinder, + ICharacterProvider characterProvider, + IExperienceTableProvider expTableProvider, + ICharacterSessionProvider characterSessionProvider) + : base(isInGame: true) + { + BackgroundTexture = nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 61); + + _icons = nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 68, true); + + var okButton = new XNAButton(dialogButtonService.SmallButtonSheet, + new Vector2(98, 214), + dialogButtonService.GetSmallDialogButtonOutSource(SmallButton.Ok), + dialogButtonService.GetSmallDialogButtonOverSource(SmallButton.Ok)); + okButton.OnClick += (_, _) => Close(XNADialogResult.OK); + okButton.SetParentControl(this); + okButton.Initialize(); + + var title = new XNALabel(Constants.FontSize09) + { + DrawPosition = new Vector2(20, 17), + AutoSize = false, + Text = localizedStringFinder.GetString(EOResourceID.DIALOG_TITLE_PERFORMANCE), + ForeColor = ColorConstants.LightGrayText + }; + title.SetParentControl(this); + title.Initialize(); + + XNALabel[] leftSide = new XNALabel[8], rightSide = new XNALabel[8]; + for (int i = 0; i < leftSide.Length; i++) + { + leftSide[i] = new XNALabel(Constants.FontSize09) + { + DrawPosition = new Vector2(38, 48 + 18 * i), + AutoSize = false, + ForeColor = ColorConstants.LightGrayText + }; + leftSide[i].SetParentControl(this); + leftSide[i].Initialize(); + + rightSide[i] = new XNALabel(Constants.FontSize09) + { + DrawPosition = new Vector2(158, 48 + 18 * i), + AutoSize = false, + ForeColor = ColorConstants.LightGrayText + }; + rightSide[i].SetParentControl(this); + rightSide[i].Initialize(); + } + + leftSide[0].Text = localizedStringFinder.GetString(EOResourceID.DIALOG_PERFORMANCE_TOTALEXP); + leftSide[1].Text = localizedStringFinder.GetString(EOResourceID.DIALOG_PERFORMANCE_NEXT_LEVEL); + leftSide[2].Text = localizedStringFinder.GetString(EOResourceID.DIALOG_PERFORMANCE_EXP_NEEDED); + leftSide[3].Text = localizedStringFinder.GetString(EOResourceID.DIALOG_PERFORMANCE_TODAY_EXP); + leftSide[4].Text = localizedStringFinder.GetString(EOResourceID.DIALOG_PERFORMANCE_TOTAL_AVG); + leftSide[5].Text = localizedStringFinder.GetString(EOResourceID.DIALOG_PERFORMANCE_TODAY_AVG); + leftSide[6].Text = localizedStringFinder.GetString(EOResourceID.DIALOG_PERFORMANCE_BEST_KILL); + leftSide[7].Text = localizedStringFinder.GetString(EOResourceID.DIALOG_PERFORMANCE_LAST_KILL); + + var c = characterProvider.MainCharacter; + var level = c.Stats[CharacterStat.Level]; + var exp = c.Stats[CharacterStat.Experience]; + var usage = c.Stats[CharacterStat.Usage]; + + rightSide[0].Text = $"{exp}"; + rightSide[1].Text = $"{expTableProvider.ExperienceByLevel[level + 1]}"; + rightSide[2].Text = $"{expTableProvider.ExperienceByLevel[level + 1] - exp}"; + rightSide[3].Text = $"{characterSessionProvider.TodayTotalExp}"; + rightSide[4].Text = $"{(int)(exp / (usage/60.0))}"; + int sessionTimeMinutes = (int)(DateTime.Now - characterSessionProvider.SessionStartTime).TotalMinutes; + rightSide[5].Text = $"{(sessionTimeMinutes > 0 ? (int)(characterSessionProvider.TodayTotalExp / (sessionTimeMinutes/60.0)) : 0)}"; + rightSide[6].Text = $"{characterSessionProvider.BestKillExp}"; + rightSide[7].Text = $"{characterSessionProvider.LastKillExp}"; + + Array.ForEach(leftSide, lbl => lbl.ResizeBasedOnText()); + Array.ForEach(rightSide, lbl => lbl.ResizeBasedOnText()); + + CenterInGameView(); + DrawPosition = new Vector2(DrawPosition.X, 15); + } + + protected override void OnDrawControl(GameTime gameTime) + { + base.OnDrawControl(gameTime); + + _spriteBatch.Begin(); + + for (int i = 0; i < 8; i++) + _spriteBatch.Draw(_icons, new Vector2(DrawPositionWithParentOffset.X + 18, DrawPositionWithParentOffset.Y + 47 + 18 * i), _iconSource, Color.White); + + for(int i = 0; i < 3; i++) + _spriteBatch.Draw(_icons, new Vector2(DrawPositionWithParentOffset.X + 142, DrawPositionWithParentOffset.Y + 48 + 18 * i), _signalSource, Color.White); + + _spriteBatch.End(); + } + } +} diff --git a/EndlessClient/EndlessClient.csproj b/EndlessClient/EndlessClient.csproj index e8e2d4510..8714f3da1 100644 --- a/EndlessClient/EndlessClient.csproj +++ b/EndlessClient/EndlessClient.csproj @@ -60,6 +60,6 @@ - + diff --git a/EndlessClient/HUD/Controls/HUD.cs b/EndlessClient/HUD/Controls/HUD.cs index 7e7f037dd..a591f7465 100644 --- a/EndlessClient/HUD/Controls/HUD.cs +++ b/EndlessClient/HUD/Controls/HUD.cs @@ -31,8 +31,6 @@ public class HUD : DrawableGameComponent private ChatTextBox chatTextBox; - private readonly XNAButton m_expInfo, m_questInfo; - public DateTime SessionStartTime { get; private set; } public HUD(Game g, PacketAPI api) : base(g) @@ -49,17 +47,6 @@ public HUD(Game g, PacketAPI api) : base(g) //m_party = new OldEOPartyPanel(pnlParty); - m_expInfo = new XNAButton(((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 58), - new Vector2(55, 0), - new Rectangle(331, 30, 22, 14), - new Rectangle(331, 30, 22, 14)) {DrawOrder = HUD_CONTROL_DRAW_ORDER}; - m_expInfo.OnClick += (o, e) => Dialogs.Old.SessionExpDialog.Show(); - m_questInfo = new XNAButton(((EOGame)Game).GFXManager.TextureFromResource(GFXTypes.PostLoginUI, 58), - new Vector2(77, 0), - new Rectangle(353, 30, 22, 14), - new Rectangle(353, 30, 22, 14)) {DrawOrder = HUD_CONTROL_DRAW_ORDER}; - m_questInfo.OnClick += (o, e) => Dialogs.Old.QuestProgressDialog.Show(m_packetAPI); - //no need to make this a member variable //it does not have any resources to dispose and it is automatically disposed by the framework // ReSharper disable once UnusedVariable @@ -160,9 +147,6 @@ protected override void Dispose(bool disposing) m_packetAPI.Dispose(); chatRenderer.Dispose(); - - m_expInfo.Close(); - m_questInfo.Close(); } base.Dispose(disposing); diff --git a/EndlessClient/HUD/Controls/HudControlIdentifier.cs b/EndlessClient/HUD/Controls/HudControlIdentifier.cs index fa0bd0a2a..941639eee 100644 --- a/EndlessClient/HUD/Controls/HudControlIdentifier.cs +++ b/EndlessClient/HUD/Controls/HudControlIdentifier.cs @@ -45,7 +45,7 @@ public enum HudControlIdentifier NewsPanel, //top bar - UsageAndStatsButton, + SessionExpButton, QuestsButton, HPStatusBar, diff --git a/EndlessClient/HUD/Controls/HudControlsFactory.cs b/EndlessClient/HUD/Controls/HudControlsFactory.cs index 0fd264487..b42e1817c 100644 --- a/EndlessClient/HUD/Controls/HudControlsFactory.cs +++ b/EndlessClient/HUD/Controls/HudControlsFactory.cs @@ -154,6 +154,9 @@ public void InjectChatController(IChatController chatController) {HudControlIdentifier.SettingsPanel, CreateStatePanel(InGameStates.Settings)}, {HudControlIdentifier.HelpPanel, CreateStatePanel(InGameStates.Help)}, + {HudControlIdentifier.SessionExpButton, CreateSessionExpButton()}, + {HudControlIdentifier.QuestsButton, CreateQuestButton()}, + {HudControlIdentifier.HPStatusBar, CreateHPStatusBar()}, {HudControlIdentifier.TPStatusBar, CreateTPStatusBar()}, {HudControlIdentifier.SPStatusBar, CreateSPStatusBar()}, @@ -302,6 +305,35 @@ private IGameComponent CreateStatePanel(InGameStates whichState) return retPanel; } + private IGameComponent CreateSessionExpButton() + { + var btn = new XNAButton( + _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 58), + new Vector2(55, 0), + new Rectangle(331, 30, 22, 14), + new Rectangle(331, 30, 22, 14)) + { + DrawOrder = HUD_CONTROL_LAYER + }; + btn.OnClick += (_, _) => _hudButtonController.ClickSessionExp(); + return btn; + + } + + private IGameComponent CreateQuestButton() + { + var btn = new XNAButton( + _nativeGraphicsManager.TextureFromResource(GFXTypes.PostLoginUI, 58), + new Vector2(77, 0), + new Rectangle(353, 30, 22, 14), + new Rectangle(353, 30, 22, 14)) + { + DrawOrder = HUD_CONTROL_LAYER + }; + btn.OnClick += (_, _) => _hudButtonController.ClickQuestStatus(); + return btn; + } + private IGameComponent CreateHPStatusBar() { return new HPStatusBar(_nativeGraphicsManager, (ICharacterProvider)_characterRepository, _userInputRepository) diff --git a/EndlessClient/HUD/HudButtonController.cs b/EndlessClient/HUD/HudButtonController.cs index 4ce087aea..73cb03522 100644 --- a/EndlessClient/HUD/HudButtonController.cs +++ b/EndlessClient/HUD/HudButtonController.cs @@ -4,6 +4,7 @@ using EndlessClient.Dialogs.Actions; using EndlessClient.HUD.Controls; using EndlessClient.HUD.Panels; +using EOLib.Domain.Interact.Quest; using EOLib.Domain.Online; using EOLib.Localization; using System.Linq; @@ -17,6 +18,7 @@ public class HudButtonController : IHudButtonController private readonly IHudStateActions _hudStateActions; private readonly IOnlinePlayerActions _onlinePlayerActions; private readonly IInGameDialogActions _inGameDialogActions; + private readonly IQuestActions _questActions; private readonly IHudControlProvider _hudControlProvider; private readonly IStatusLabelSetter _statusLabelSetter; private readonly ILocalizedStringFinder _localizedStringFinder; @@ -25,6 +27,7 @@ public class HudButtonController : IHudButtonController public HudButtonController(IHudStateActions hudStateActions, IOnlinePlayerActions onlinePlayerActions, IInGameDialogActions inGameDialogActions, + IQuestActions questActions, IHudControlProvider hudControlProvider, IStatusLabelSetter statusLabelSetter, ILocalizedStringFinder localizedStringFinder, @@ -33,6 +36,7 @@ public class HudButtonController : IHudButtonController _hudStateActions = hudStateActions; _onlinePlayerActions = onlinePlayerActions; _inGameDialogActions = inGameDialogActions; + _questActions = questActions; _hudControlProvider = hudControlProvider; _statusLabelSetter = statusLabelSetter; _localizedStringFinder = localizedStringFinder; @@ -116,5 +120,17 @@ public async Task ClickIgnoreList() EOResourceID.STATUS_LABEL_IGNORE_LIST, _localizedStringFinder.GetString(EOResourceID.STATUS_LABEL_USE_RIGHT_MOUSE_CLICK_DELETE)); } + + public void ClickSessionExp() + { + _inGameDialogActions.ShowSessionExpDialog(); + } + + public void ClickQuestStatus() + { + _questActions.RequestQuestHistory(QuestPage.Progress); + _questActions.RequestQuestHistory(QuestPage.History); + _inGameDialogActions.ShowQuestStatusDialog(); + } } } \ No newline at end of file diff --git a/EndlessClient/HUD/IHudButtonController.cs b/EndlessClient/HUD/IHudButtonController.cs index dfd139433..ecc327ee1 100644 --- a/EndlessClient/HUD/IHudButtonController.cs +++ b/EndlessClient/HUD/IHudButtonController.cs @@ -28,6 +28,8 @@ public interface IHudButtonController Task ClickIgnoreList(); - //E/Q + void ClickSessionExp(); + + void ClickQuestStatus(); } } diff --git a/EndlessClient/Old/OldWorld.cs b/EndlessClient/Old/OldWorld.cs index e03dd4850..3d46b1123 100644 --- a/EndlessClient/Old/OldWorld.cs +++ b/EndlessClient/Old/OldWorld.cs @@ -288,7 +288,6 @@ public static void IgnoreDialogs(XNAControl control) control.IgnoreDialog(typeof(LockerDialog)); control.IgnoreDialog(typeof(TradeDialog)); control.IgnoreDialog(typeof(SkillmasterDialog)); - control.IgnoreDialog(typeof(QuestProgressDialog)); } public static Texture2D GetSpellIcon(short icon, bool hover) diff --git a/EndlessClient/Old/PacketAPICallbackManager.cs b/EndlessClient/Old/PacketAPICallbackManager.cs index 2fc251a5c..18a3fba5c 100644 --- a/EndlessClient/Old/PacketAPICallbackManager.cs +++ b/EndlessClient/Old/PacketAPICallbackManager.cs @@ -68,10 +68,6 @@ public void AssignCallbacks() m_packetAPI.OnSpellTrain += _statskillTrainSpell; m_packetAPI.OnCharacterStatsReset += _statskillReset; - //quests - m_packetAPI.OnViewQuestProgress += _questProgress; - m_packetAPI.OnViewQuestHistory += _questHistory; - m_packetAPI.OnPlaySoundEffect += _playSoundEffect; //spell casting @@ -340,20 +336,6 @@ private void _statskillReset(StatResetData data) m_game.Hud.RemoveAllSpells(); } - private void _questProgress(short numquests, List questinfo) - { - if (QuestProgressDialog.Instance == null) return; - - QuestProgressDialog.Instance.SetInProgressDisplayData(numquests, questinfo); - } - - private void _questHistory(short numquests, List completedquestnames) - { - if (QuestProgressDialog.Instance == null) return; - - QuestProgressDialog.Instance.SetHistoryDisplayData(numquests, completedquestnames); - } - private void _playSoundEffect(int effectID) { try diff --git a/EndlessClient/Rendering/MapEntityRenderers/ShadowLayerRenderer.cs b/EndlessClient/Rendering/MapEntityRenderers/ShadowLayerRenderer.cs index 51ba323bc..a178bb29a 100644 --- a/EndlessClient/Rendering/MapEntityRenderers/ShadowLayerRenderer.cs +++ b/EndlessClient/Rendering/MapEntityRenderers/ShadowLayerRenderer.cs @@ -17,7 +17,7 @@ public class ShadowLayerRenderer : BaseMapEntityRenderer public override MapRenderLayer RenderLayer => MapRenderLayer.Shadows; - protected override int RenderDistance => 10; + protected override int RenderDistance => 16; public ShadowLayerRenderer(INativeGraphicsManager nativeGraphicsManager, ICurrentMapProvider currentMapProvider,