From 3ca055d3200ada474583cd7be92ca7f90bcc38f0 Mon Sep 17 00:00:00 2001 From: Jukkales Date: Sun, 14 Apr 2024 15:34:26 +0200 Subject: [PATCH] overlay, updates and safety features --- HoardFarm/HoardFarm.cs | 17 +++- HoardFarm/HoardFarm.csproj | 2 +- HoardFarm/ImGuiEx/ImGuiEx.cs | 90 +++++++++++++++++++++ HoardFarm/Model/Configuration.cs | 3 + HoardFarm/Service/HoardFarmService.cs | 45 ++++++++++- HoardFarm/Tasks/EnterHeavenOnHigh.cs | 28 ++++++- HoardFarm/Tasks/UseMagiciteTask.cs | 30 +++++++ HoardFarm/Tasks/UsePomanderTask.cs | 7 +- HoardFarm/Utils/DataIDs.cs | 6 ++ HoardFarm/Utils/Utils.cs | 80 +++++++++++++++++- HoardFarm/Windows/ConfigWindow.cs | 28 ++++++- HoardFarm/Windows/DeepDungeonMenuOverlay.cs | 43 ++++++++++ HoardFarm/Windows/MainWindow.cs | 48 ++++++++--- 13 files changed, 399 insertions(+), 28 deletions(-) create mode 100644 HoardFarm/ImGuiEx/ImGuiEx.cs create mode 100644 HoardFarm/Tasks/UseMagiciteTask.cs create mode 100644 HoardFarm/Windows/DeepDungeonMenuOverlay.cs diff --git a/HoardFarm/HoardFarm.cs b/HoardFarm/HoardFarm.cs index 5eb2118..cb0c8a2 100644 --- a/HoardFarm/HoardFarm.cs +++ b/HoardFarm/HoardFarm.cs @@ -19,6 +19,7 @@ public sealed class HoardFarm : IDalamudPlugin private readonly AchievementService achievementService; private readonly MainWindow mainWindow; private readonly ConfigWindow configWindow; + private readonly DeepDungeonMenuOverlay deepDungeonMenuOverlay; public WindowSystem WindowSystem = new("HoardFarm"); public HoardFarm(DalamudPluginInterface? pluginInterface) @@ -37,9 +38,11 @@ public HoardFarm(DalamudPluginInterface? pluginInterface) mainWindow = new MainWindow(); configWindow = new ConfigWindow(); + deepDungeonMenuOverlay = new DeepDungeonMenuOverlay(); WindowSystem.AddWindow(mainWindow); WindowSystem.AddWindow(configWindow); + WindowSystem.AddWindow(deepDungeonMenuOverlay); hoardFarmService = new HoardFarmService(); HoardService = hoardFarmService; @@ -80,8 +83,6 @@ private void FrameworkUpdate(IFramework framework) public void Dispose() { WindowSystem.RemoveAllWindows(); - mainWindow.Dispose(); - configWindow.Dispose(); hoardFarmService.Dispose(); achievementService.Dispose(); @@ -120,8 +121,7 @@ public void OnCommand(string? args = null) HoardService.HoardMode = !HoardService.HoardMode; return; default: - Achievements.UpdateProgress(); - mainWindow.IsOpen = true; + ShowMainWindow(); break; } } @@ -130,4 +130,13 @@ public void ShowConfigWindow() { configWindow.IsOpen = true; } + + public void ShowMainWindow() + { + if (!mainWindow.IsOpen) + { + Achievements.UpdateProgress(); + mainWindow.IsOpen = true; + } + } } diff --git a/HoardFarm/HoardFarm.csproj b/HoardFarm/HoardFarm.csproj index 104b86f..9a97530 100644 --- a/HoardFarm/HoardFarm.csproj +++ b/HoardFarm/HoardFarm.csproj @@ -2,7 +2,7 @@ Jukkales - 1.2.0.1 + 1.3.0.0 HoardFarm Dalamud Plugin https://github.com/Jukkales/HoardFarm diff --git a/HoardFarm/ImGuiEx/ImGuiEx.cs b/HoardFarm/ImGuiEx/ImGuiEx.cs new file mode 100644 index 0000000..02bcbc5 --- /dev/null +++ b/HoardFarm/ImGuiEx/ImGuiEx.cs @@ -0,0 +1,90 @@ +using System.Numerics; +using System.Runtime.InteropServices; +using Dalamud.Interface; +using Dalamud.Interface.Internal.Notifications; +using Dalamud.Interface.Utility; +using ECommons.ImGuiMethods; +using ImGuiNET; + +namespace HoardFarm.ImGuiEx; + +// https://github.com/UnknownX7/Hypostasis/blob/ccaf819cb755d022790d8955d4283c95a0c10fec/ImGui/Header.cs +public static partial class ImGuiEx +{ + [LibraryImport("cimgui")] + [UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])] + private static partial nint igGetCurrentWindow(); + public static unsafe ImGuiWindow* GetCurrentWindow() => (ImGuiWindow*)igGetCurrentWindow(); + public static unsafe ImGuiWindowFlags GetCurrentWindowFlags() => GetCurrentWindow()->Flags; + public static unsafe bool CurrentWindowHasCloseButton() => GetCurrentWindow()->HasCloseButton != 0; + public record HeaderIconOptions + { + public Vector2 Offset { get; init; } = Vector2.Zero; + public ImGuiMouseButton MouseButton { get; init; } = ImGuiMouseButton.Left; + public string Tooltip { get; init; } = string.Empty; + public uint Color { get; init; } = 0xFFFFFFFF; + public bool ToastTooltipOnClick { get; init; } = false; + public ImGuiMouseButton ToastTooltipOnClickButton { get; init; } = ImGuiMouseButton.Left; + } + + private static uint headerLastWindowID = 0; + private static ulong headerLastFrame = 0; + private static uint headerCurrentPos = 0; + private static float headerImGuiButtonWidth = 0; + + public static bool AddHeaderIcon(string id, FontAwesomeIcon icon, HeaderIconOptions options = null) + { + if (ImGui.IsWindowCollapsed()) return false; + + var scale = ImGuiHelpers.GlobalScale; + var currentID = ImGui.GetID(0); + if (currentID != headerLastWindowID || headerLastFrame != PluginInterface.UiBuilder.FrameCount) + { + headerLastWindowID = currentID; + headerLastFrame = PluginInterface.UiBuilder.FrameCount; + headerCurrentPos = 0; + headerImGuiButtonWidth = 0f; + if (CurrentWindowHasCloseButton()) + headerImGuiButtonWidth += 17 * scale; + if (!GetCurrentWindowFlags().HasFlag(ImGuiWindowFlags.NoCollapse)) + headerImGuiButtonWidth += 17 * scale; + } + + options ??= new(); + var prevCursorPos = ImGui.GetCursorPos(); + var buttonSize = new Vector2(20 * scale); + var buttonPos = new Vector2(ImGui.GetWindowWidth() - buttonSize.X - headerImGuiButtonWidth - 20 * headerCurrentPos++ * scale - ImGui.GetStyle().FramePadding.X * 2, ImGui.GetScrollY() + 1); + ImGui.SetCursorPos(buttonPos); + var drawList = ImGui.GetWindowDrawList(); + drawList.PushClipRectFullScreen(); + + var pressed = false; + ImGui.InvisibleButton(id, buttonSize); + var itemMin = ImGui.GetItemRectMin(); + var itemMax = ImGui.GetItemRectMax(); + var halfSize = ImGui.GetItemRectSize() / 2; + var center = itemMin + halfSize; + if (ImGui.IsWindowHovered() && ImGui.IsMouseHoveringRect(itemMin, itemMax, false)) + { + if (!string.IsNullOrEmpty(options.Tooltip)) + ImGui.SetTooltip(options.Tooltip); + ImGui.GetWindowDrawList().AddCircleFilled(center, halfSize.X, ImGui.GetColorU32(ImGui.IsMouseDown(ImGuiMouseButton.Left) ? ImGuiCol.ButtonActive : ImGuiCol.ButtonHovered)); + if (ImGui.IsMouseReleased(options.MouseButton)) + pressed = true; + if (options.ToastTooltipOnClick && ImGui.IsMouseReleased(options.ToastTooltipOnClickButton)) + PluginInterface.UiBuilder.AddNotification(options.Tooltip!, null, NotificationType.Info); + } + + ImGui.SetCursorPos(buttonPos); + ImGui.PushFont(UiBuilder.IconFont); + var iconString = icon.ToIconString(); + drawList.AddText(UiBuilder.IconFont, ImGui.GetFontSize(), itemMin + halfSize - ImGui.CalcTextSize(iconString) / 2 + options.Offset, options.Color, iconString); + ImGui.PopFont(); + + ImGui.PopClipRect(); + ImGui.SetCursorPos(prevCursorPos); + + return pressed; + } + +} diff --git a/HoardFarm/Model/Configuration.cs b/HoardFarm/Model/Configuration.cs index 3c652b2..fdce4a3 100644 --- a/HoardFarm/Model/Configuration.cs +++ b/HoardFarm/Model/Configuration.cs @@ -15,6 +15,9 @@ public class Configuration : IPluginConfiguration public int OverallRuns { get; set; } public int OverallFoundHoards { get; set; } public int OverallTime { get; set; } + public bool ShowOverlay { get; set; } = true; + public bool ParanoidMode { get; set; } = false; + public void Save() { diff --git a/HoardFarm/Service/HoardFarmService.cs b/HoardFarm/Service/HoardFarmService.cs index 4ced20a..f937230 100644 --- a/HoardFarm/Service/HoardFarmService.cs +++ b/HoardFarm/Service/HoardFarmService.cs @@ -17,6 +17,7 @@ namespace HoardFarm.Service; public class HoardFarmService : IDisposable { public string HoardModeStatus = ""; + public string HoardModeError = ""; private bool hoardModeActive; private readonly Timer updateTimer; public int SessionRuns; @@ -84,6 +85,7 @@ private void EnableFarm() SessionFoundHoards = 0; updateTimer.Enabled = true; HoardModeStatus = "Running"; + HoardModeError = ""; ChatGui.ChatMessage += OnChatMessage; } @@ -146,6 +148,7 @@ private void OnTimerUpdate(object? sender, ElapsedEventArgs e) HoardModeStatus = "Waiting Navmesh"; return; } + if (searchMode && hoardPosition == Vector3.Zero) { if (!SearchLogic()) @@ -161,6 +164,14 @@ private void OnTimerUpdate(object? sender, ElapsedEventArgs e) FinishRun = true; return; } + if (Player.Territory == HoHMapId1) + { + HoardModeStatus = "Please prepare"; + HoardModeError = "Please prepare before starting.\nFloor One is not supported."; + FinishRun = true; + Enqueue(new LeaveDutyTask(), "Leave Duty"); + return; + } if (!InHoH && !InRubySea && NotBusy() && !KyuseiInteractable()) { HoardModeStatus = "Moving to HoH"; @@ -176,15 +187,31 @@ private void OnTimerUpdate(object? sender, ElapsedEventArgs e) return; } HoardModeStatus = "Entering HoH"; + if (Config.ParanoidMode) + { + EnqueueWait(Random.Shared.Next(3000, 6000)); + } Enqueue(new EnterHeavenOnHigh(), "Enter HoH"); } if (InHoH && NotBusy()) { + if (!CheckMinimalSetup()) + { + HoardModeStatus = "Please prepare"; + HoardModeError = "Please prepare before starting.\nYou need at least one Intuition Pomander\nand one Concealment."; + FinishRun = true; + Enqueue(new LeaveDutyTask(), "Leave Duty"); + return; + } + if (!intuitionUsed) { - Enqueue(new UsePomanderTask(Pomander.Intuition), "Use Intuition"); - intuitionUsed = true; + if (CanUsePomander(Pomander.Intuition)) + { + Enqueue(new UsePomanderTask(Pomander.Intuition), "Use Intuition"); + intuitionUsed = true; + } } else { @@ -234,6 +261,20 @@ private void OnTimerUpdate(object? sender, ElapsedEventArgs e) } } + private bool CheckMinimalSetup() + { + if (!CanUsePomander(Pomander.Intuition)) + { + return false; + } + if (CanUsePomander(Pomander.Concealment)) + { + return true; + } + + return CanUsePomander(Pomander.Safety) && CanUseMagicite(); + } + private void LeaveDuty() { HoardModeStatus = "Leaving"; diff --git a/HoardFarm/Tasks/EnterHeavenOnHigh.cs b/HoardFarm/Tasks/EnterHeavenOnHigh.cs index 0bf37d4..2e3e259 100644 --- a/HoardFarm/Tasks/EnterHeavenOnHigh.cs +++ b/HoardFarm/Tasks/EnterHeavenOnHigh.cs @@ -9,11 +9,22 @@ namespace HoardFarm.Tasks; public class EnterHeavenOnHigh : IBaseTask { - public bool? Run() + public unsafe bool? Run() { + TryGetAddonByName("DeepDungeonMenu", out var menu); + TryGetAddonByName("DeepDungeonSaveData", out var save); Enqueue(WaitForYesAlreadyDisabledTask, "Disable Yes Already"); - Enqueue(InteractKyusei, "Interact Kyusei"); - Enqueue(EnterDuty, "Enter Heaven on High"); + PluginLog.Information("menu: {menu}, save: {save}"); + if (menu == null && save == null) + { + Enqueue(InteractKyusei, "Interact Kyusei"); + } + + if ((menu == null && save == null) || (menu != null && save == null)) + { + Enqueue(EnterDuty, "Enter Heaven on High"); + } + Enqueue(SelectSave, "Select Save"); Enqueue(new SelectYesnoTask(ConfirmPartyKoMessageId), "Confirm Party KO"); Enqueue(ConfirmDuty, "Confirm Duty"); @@ -62,6 +73,17 @@ public class EnterHeavenOnHigh : IBaseTask return false; } + + private static unsafe bool VerifySave() + { + if (TryGetAddonByName("DeepDungeonSaveData", out var menu) && IsAddonReady(menu)) + { + var saveId = (uint)(Config.HoardModeSave == 0 ? 21002 : 21001); + GetNodeByIDChain(menu->GetRootNode(), [6, 2]); + } + + return false; + } private static unsafe bool? ConfirmDuty() { diff --git a/HoardFarm/Tasks/UseMagiciteTask.cs b/HoardFarm/Tasks/UseMagiciteTask.cs new file mode 100644 index 0000000..b49b764 --- /dev/null +++ b/HoardFarm/Tasks/UseMagiciteTask.cs @@ -0,0 +1,30 @@ +using ECommons.Automation; +using ECommons.Throttlers; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; +using FFXIVClientStructs.FFXIV.Component.GUI; + +namespace HoardFarm.Tasks; + +public class UseMagiciteTask() : IBaseTask +{ + public unsafe bool? Run() + { + if (TryGetAddonByName("DeepDungeonStatus", out var addon) && IsAddonReady(addon)) + { + if (CanUseMagicite()) + { + Callback.Fire(addon, true, 12, 0); + EnqueueWaitImmediate(3000); + } + + return true; + } + + if (EzThrottler.Throttle("OpenDeepDungeonStatus", 2000)) { + AgentDeepDungeonStatus.Instance()->AgentInterface.Show(); + } + + return false; + } + +} diff --git a/HoardFarm/Tasks/UsePomanderTask.cs b/HoardFarm/Tasks/UsePomanderTask.cs index 00c0777..46e5e63 100644 --- a/HoardFarm/Tasks/UsePomanderTask.cs +++ b/HoardFarm/Tasks/UsePomanderTask.cs @@ -12,8 +12,11 @@ public class UsePomanderTask(Pomander pomander) : IBaseTask { if (TryGetAddonByName("DeepDungeonStatus", out var addon) && IsAddonReady(addon)) { - Callback.Fire(addon, true, 11, (int)pomander); - EnqueueWaitImmediate(2000); + if (CanUsePomander(pomander)) + { + Callback.Fire(addon, true, 11, (int)pomander); + EnqueueWaitImmediate(2000); + } return true; } diff --git a/HoardFarm/Utils/DataIDs.cs b/HoardFarm/Utils/DataIDs.cs index 92fd261..246f54d 100644 --- a/HoardFarm/Utils/DataIDs.cs +++ b/HoardFarm/Utils/DataIDs.cs @@ -9,6 +9,7 @@ public static class DataIDs public static readonly Vector3 KyuseiLocation = new(-2.02948f, 3.0059814f, -611.3528f); public const ushort RubySeaMapId = 613; + public const ushort HoHMapId1 = 770; public const ushort HoHMapId11 = 771; public const ushort HoHMapId21 = 772; @@ -25,4 +26,9 @@ public static class DataIDs public static readonly HashSet ChestIDs = [1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 2007357, 2007358]; + public static readonly uint[] ConcealmentChain = [1, 16, 18, 31, 2]; + public static readonly uint[] SafetyChain = [1, 16, 18, 19, 2]; + public static readonly uint[] IntuitionChain = [1, 16, 18, 32, 2]; + + public static readonly uint[] MagiciteChain = [1, 54, 56, 57, 2]; } diff --git a/HoardFarm/Utils/Utils.cs b/HoardFarm/Utils/Utils.cs index ef55031..db0fda5 100644 --- a/HoardFarm/Utils/Utils.cs +++ b/HoardFarm/Utils/Utils.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Numerics; using Dalamud.Game.ClientState.Conditions; @@ -7,8 +8,10 @@ using ECommons.DalamudServices; using ECommons.GameHelpers; using ECommons.Reflection; +using FFXIVClientStructs.FFXIV.Client.Game.Control; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using FFXIVClientStructs.FFXIV.Component.GUI; +using HoardFarm.Model; namespace HoardFarm.Utils; @@ -22,15 +25,59 @@ public static class Utils public static float Distance(this Vector3 v, Vector3 v2) => new Vector2(v.X - v2.X, v.Z - v2.Z).Length(); public static bool PluginInstalled(string name) => DalamudReflector.TryGetDalamudPlugin(name, out _, false, true); - public static bool NotBusy() + public static unsafe bool NotBusy() { + + var occupied = IsOccupied(); + var target = TargetSystem.Instance()->Target; + + if (occupied && Svc.Condition[ConditionFlag.OccupiedInQuestEvent] && target != null && target->DataID == KyuseiDataId) + { + occupied = false; + } + return Player.Available && Player.Object.CastActionId == 0 - && !IsOccupied() + && !occupied && !Svc.Condition[ConditionFlag.Jumping] && Player.Object.IsTargetable; } + + public static unsafe AtkResNode* GetNodeByIDChain(AtkResNode* node, params uint[] ids) { + if(node == null || ids.Length <= 0) { + return null; + } + + if(node->NodeID == ids[0]) { + if(ids.Length == 1) { + return node; + } + + var newList = new List(ids); + newList.RemoveAt(0); + + var childNode = node->ChildNode; + if(childNode != null) { + return GetNodeByIDChain(childNode, newList.ToArray()); + } + + if((int)node->Type >= 1000) { + var componentNode = node->GetAsAtkComponentNode(); + var component = componentNode->Component; + var uldManager = component->UldManager; + childNode = uldManager.NodeList[0]; + return childNode == null ? null : GetNodeByIDChain(childNode, newList.ToArray()); + } + + return null; + } + + //check siblings + var sibNode = node->PrevSiblingNode; + return sibNode != null ? GetNodeByIDChain(sibNode, ids) : null; + } + public static unsafe AtkUnitBase* FindSelectYesNo(uint rowId) { var s = Svc.Data.GetExcelSheet()!.GetRow(rowId)!.Text @@ -66,7 +113,7 @@ public static unsafe bool KyuseiInteractable() { if (ObjectTable.TryGetFirst(e => e.DataId == KyuseiDataId, out var npc)) { - return npc.Position.Distance(Player.GameObject->Position) < 3f; + return npc.Position.Distance(Player.GameObject->Position) < 7f; } return false; } @@ -75,4 +122,31 @@ public static bool WaitTillOnokoro() { return InRubySea && Player.Interactable && NotBusy(); } + + public static unsafe bool CanUsePomander(Pomander pomander) + { + if (TryGetAddonByName("DeepDungeonStatus", out var addon) && IsAddonReady(addon)) + { + var chain = pomander switch + { + Pomander.Intuition => IntuitionChain, + Pomander.Concealment => ConcealmentChain, + Pomander.Safety => SafetyChain, + _ => [] + }; + return chain.Length != 0 && GetNodeByIDChain(addon->GetRootNode(), chain)->IsVisible; + } + + return false; + } + + public static unsafe bool CanUseMagicite() + { + if (TryGetAddonByName("DeepDungeonStatus", out var addon) && IsAddonReady(addon)) + { + return GetNodeByIDChain(addon->GetRootNode(), MagiciteChain)->IsVisible; + } + + return false; + } } diff --git a/HoardFarm/Windows/ConfigWindow.cs b/HoardFarm/Windows/ConfigWindow.cs index f9998ae..05fb9e8 100644 --- a/HoardFarm/Windows/ConfigWindow.cs +++ b/HoardFarm/Windows/ConfigWindow.cs @@ -1,13 +1,13 @@ using System; using System.Diagnostics; +using Dalamud.Interface; using Dalamud.Interface.Windowing; using ImGuiNET; namespace HoardFarm.Windows; -public class ConfigWindow() : Window("Hoard Farm Config", ImGuiWindowFlags.AlwaysAutoResize), IDisposable +public class ConfigWindow() : Window("Hoard Farm Config", ImGuiWindowFlags.AlwaysAutoResize) { - public void Dispose() { } public override void Draw() { @@ -26,13 +26,35 @@ public override void Draw() ImGui.PopStyleColor(3); ImGui.Spacing(); + ImGui.Separator(); if (ImGui.Button("Reset Statistics")) { Config.OverallRuns = 0; Config.OverallFoundHoards = 0; Config.OverallTime = 0; Config.Save(); - + } + + var showOverlay = Config.ShowOverlay; + if (ImGui.Checkbox("Show \"Open Hoardfarm\"-Overlay", ref showOverlay)) + { + Config.ShowOverlay = showOverlay; + Config.Save(); + } + var paranoid = Config.ParanoidMode; + if (ImGui.Checkbox("Paranoid mode", ref paranoid)) + { + Config.ParanoidMode = paranoid; + Config.Save(); + } + ImGui.SameLine(); + ImGui.PushFont(UiBuilder.IconFont); + ImGui.Text(FontAwesomeIcon.QuestionCircle.ToIconString()); + ImGui.PopFont(); + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip("Paranoid mode will wait some seconds before requeue again.\n" + + "Not really necessary, but makes some people feel better."); } } } diff --git a/HoardFarm/Windows/DeepDungeonMenuOverlay.cs b/HoardFarm/Windows/DeepDungeonMenuOverlay.cs new file mode 100644 index 0000000..32d9824 --- /dev/null +++ b/HoardFarm/Windows/DeepDungeonMenuOverlay.cs @@ -0,0 +1,43 @@ +using System.Numerics; +using Dalamud.Interface.Windowing; +using FFXIVClientStructs.FFXIV.Component.GUI; +using ImGuiNET; + +namespace HoardFarm.Windows; + +public class DeepDungeonMenuOverlay : Window +{ + public DeepDungeonMenuOverlay() : base("DeepDungeonMenuOverlay", + ImGuiWindowFlags.NoDecoration | ImGuiWindowFlags.AlwaysAutoResize, true) + { + RespectCloseHotkey = false; + IsOpen = true; + } + + public override unsafe bool DrawConditions() + { + if (!InRubySea || !KyuseiInteractable() || !Config.ShowOverlay) return false; + if (TryGetAddonByName("DeepDungeonMenu", out var menu) && IsAddonReady(menu)) + { + var width = menu->GetRootNode()->Width * menu->GetRootNode()->GetScaleX(); + Position = new Vector2(menu->X + width - 125, menu->Y - 40); + return true; + } + + if (TryGetAddonByName("DeepDungeonSaveData", out var save) && IsAddonReady(save)) + { + var width = save->GetRootNode()->Width * save->GetRootNode()->GetScaleX(); + Position = new Vector2(save->X + width - 125, save->Y - 40); + return true; + } + return false; + } + + public override void Draw() + { + if (ImGui.Button("Open Hoardfarm")) + { + P.ShowMainWindow(); + } + } +} diff --git a/HoardFarm/Windows/MainWindow.cs b/HoardFarm/Windows/MainWindow.cs index 3bd9dfd..c64947f 100644 --- a/HoardFarm/Windows/MainWindow.cs +++ b/HoardFarm/Windows/MainWindow.cs @@ -1,27 +1,22 @@ using System; +using System.Diagnostics; using Dalamud.Interface; using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Windowing; -using ECommons.ImGuiMethods; using HoardFarm.IPC; using HoardFarm.Model; -using HoardFarm.Service; using ImGuiNET; +using static HoardFarm.ImGuiEx.ImGuiEx; namespace HoardFarm.Windows; -public class MainWindow() : Window($"Hoard Farm {P.GetType().Assembly.GetName().Version}###HoardFarm", ImGuiWindowFlags.AlwaysAutoResize), IDisposable +public class MainWindow() : Window($"Hoard Farm {P.GetType().Assembly.GetName().Version}###HoardFarm", ImGuiWindowFlags.AlwaysAutoResize) { private readonly Configuration conf = Config; - - public void Dispose() { } - + public override void Draw() { - if (ImGuiEx.AddHeaderIcon("OpenConfig", FontAwesomeIcon.Cog, new ImGuiEx.HeaderIconOptions() { Tooltip = "Open Config" })) - { - P.ShowConfigWindow(); - } + HeaderIcons(); using (_ = ImRaii.Disabled(!PluginInstalled(NavmeshIPC.Name))) { @@ -170,7 +165,40 @@ public override void Draw() $"You will need at least {FormatRemaining((20000 - Achievements.Progress) * overallTimeAverage)}\nof farming to complete the achievement."); } + if (HoardService.HoardModeError != string.Empty) { + ImGui.Separator(); + ImGui.PushFont(UiBuilder.IconFont); + ImGui.TextColored(new System.Numerics.Vector4(1, 0, 0, 1), FontAwesomeIcon.ExclamationTriangle.ToIconString()); + ImGui.PopFont(); + ImGui.SameLine(); + ImGui.TextColored(new System.Numerics.Vector4(1, 0, 0, 1),"Unable to run:\n"); + ImGui.Text(HoardService.HoardModeError); + } + + } + private static void HeaderIcons() + { + if (AddHeaderIcon("OpenConfig", FontAwesomeIcon.Cog, new HeaderIconOptions { Tooltip = "Open Config" })) + { + P.ShowConfigWindow(); + } + if (AddHeaderIcon("OpenHelp", FontAwesomeIcon.QuestionCircle, new HeaderIconOptions { Tooltip = "Open Help" })) + { + Process.Start(new ProcessStartInfo + { + FileName = "https://github.com/Jukkales/HoardFarm/wiki/How-to-run", + UseShellExecute = true + }); + } + if (AddHeaderIcon("KofiLink", FontAwesomeIcon.Heart, new HeaderIconOptions { Tooltip = "Support me ♥", Color = 0xFF3030D0 })) + { + Process.Start(new ProcessStartInfo + { + FileName = "https://ko-fi.com/jukkales", + UseShellExecute = true + }); + } } private static String FormatTime(int seconds, bool withHours = true)