diff --git a/SomethingNeedDoing/Grammar/Commands/ActionCommand.cs b/SomethingNeedDoing/Grammar/Commands/ActionCommand.cs index 27278a77..8932a211 100644 --- a/SomethingNeedDoing/Grammar/Commands/ActionCommand.cs +++ b/SomethingNeedDoing/Grammar/Commands/ActionCommand.cs @@ -122,7 +122,7 @@ public override async Task Execute(ActiveMacro macro, CancellationToken token) else { // Wait for the data update - if (!DataWaiter.WaitOne(SafeCraftMaxWait)) + if (!DataWaiter.WaitOne(SafeCraftMaxWait) && Service.Configuration.StopMacroIfActionTimeout) throw new MacroActionTimeoutError("Did not receive a timely response"); } diff --git a/SomethingNeedDoing/Grammar/Commands/ItemCommand.cs b/SomethingNeedDoing/Grammar/Commands/ItemCommand.cs index 4ae74ebb..e2b5da1a 100644 --- a/SomethingNeedDoing/Grammar/Commands/ItemCommand.cs +++ b/SomethingNeedDoing/Grammar/Commands/ItemCommand.cs @@ -1,12 +1,14 @@ +using ECommons.DalamudServices; using FFXIVClientStructs.FFXIV.Client.Game; +using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using SomethingNeedDoing.Exceptions; using SomethingNeedDoing.Grammar.Modifiers; using SomethingNeedDoing.Misc; using System.Linq; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading; -using System.Threading.Tasks; using Sheets = Lumina.Excel.GeneratedSheets; namespace SomethingNeedDoing.Grammar.Commands; @@ -18,6 +20,10 @@ internal class ItemCommand : MacroCommand { private static readonly Regex Regex = new(@"^/item\s+(?.*?)\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase); + public static nint itemContextMenuAgent = nint.Zero; + public delegate void UseItemDelegate(nint itemContextMenuAgent, uint itemID, uint inventoryPage, uint inventorySlot, short a5); + public static UseItemDelegate UseItemSig; + private readonly string itemName; private readonly ItemQualityModifier itemQualityMod; @@ -33,6 +39,15 @@ private ItemCommand(string text, string itemName, WaitModifier wait, ItemQuality { this.itemName = itemName.ToLowerInvariant(); this.itemQualityMod = itemQualityMod; + if (!Service.Configuration.UseItemStructsVersion) + { + try + { + UseItemSig = Marshal.GetDelegateForFunctionPointer(Service.SigScanner.ScanText("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 48 8D 0D ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 89 7C 24 38")); + unsafe { itemContextMenuAgent = (nint)Framework.Instance()->GetUiModule()->GetAgentModule()->GetAgentByInternalId(AgentId.InventoryContext); } + } + catch { Svc.Log.Error($"Failed to load {nameof(UseItemSig)}"); } + } } /// @@ -55,7 +70,7 @@ public static ItemCommand Parse(string text) } /// - public override async Task Execute(ActiveMacro macro, CancellationToken token) + public override async System.Threading.Tasks.Task Execute(ActiveMacro macro, CancellationToken token) { Service.Log.Debug($"Executing: {this.Text}"); @@ -64,7 +79,7 @@ public override async Task Execute(ActiveMacro macro, CancellationToken token) var count = this.GetInventoryItemCount(itemId, this.itemQualityMod.IsHq); Service.Log.Debug($"Item Count: {count}"); - if (count == 0) + if (count == 0 && Service.Configuration.StopMacroIfItemNotFound) throw new MacroCommandError("You do not have that item"); this.UseItem(itemId, this.itemQualityMod.IsHq); @@ -81,9 +96,14 @@ private unsafe void UseItem(uint itemID, bool isHQ = false) if (isHQ) itemID += 1_000_000; - var result = agent->UseItem(itemID); - if (result != 0) - throw new MacroCommandError("Failed to use item"); + if (Service.Configuration.UseItemStructsVersion) + { + var result = agent->UseItem(itemID); + if (result != 0 && Service.Configuration.StopMacroIfCantUseItem) + throw new MacroCommandError("Failed to use item"); + } + else + UseItemSig(itemContextMenuAgent, itemID, 9999, 0, 0); } private unsafe int GetInventoryItemCount(uint itemID, bool isHQ) diff --git a/SomethingNeedDoing/Grammar/Commands/WaitAddonCommand.cs b/SomethingNeedDoing/Grammar/Commands/WaitAddonCommand.cs index 7d6699db..ffd21e8d 100644 --- a/SomethingNeedDoing/Grammar/Commands/WaitAddonCommand.cs +++ b/SomethingNeedDoing/Grammar/Commands/WaitAddonCommand.cs @@ -64,10 +64,10 @@ public override async Task Execute(ActiveMacro macro, CancellationToken token) var (addonPtr, isVisible) = await this.LinearWait(AddonCheckInterval, this.maxWait, this.IsAddonVisible, token); - if (addonPtr == IntPtr.Zero) + if (addonPtr == IntPtr.Zero && Service.Configuration.StopMacroIfAddonNotFound) throw new MacroCommandError("Addon not found"); - if (!isVisible) + if (!isVisible && Service.Configuration.StopMacroIfAddonNotVisible) throw new MacroCommandError("Addon not visible"); await this.PerformWait(token); diff --git a/SomethingNeedDoing/Interface/HelpWindow.cs b/SomethingNeedDoing/Interface/HelpWindow.cs index acf436c0..cec8331c 100644 --- a/SomethingNeedDoing/Interface/HelpWindow.cs +++ b/SomethingNeedDoing/Interface/HelpWindow.cs @@ -326,6 +326,11 @@ static void DisplayChangelog(string date, string changes, bool separator = true) ImGui.PushFont(UiBuilder.MonoFont); + DisplayChangelog( + "2024-02-11", + "- Added the ability to toggle ending scripts when encountering certain errors.\n" + + "- Added an alternative system for /useitem\n"); + DisplayChangelog( "2024-02-09", "- Added GetCurrentBait()\n" + @@ -936,6 +941,40 @@ static void DisplayOption(params string[] lines) } } + if (ImGui.CollapsingHeader("/action")) + { + var stopMacro = Service.Configuration.StopMacroIfActionTimeout; + if (ImGui.Checkbox("Stop macro if /action times out", ref stopMacro)) + { + Service.Configuration.StopMacroIfActionTimeout = stopMacro; + Service.Configuration.Save(); + } + } + + if (ImGui.CollapsingHeader("/item")) + { + var defaultUseItem = Service.Configuration.UseItemStructsVersion; + if (ImGui.Checkbox("Use SND's /useitem system", ref defaultUseItem)) + { + Service.Configuration.UseItemStructsVersion = defaultUseItem; + Service.Configuration.Save(); + } + + var stopMacroNotFound = Service.Configuration.StopMacroIfItemNotFound; + if (ImGui.Checkbox("Stop macro if you cannot use an item", ref stopMacroNotFound)) + { + Service.Configuration.StopMacroIfItemNotFound = stopMacroNotFound; + Service.Configuration.Save(); + } + + var stopMacro = Service.Configuration.StopMacroIfCantUseItem; + if (ImGui.Checkbox("Stop macro if you cannot use an item", ref stopMacro)) + { + Service.Configuration.StopMacroIfCantUseItem = stopMacro; + Service.Configuration.Save(); + } + } + if (ImGui.CollapsingHeader("/target")) { var defaultTarget = Service.Configuration.UseSNDTargeting; @@ -945,16 +984,33 @@ static void DisplayOption(params string[] lines) Service.Configuration.Save(); } - var stopMacroIfNoTarget = Service.Configuration.StopMacroIfTargetNotFound; - if (ImGui.Checkbox("Stop macro if target not found (only applies to SND's targeting system).", ref stopMacroIfNoTarget)) + var stopMacro = Service.Configuration.StopMacroIfTargetNotFound; + if (ImGui.Checkbox("Stop macro if target not found (only applies to SND's targeting system).", ref stopMacro)) { - Service.Configuration.StopMacroIfTargetNotFound = stopMacroIfNoTarget; + Service.Configuration.StopMacroIfTargetNotFound = stopMacro; Service.Configuration.Save(); } DisplayOption("- Override the behaviour of /target with SND's system."); } + if (ImGui.CollapsingHeader("/waitaddon")) + { + var stopMacro = Service.Configuration.StopMacroIfAddonNotFound; + if (ImGui.Checkbox("Stop macro if an addon is not found", ref stopMacro)) + { + Service.Configuration.StopMacroIfAddonNotFound = stopMacro; + Service.Configuration.Save(); + } + + var stopMacroVisible = Service.Configuration.StopMacroIfAddonNotVisible; + if (ImGui.Checkbox("Stop macro if an addon isn't visible", ref stopMacroVisible)) + { + Service.Configuration.StopMacroIfAddonNotVisible = stopMacroVisible; + Service.Configuration.Save(); + } + } + ImGui.PopFont(); } diff --git a/SomethingNeedDoing/SomethingNeedDoingConfiguration.cs b/SomethingNeedDoing/SomethingNeedDoingConfiguration.cs index 73ea8b60..e9e72e50 100644 --- a/SomethingNeedDoing/SomethingNeedDoingConfiguration.cs +++ b/SomethingNeedDoing/SomethingNeedDoingConfiguration.cs @@ -114,8 +114,14 @@ public class SomethingNeedDoingConfiguration : IPluginConfiguration public int BeepCount { get; set; } = 3; public bool UseSNDTargeting { get; set; } = true; + public bool UseItemStructsVersion { get; set; } = true; + public bool StopMacroIfActionTimeout { get; set; } = true; + public bool StopMacroIfItemNotFound { get; set; } = true; + public bool StopMacroIfCantUseItem { get; set; } = true; public bool StopMacroIfTargetNotFound { get; set; } = true; + public bool StopMacroIfAddonNotFound { get; set; } = true; + public bool StopMacroIfAddonNotVisible { get; set; } = true; /// /// Gets or sets the chat channel to use.