diff --git a/ARControl/ARControl.csproj b/ARControl/ARControl.csproj index d61d3c9..55d53c1 100644 --- a/ARControl/ARControl.csproj +++ b/ARControl/ARControl.csproj @@ -1,7 +1,7 @@ net7.0-windows - 2.4 + 2.5 11.0 enable true @@ -16,7 +16,7 @@ $(appdata)\XIVLauncher\addon\Hooks\dev\ - $(appdata)\XIVLauncher\installedPlugins\AutoRetainer\4.2.1.1\ + $(appdata)\XIVLauncher\installedPlugins\AutoRetainer\4.2.1.2\ diff --git a/ARControl/ARControl.json b/ARControl/ARControl.json index 8adb113..5f1ae3c 100644 --- a/ARControl/ARControl.json +++ b/ARControl/ARControl.json @@ -4,5 +4,5 @@ "Punchline": "Better AutoRetainer Venture Planner", "Description": "", "RepoUrl": "https://git.carvel.li/liza/ARControl", - "IconUrl": "https://git.carvel.li/liza/plugin-repo/raw/branch/master/dist/ARControl.png" + "IconUrl": "https://plugins.carvel.li/icons/ARControl.png" } diff --git a/ARControl/AutoRetainerControlPlugin.Sync.cs b/ARControl/AutoRetainerControlPlugin.Sync.cs index 51398fc..c271035 100644 --- a/ARControl/AutoRetainerControlPlugin.Sync.cs +++ b/ARControl/AutoRetainerControlPlugin.Sync.cs @@ -38,6 +38,12 @@ partial class AutoRetainerControlPlugin save = true; } + if (character.Ventures != offlineCharacterData.Ventures) + { + character.Ventures = offlineCharacterData.Ventures; + save = true; + } + List seenRetainers = new(); foreach (var retainerData in offlineCharacterData.RetainerData) { diff --git a/ARControl/AutoRetainerControlPlugin.cs b/ARControl/AutoRetainerControlPlugin.cs index 36ed311..b19728f 100644 --- a/ARControl/AutoRetainerControlPlugin.cs +++ b/ARControl/AutoRetainerControlPlugin.cs @@ -112,127 +112,141 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin _pluginLog.Information("Checking tasks..."); Sync(); - var venturesInProgress = CalculateVenturesInProgress(ch); - foreach (var inpr in venturesInProgress) - { - _pluginLog.Verbose($"Venture In Progress: ItemId {inpr.Key} for a total amount of {inpr.Value}"); - } - IReadOnlyList itemListIds; - if (ch.Type == Configuration.CharacterType.Standalone) - itemListIds = ch.ItemListIds; + if (ch.Ventures == 0) + { + _pluginLog.Warning("Could not assign a next venture from venture list, as the character has no ventures left."); + } + else if (ch.Ventures <= _configuration.Misc.VenturesToKeep) + { + _pluginLog.Warning($"Could not assign a next venture from venture list, character only has {ch.Ventures} left, configuration says to only send out above {_configuration.Misc.VenturesToKeep} ventures."); + } else { - var group = _configuration.CharacterGroups.SingleOrDefault(x => x.Id == ch.CharacterGroupId); - if (group == null) + var venturesInProgress = CalculateVenturesInProgress(ch); + foreach (var inProgress in venturesInProgress) { - _pluginLog.Error($"Unable to resolve character group {ch.CharacterGroupId}."); - return null; + _pluginLog.Verbose( + $"Venture In Progress: ItemId {inProgress.Key} for a total amount of {inProgress.Value}"); } - itemListIds = group.ItemListIds; - } - - var itemLists = itemListIds.Where(listId => listId != Guid.Empty) - .Select(listId => _configuration.ItemLists.SingleOrDefault(x => x.Id == listId)) - .Where(list => list != null) - .Cast() - .ToList(); - InventoryManager* inventoryManager = InventoryManager.Instance(); - foreach (var list in itemLists) - { - _pluginLog.Information($"Checking ventures in list '{list.Name}'"); - IReadOnlyList itemsOnList; - if (list.Type == Configuration.ListType.CollectOneTime) - { - itemsOnList = list.Items - .Select(x => new StockedItem - { - QueuedItem = x, - InventoryCount = 0, - }) - .Where(x => x.RequestedCount > 0) - .ToList() - .AsReadOnly(); - } + IReadOnlyList itemListIds; + if (ch.Type == Configuration.CharacterType.Standalone) + itemListIds = ch.ItemListIds; else { - itemsOnList = list.Items - .Select(x => new StockedItem - { - QueuedItem = x, - InventoryCount = inventoryManager->GetInventoryItemCount(x.ItemId) + - (venturesInProgress.TryGetValue(x.ItemId, out int inProgress) - ? inProgress - : 0), - }) - .Where(x => x.InventoryCount <= x.RequestedCount) - .ToList() - .AsReadOnly(); + var group = _configuration.CharacterGroups.SingleOrDefault(x => x.Id == ch.CharacterGroupId); + if (group == null) + { + _pluginLog.Error($"Unable to resolve character group {ch.CharacterGroupId}."); + return null; + } - // collect items with the least current inventory first - if (list.Priority == Configuration.ListPriority.Balanced) - itemsOnList = itemsOnList.OrderBy(x => x.InventoryCount).ToList().AsReadOnly(); + itemListIds = group.ItemListIds; } - _pluginLog.Debug($"Found {itemsOnList.Count} to-do items on current list"); - if (itemsOnList.Count == 0) - continue; - - foreach (var itemOnList in itemsOnList) + var itemLists = itemListIds.Where(listId => listId != Guid.Empty) + .Select(listId => _configuration.ItemLists.SingleOrDefault(x => x.Id == listId)) + .Where(list => list != null) + .Cast() + .ToList(); + InventoryManager* inventoryManager = InventoryManager.Instance(); + foreach (var list in itemLists) { - _pluginLog.Debug($"Checking venture info for itemId {itemOnList.ItemId}"); - - var (venture, reward) = _ventureResolver.ResolveVenture(ch, retainer, itemOnList.ItemId); - if (venture == null) + _pluginLog.Information($"Checking ventures in list '{list.Name}'"); + IReadOnlyList itemsOnList; + if (list.Type == Configuration.ListType.CollectOneTime) { - venture = _gameCache.Ventures.FirstOrDefault(x => x.ItemId == itemOnList.ItemId); - _pluginLog.Debug($"Retainer doesn't know how to gather itemId {itemOnList.ItemId} ({venture?.Name})"); - } - else if (reward == null) - { - _pluginLog.Debug($"Retainer can't complete venture '{venture.Name}'"); + itemsOnList = list.Items + .Select(x => new StockedItem + { + QueuedItem = x, + InventoryCount = 0, + }) + .Where(x => x.RequestedCount > 0) + .ToList() + .AsReadOnly(); } else { - _chatGui.Print( - new SeString(new UIForegroundPayload(579)) - .Append(SeIconChar.Collectible.ToIconString()) - .Append(new UIForegroundPayload(0)) - .Append($" Sending retainer ") - .Append(new UIForegroundPayload(1)) - .Append(retainerName) - .Append(new UIForegroundPayload(0)) - .Append(" to collect ") - .Append(new UIForegroundPayload(1)) - .Append($"{reward.Quantity}x ") - .Append(new ItemPayload(venture.ItemId)) - .Append(venture.Name) - .Append(RawPayload.LinkTerminator) - .Append(new UIForegroundPayload(0)) - .Append(" for ") - .Append(new UIForegroundPayload(1)) - .Append($"{list.Name} {list.GetIcon()}") - .Append(new UIForegroundPayload(0)) - .Append(".")); - _pluginLog.Information( - $"Setting AR to use venture {venture.RowId}, which should retrieve {reward.Quantity}x {venture.Name}"); - - if (!dryRun) - { - retainer.HasVenture = true; - retainer.LastVenture = venture.RowId; - - if (list.Type == Configuration.ListType.CollectOneTime) + itemsOnList = list.Items + .Select(x => new StockedItem { - itemOnList.RequestedCount = - Math.Max(0, itemOnList.RequestedCount - reward.Quantity); + QueuedItem = x, + InventoryCount = inventoryManager->GetInventoryItemCount(x.ItemId) + + (venturesInProgress.TryGetValue(x.ItemId, out int inProgress) + ? inProgress + : 0), + }) + .Where(x => x.InventoryCount <= x.RequestedCount) + .ToList() + .AsReadOnly(); + + // collect items with the least current inventory first + if (list.Priority == Configuration.ListPriority.Balanced) + itemsOnList = itemsOnList.OrderBy(x => x.InventoryCount).ToList().AsReadOnly(); + } + + _pluginLog.Debug($"Found {itemsOnList.Count} to-do items on current list"); + if (itemsOnList.Count == 0) + continue; + + foreach (var itemOnList in itemsOnList) + { + _pluginLog.Debug($"Checking venture info for itemId {itemOnList.ItemId}"); + + var (venture, reward) = _ventureResolver.ResolveVenture(ch, retainer, itemOnList.ItemId); + if (venture == null) + { + venture = _gameCache.Ventures.FirstOrDefault(x => x.ItemId == itemOnList.ItemId); + _pluginLog.Debug( + $"Retainer doesn't know how to gather itemId {itemOnList.ItemId} ({venture?.Name})"); + } + else if (reward == null) + { + _pluginLog.Debug($"Retainer can't complete venture '{venture.Name}'"); + } + else + { + _chatGui.Print( + new SeString(new UIForegroundPayload(579)) + .Append(SeIconChar.Collectible.ToIconString()) + .Append(new UIForegroundPayload(0)) + .Append($" Sending retainer ") + .Append(new UIForegroundPayload(1)) + .Append(retainerName) + .Append(new UIForegroundPayload(0)) + .Append(" to collect ") + .Append(new UIForegroundPayload(1)) + .Append($"{reward.Quantity}x ") + .Append(new ItemPayload(venture.ItemId)) + .Append(venture.Name) + .Append(RawPayload.LinkTerminator) + .Append(new UIForegroundPayload(0)) + .Append(" for ") + .Append(new UIForegroundPayload(1)) + .Append($"{list.Name} {list.GetIcon()}") + .Append(new UIForegroundPayload(0)) + .Append(".")); + _pluginLog.Information( + $"Setting AR to use venture {venture.RowId}, which should retrieve {reward.Quantity}x {venture.Name}"); + + if (!dryRun) + { + retainer.HasVenture = true; + retainer.LastVenture = venture.RowId; + + if (list.Type == Configuration.ListType.CollectOneTime) + { + itemOnList.RequestedCount = + Math.Max(0, itemOnList.RequestedCount - reward.Quantity); + } + + _pluginInterface.SavePluginConfig(_configuration); } - _pluginInterface.SavePluginConfig(_configuration); + return venture.RowId; } - - return venture.RowId; } } } diff --git a/ARControl/Configuration.cs b/ARControl/Configuration.cs index 39a5dd4..264fd04 100644 --- a/ARControl/Configuration.cs +++ b/ARControl/Configuration.cs @@ -12,6 +12,7 @@ internal sealed class Configuration : IPluginConfiguration public List Characters { get; set; } = new(); public List ItemLists { get; set; } = new(); public List CharacterGroups { get; set; } = new(); + public MiscConfiguration Misc { get; set; } = new(); public ConfigWindowUiOptions ConfigUiOptions { get; set; } = new(); public sealed class ItemList @@ -68,6 +69,7 @@ internal sealed class Configuration : IPluginConfiguration public required string CharacterName { get; set; } public required string WorldName { get; set; } + public uint Ventures { get; set; } public CharacterType Type { get; set; } = CharacterType.NotManaged; public Guid CharacterGroupId { get; set; } public List ItemListIds { get; set; } = new(); @@ -107,6 +109,11 @@ internal sealed class Configuration : IPluginConfiguration public int Perception { get; set; } } + public sealed class MiscConfiguration + { + public int VenturesToKeep { get; set; } + } + public sealed class ConfigWindowUiOptions { public bool ShowVentureListContents { get; set; } = true; diff --git a/ARControl/Windows/ConfigWindow.cs b/ARControl/Windows/ConfigWindow.cs index b46ca29..f18896c 100644 --- a/ARControl/Windows/ConfigWindow.cs +++ b/ARControl/Windows/ConfigWindow.cs @@ -85,7 +85,7 @@ internal sealed class ConfigWindow : Window DrawCharacterGroups(); DrawCharacters(); DrawGatheredItemsToCheck(); - DrawUiTab(); + DrawMiscTab(); ImGui.EndTabBar(); } } @@ -1020,10 +1020,30 @@ internal sealed class ConfigWindow : Window ImGui.PopID(); } - private void DrawUiTab() + private void DrawMiscTab() { - if (ImGui.BeginTabItem("UI")) + if (ImGui.BeginTabItem("Misc")) { + ImGui.Text("Venture Settings"); + ImGui.Spacing(); + + ImGui.SetNextItemWidth(130); + int venturesToKeep = _configuration.Misc.VenturesToKeep; + if (ImGui.InputInt("Minimum Ventures needed to assign retainers", ref venturesToKeep)) + { + _configuration.Misc.VenturesToKeep = Math.Max(0, Math.Min(65000, venturesToKeep)); + Save(); + } + + ImGui.SameLine(); + ImGuiComponents.HelpMarker($"If you have less than {venturesToKeep} ventures, retainers will only be sent out for Quick Ventures (instead of picking the next item from the Venture List)."); + + ImGui.Spacing(); + ImGui.Separator(); + ImGui.Spacing(); + + ImGui.Text("User Interface Settings"); + bool showContents = _configuration.ConfigUiOptions.ShowVentureListContents; if (ImGui.Checkbox("Show Venture List preview in Groups/Retainer tabs", ref showContents)) {