From 79f8959852f6dc0688a65c88d35e4a8861938244 Mon Sep 17 00:00:00 2001 From: Liza Carvelli Date: Fri, 26 Apr 2024 10:01:23 +0200 Subject: [PATCH] Show rank requirements when expert delivery is locked --- Deliveroo/DeliverooPlugin.GameFunctions.cs | 19 ++++++-- Deliveroo/DeliverooPlugin.cs | 25 +++++++++-- Deliveroo/GameData/GcRankInfo.cs | 33 ++++++++++++++ Deliveroo/Windows/TurnInWindow.cs | 50 ++++++++++++++++++++++ 4 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 Deliveroo/GameData/GcRankInfo.cs diff --git a/Deliveroo/DeliverooPlugin.GameFunctions.cs b/Deliveroo/DeliverooPlugin.GameFunctions.cs index 72d0b21..d1d2593 100644 --- a/Deliveroo/DeliverooPlugin.GameFunctions.cs +++ b/Deliveroo/DeliverooPlugin.GameFunctions.cs @@ -28,7 +28,7 @@ partial class DeliverooPlugin (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)obj.Address, false); } - private unsafe int GetCurrentSealCount() + internal unsafe int GetCurrentSealCount() { InventoryManager* inventoryManager = InventoryManager.Instance(); switch ((GrandCompany)PlayerState.Instance()->GrandCompany) @@ -93,9 +93,22 @@ partial class DeliverooPlugin }; } - private uint GetSealCap() => _sealCaps.TryGetValue(GetGrandCompanyRank(), out var cap) ? cap : 0; + private uint GetSealCap() => _gcRankInfo.TryGetValue(GetGrandCompanyRank(), out var rank) ? rank.MaxSeals : 0; - public uint MaxSealCap => _sealCaps[11]; + public uint MaxSealCap => _gcRankInfo[11].MaxSeals; + + internal uint GetSealsRequiredForNextRank() + => _gcRankInfo.GetValueOrDefault(GetGrandCompanyRank())?.RequiredSeals ?? 0; + + internal byte GetRequiredHuntingLogForNextRank() + => _gcRankInfo.GetValueOrDefault(GetGrandCompanyRank() + 1u)?.RequiredHuntingLog ?? 0; + + internal string? GetNextGrandCompanyRankName() + { + bool female = _clientState.LocalPlayer!.Customize[(int)CustomizeIndex.Gender] == 1; + GrandCompany grandCompany = GetGrandCompany(); + return _gcRankInfo.GetValueOrDefault(GetGrandCompanyRank() + 1u)?.GetName(grandCompany, female); + } public unsafe int GetItemCount(uint itemId, bool checkRetainerInventory) { diff --git a/Deliveroo/DeliverooPlugin.cs b/Deliveroo/DeliverooPlugin.cs index 55014f9..6090bb5 100644 --- a/Deliveroo/DeliverooPlugin.cs +++ b/Deliveroo/DeliverooPlugin.cs @@ -19,6 +19,7 @@ using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; using LLib; using LLib.GameUI; +using Lumina.Excel; using Lumina.Excel.GeneratedSheets; namespace Deliveroo; @@ -52,7 +53,7 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin private readonly ItemCache _itemCache; private readonly ConfigWindow _configWindow; private readonly TurnInWindow _turnInWindow; - private readonly ReadOnlyDictionary _sealCaps; + private readonly ReadOnlyDictionary _gcRankInfo; private readonly Dictionary _retainerItemCache = new(); private Stage _currentStageInternal = Stage.Stopped; @@ -90,8 +91,20 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin _windowSystem.AddWindow(_configWindow); _turnInWindow = new TurnInWindow(this, _pluginInterface, _configuration, _condition, _clientState, _gcRewardsCache, _configWindow, _iconCache); _windowSystem.AddWindow(_turnInWindow); - _sealCaps = dataManager.GetExcelSheet()!.Where(x => x.RowId > 0) - .ToDictionary(x => x.RowId, x => x.MaxSeals) + + _gcRankInfo = dataManager.GetExcelSheet()!.Where(x => x.RowId > 0) + .ToDictionary(x => x.RowId, x => new GcRankInfo + { + NameTwinAddersMale = ExtractRankName(dataManager, x.RowId, r => r.Singular), + NameTwinAddersFemale = ExtractRankName(dataManager, x.RowId, r => r.Singular), + NameMaelstromMale = ExtractRankName(dataManager, x.RowId, r => r.Singular), + NameMaelstromFemale = ExtractRankName(dataManager, x.RowId, r => r.Singular), + NameImmortalFlamesMale = ExtractRankName(dataManager, x.RowId, r => r.Singular), + NameImmortalFlamesFemale = ExtractRankName(dataManager, x.RowId, r => r.Singular), + MaxSeals = x.MaxSeals, + RequiredSeals = x.RequiredSeals, + RequiredHuntingLog = x.Unknown10, + }) .AsReadOnly(); _framework.Update += FrameworkUpdate; @@ -116,6 +129,12 @@ public sealed partial class DeliverooPlugin : IDalamudPlugin _addonLifecycle.RegisterListener(AddonEvent.PostSetup, "SelectYesno", SelectYesNoPostSetup); } + private static string ExtractRankName(IDataManager dataManager, uint rankId, Func func) + where T : ExcelRow + { + return func(dataManager.GetExcelSheet()!.GetRow(rankId)!).ToString(); + } + private void ChatMessage(XivChatType type, uint senderId, ref SeString sender, ref SeString message, ref bool isHandled) { if (_configuration.PauseAtRank <= 0) diff --git a/Deliveroo/GameData/GcRankInfo.cs b/Deliveroo/GameData/GcRankInfo.cs new file mode 100644 index 0000000..2f9e7c9 --- /dev/null +++ b/Deliveroo/GameData/GcRankInfo.cs @@ -0,0 +1,33 @@ +using System; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; + +namespace Deliveroo.GameData +{ + internal sealed class GcRankInfo + { + public required string NameTwinAddersMale { private get; init; } + public required string NameTwinAddersFemale { private get; init; } + public required string NameMaelstromMale { private get; init; } + public required string NameMaelstromFemale { private get; init; } + public required string NameImmortalFlamesMale { private get; init; } + public required string NameImmortalFlamesFemale { private get; init; } + + public required uint MaxSeals { get; init; } + public required uint RequiredSeals { get; init; } + public required byte RequiredHuntingLog { get; init; } + + public string GetName(GrandCompany grandCompany, bool female) + { + return (grandCompany, female) switch + { + (GrandCompany.TwinAdder, false) => NameTwinAddersMale, + (GrandCompany.TwinAdder, true) => NameTwinAddersFemale, + (GrandCompany.Maelstrom, false) => NameMaelstromMale, + (GrandCompany.Maelstrom, true) => NameMaelstromFemale, + (GrandCompany.ImmortalFlames, false) => NameImmortalFlamesMale, + (GrandCompany.ImmortalFlames, true) => NameImmortalFlamesFemale, + _ => throw new ArgumentOutOfRangeException(nameof(grandCompany) + "," + nameof(female)), + }; + } + } +} diff --git a/Deliveroo/Windows/TurnInWindow.cs b/Deliveroo/Windows/TurnInWindow.cs index 27a0d7c..5a173c0 100644 --- a/Deliveroo/Windows/TurnInWindow.cs +++ b/Deliveroo/Windows/TurnInWindow.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; using Dalamud.Game.ClientState.Conditions; +using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Components; @@ -108,6 +109,7 @@ internal sealed class TurnInWindow : LWindow Flags = ImGuiWindowFlags.AlwaysAutoResize; } } + public decimal Multiplier { private get; set; } public string Error { private get; set; } = string.Empty; @@ -186,6 +188,8 @@ internal sealed class TurnInWindow : LWindow { State = false; ImGui.TextColored(ImGuiColors.DalamudRed, "You do not have the required rank for Expert Delivery."); + + DrawNextRankPrequesites(); return; } else if (_configuration.BehaviorOnOtherWorld == Configuration.EBehaviorOnOtherWorld.DisableTurnIn && @@ -256,6 +260,52 @@ internal sealed class TurnInWindow : LWindow ImGui.Text($"Debug (State): {_plugin.CurrentStage}"); } + private unsafe void DrawNextRankPrequesites() + { + string? rankName = _plugin.GetNextGrandCompanyRankName(); + if (rankName != null) + { + int currentSeals = _plugin.GetCurrentSealCount(); + uint requiredSeals = _plugin.GetSealsRequiredForNextRank(); + + int currentHuntingLog = MonsterNoteManager.Instance()->RankDataArraySpan[(int)_plugin.GetGrandCompany() + 7] + .Rank; + byte requiredHuntingLog = _plugin.GetRequiredHuntingLogForNextRank(); + + bool enoughSeals = currentSeals >= requiredSeals; + bool enoughHuntingLog = requiredHuntingLog >= currentHuntingLog; + + if (enoughSeals && enoughHuntingLog) + ImGui.TextColored(ImGuiColors.HealerGreen, $"You meet all requirements to rank up to {rankName}."); + else + ImGui.Text($"Ranking up to {rankName} requires:"); + + ImGui.Indent(); + if (enoughSeals) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); + ImGui.BulletText($"{currentSeals:N0} / {requiredSeals:N0} GC seals"); + ImGui.PopStyleColor(); + } + else + ImGui.BulletText($"{currentSeals:N0} / {requiredSeals:N0} GC seals"); + + if (requiredHuntingLog > 0) + { + if (enoughHuntingLog) + { + ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen); + ImGui.BulletText($"Complete Hunting Log #{requiredHuntingLog}"); + ImGui.PopStyleColor(); + } + else + ImGui.BulletText($"Complete Hunting Log #{requiredHuntingLog}"); + } + + ImGui.Unindent(); + } + } + private void DrawItemsToBuy(GrandCompany grandCompany) { var itemsWrapper = ItemsWrapper;