forked from liza/ARControl
Merge branch 'venture-2.x'
This commit is contained in:
commit
c7b5a7bee2
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "LLib"]
|
||||||
|
path = LLib
|
||||||
|
url = git@git.carvel.li:liza/LLib.git
|
@ -2,6 +2,8 @@
|
|||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ARControl", "ARControl\ARControl.csproj", "{B33BF820-56C2-45A1-AEEC-3DCF526DBF42}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ARControl", "ARControl\ARControl.csproj", "{B33BF820-56C2-45A1-AEEC-3DCF526DBF42}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LLib", "LLib\LLib.csproj", "{C00249D7-E550-4A3F-937B-D938D1D46B8A}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -12,5 +14,9 @@ Global
|
|||||||
{B33BF820-56C2-45A1-AEEC-3DCF526DBF42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B33BF820-56C2-45A1-AEEC-3DCF526DBF42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B33BF820-56C2-45A1-AEEC-3DCF526DBF42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B33BF820-56C2-45A1-AEEC-3DCF526DBF42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B33BF820-56C2-45A1-AEEC-3DCF526DBF42}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B33BF820-56C2-45A1-AEEC-3DCF526DBF42}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C00249D7-E550-4A3F-937B-D938D1D46B8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C00249D7-E550-4A3F-937B-D938D1D46B8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C00249D7-E550-4A3F-937B-D938D1D46B8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C00249D7-E550-4A3F-937B-D938D1D46B8A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<Version>1.0</Version>
|
<Version>2.0</Version>
|
||||||
<LangVersion>11.0</LangVersion>
|
<LangVersion>11.0</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||||
@ -16,13 +16,17 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
<DalamudLibPath>$(appdata)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
||||||
<AutoRetainerLibPath>$(appdata)\XIVLauncher\installedPlugins\AutoRetainer\4.2.0.6\</AutoRetainerLibPath>
|
<AutoRetainerLibPath>$(appdata)\XIVLauncher\installedPlugins\AutoRetainer\4.2.1.0\</AutoRetainerLibPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))'">
|
<PropertyGroup Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))'">
|
||||||
<DalamudLibPath>$(DALAMUD_HOME)/</DalamudLibPath>
|
<DalamudLibPath>$(DALAMUD_HOME)/</DalamudLibPath>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\LLib\LLib.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DalamudPackager" Version="2.1.12"/>
|
<PackageReference Include="DalamudPackager" Version="2.1.12"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -48,6 +52,10 @@
|
|||||||
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="FFXIVClientStructs">
|
||||||
|
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="AutoRetainerAPI">
|
<Reference Include="AutoRetainerAPI">
|
||||||
<HintPath>$(AutoRetainerLibPath)AutoRetainerAPI.dll</HintPath>
|
<HintPath>$(AutoRetainerLibPath)AutoRetainerAPI.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@ -57,7 +65,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Target Name="RenameLatestZip" AfterTargets="PackagePlugin">
|
<Target Name="RenameLatestZip" AfterTargets="PackagePlugin">
|
||||||
<Exec Command="rename $(OutDir)$(AssemblyName)\latest.zip $(AssemblyName)-$(Version).zip"/>
|
<Exec Command="rename $(OutDir)$(AssemblyName)\latest.zip $(AssemblyName)-$(Version).zip"/>
|
||||||
</Target>
|
</Target>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace ARControl;
|
namespace ARControl;
|
||||||
|
|
||||||
@ -24,7 +25,7 @@ partial class AutoRetainerControlPlugin
|
|||||||
LocalContentId = registeredCharacterId,
|
LocalContentId = registeredCharacterId,
|
||||||
CharacterName = offlineCharacterData.Name,
|
CharacterName = offlineCharacterData.Name,
|
||||||
WorldName = offlineCharacterData.World,
|
WorldName = offlineCharacterData.World,
|
||||||
Managed = false,
|
Type = Configuration.CharacterType.NotManaged,
|
||||||
};
|
};
|
||||||
|
|
||||||
save = true;
|
save = true;
|
||||||
@ -37,6 +38,7 @@ partial class AutoRetainerControlPlugin
|
|||||||
save = true;
|
save = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<string> seenRetainers = new();
|
||||||
foreach (var retainerData in offlineCharacterData.RetainerData)
|
foreach (var retainerData in offlineCharacterData.RetainerData)
|
||||||
{
|
{
|
||||||
var retainer = character.Retainers.SingleOrDefault(x => x.Name == retainerData.Name);
|
var retainer = character.Retainers.SingleOrDefault(x => x.Name == retainerData.Name);
|
||||||
@ -52,6 +54,8 @@ partial class AutoRetainerControlPlugin
|
|||||||
character.Retainers.Add(retainer);
|
character.Retainers.Add(retainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seenRetainers.Add(retainer.Name);
|
||||||
|
|
||||||
if (retainer.DisplayOrder != retainerData.DisplayOrder)
|
if (retainer.DisplayOrder != retainerData.DisplayOrder)
|
||||||
{
|
{
|
||||||
retainer.DisplayOrder = retainerData.DisplayOrder;
|
retainer.DisplayOrder = retainerData.DisplayOrder;
|
||||||
@ -70,6 +74,12 @@ partial class AutoRetainerControlPlugin
|
|||||||
save = true;
|
save = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (retainer.HasVenture != retainerData.HasVenture)
|
||||||
|
{
|
||||||
|
retainer.HasVenture = retainerData.HasVenture;
|
||||||
|
save = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (retainer.LastVenture != retainerData.VentureID)
|
if (retainer.LastVenture != retainerData.VentureID)
|
||||||
{
|
{
|
||||||
retainer.LastVenture = retainerData.VentureID;
|
retainer.LastVenture = retainerData.VentureID;
|
||||||
@ -96,6 +106,9 @@ partial class AutoRetainerControlPlugin
|
|||||||
save = true;
|
save = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (character.Retainers.RemoveAll(x => !seenRetainers.Contains(x.Name)) > 0)
|
||||||
|
save = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (save)
|
if (save)
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using ARControl.GameData;
|
using ARControl.GameData;
|
||||||
using ARControl.Windows;
|
using ARControl.Windows;
|
||||||
using AutoRetainerAPI;
|
using AutoRetainerAPI;
|
||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
|
using Dalamud.Game.Text;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
|
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Components;
|
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using ECommons;
|
using ECommons;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
namespace ARControl;
|
namespace ARControl;
|
||||||
@ -18,6 +22,7 @@ namespace ARControl;
|
|||||||
[SuppressMessage("ReSharper", "UnusedType.Global")]
|
[SuppressMessage("ReSharper", "UnusedType.Global")]
|
||||||
public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin
|
public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin
|
||||||
{
|
{
|
||||||
|
private const int QuickVentureId = 395;
|
||||||
private readonly WindowSystem _windowSystem = new(nameof(AutoRetainerControlPlugin));
|
private readonly WindowSystem _windowSystem = new(nameof(AutoRetainerControlPlugin));
|
||||||
|
|
||||||
private readonly DalamudPluginInterface _pluginInterface;
|
private readonly DalamudPluginInterface _pluginInterface;
|
||||||
@ -28,12 +33,14 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin
|
|||||||
|
|
||||||
private readonly Configuration _configuration;
|
private readonly Configuration _configuration;
|
||||||
private readonly GameCache _gameCache;
|
private readonly GameCache _gameCache;
|
||||||
|
private readonly IconCache _iconCache;
|
||||||
private readonly VentureResolver _ventureResolver;
|
private readonly VentureResolver _ventureResolver;
|
||||||
private readonly ConfigWindow _configWindow;
|
private readonly ConfigWindow _configWindow;
|
||||||
private readonly AutoRetainerApi _autoRetainerApi;
|
private readonly AutoRetainerApi _autoRetainerApi;
|
||||||
|
|
||||||
public AutoRetainerControlPlugin(DalamudPluginInterface pluginInterface, IDataManager dataManager,
|
public AutoRetainerControlPlugin(DalamudPluginInterface pluginInterface, IDataManager dataManager,
|
||||||
IClientState clientState, IChatGui chatGui, ICommandManager commandManager, IPluginLog pluginLog)
|
IClientState clientState, IChatGui chatGui, ICommandManager commandManager, ITextureProvider textureProvider,
|
||||||
|
IPluginLog pluginLog)
|
||||||
{
|
{
|
||||||
_pluginInterface = pluginInterface;
|
_pluginInterface = pluginInterface;
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
@ -41,11 +48,15 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin
|
|||||||
_commandManager = commandManager;
|
_commandManager = commandManager;
|
||||||
_pluginLog = pluginLog;
|
_pluginLog = pluginLog;
|
||||||
|
|
||||||
_configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration();
|
_configuration = (Configuration?)_pluginInterface.GetPluginConfig() ?? new Configuration { Version = 2 };
|
||||||
|
|
||||||
_gameCache = new GameCache(dataManager);
|
_gameCache = new GameCache(dataManager);
|
||||||
|
_iconCache = new IconCache(textureProvider);
|
||||||
_ventureResolver = new VentureResolver(_gameCache, _pluginLog);
|
_ventureResolver = new VentureResolver(_gameCache, _pluginLog);
|
||||||
_configWindow = new ConfigWindow(_pluginInterface, _configuration, _gameCache, _clientState, _commandManager, _pluginLog);
|
_configWindow =
|
||||||
|
new ConfigWindow(_pluginInterface, _configuration, _gameCache, _clientState, _commandManager, _iconCache,
|
||||||
|
_pluginLog)
|
||||||
|
{ IsOpen = true };
|
||||||
_windowSystem.AddWindow(_configWindow);
|
_windowSystem.AddWindow(_configWindow);
|
||||||
|
|
||||||
ECommonsMain.Init(_pluginInterface, this);
|
ECommonsMain.Init(_pluginInterface, this);
|
||||||
@ -66,77 +77,237 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void SendRetainerToVenture(string retainerName)
|
private void SendRetainerToVenture(string retainerName)
|
||||||
|
{
|
||||||
|
var venture = GetNextVenture(retainerName, false);
|
||||||
|
if (venture == QuickVentureId)
|
||||||
|
_autoRetainerApi.SetVenture(0);
|
||||||
|
else if (venture.HasValue)
|
||||||
|
_autoRetainerApi.SetVenture(venture.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe uint? GetNextVenture(string retainerName, bool dryRun)
|
||||||
{
|
{
|
||||||
var ch = _configuration.Characters.SingleOrDefault(x => x.LocalContentId == _clientState.LocalContentId);
|
var ch = _configuration.Characters.SingleOrDefault(x => x.LocalContentId == _clientState.LocalContentId);
|
||||||
if (ch == null)
|
if (ch == null)
|
||||||
{
|
{
|
||||||
_pluginLog.Information("No character information found");
|
_pluginLog.Information("No character information found");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
else if (!ch.Managed)
|
|
||||||
|
if (ch.Type == Configuration.CharacterType.NotManaged)
|
||||||
{
|
{
|
||||||
_pluginLog.Information("Character is not managed");
|
_pluginLog.Information("Character is not managed");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var retainer = ch.Retainers.SingleOrDefault(x => x.Name == retainerName);
|
var retainer = ch.Retainers.SingleOrDefault(x => x.Name == retainerName);
|
||||||
if (retainer == null)
|
if (retainer == null)
|
||||||
{
|
{
|
||||||
_pluginLog.Information("No retainer information found");
|
_pluginLog.Information("No retainer information found");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
else if (!retainer.Managed)
|
|
||||||
|
if (!retainer.Managed)
|
||||||
{
|
{
|
||||||
_pluginLog.Information("Retainer is not managed");
|
_pluginLog.Information("Retainer is not managed");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pluginLog.Information("Checking tasks...");
|
||||||
|
Sync();
|
||||||
|
var venturesInProgress = CalculateVenturesInProgress(ch);
|
||||||
|
foreach (var inpr in venturesInProgress)
|
||||||
|
{
|
||||||
|
_pluginLog.Information($"In Progress: {inpr.Key} → {inpr.Value}");
|
||||||
|
}
|
||||||
|
|
||||||
|
IReadOnlyList<Guid> itemListIds;
|
||||||
|
if (ch.Type == Configuration.CharacterType.Standalone)
|
||||||
|
itemListIds = ch.ItemListIds;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var group = _configuration.CharacterGroups.SingleOrDefault(x => x.Id == ch.CharacterGroupId);
|
||||||
|
if (group == null)
|
||||||
|
{
|
||||||
|
_pluginLog.Error($"Unable to resolve character group {ch.CharacterGroupId}.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<Configuration.ItemList>()
|
||||||
|
.ToList();
|
||||||
|
InventoryManager* inventoryManager = InventoryManager.Instance();
|
||||||
|
foreach (var list in itemLists)
|
||||||
|
{
|
||||||
|
_pluginLog.Information($"Checking ventures in list '{list.Name}'");
|
||||||
|
IReadOnlyList<StockedItem> 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();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_pluginLog.Information("Checking tasks...");
|
itemsOnList = list.Items
|
||||||
Sync();
|
.Select(x => new StockedItem
|
||||||
foreach (var queuedItem in _configuration.QueuedItems.Where(x => x.RemainingQuantity > 0))
|
|
||||||
{
|
{
|
||||||
_pluginLog.Information($"Checking venture info for itemId {queuedItem.ItemId}");
|
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 (venture, reward) = _ventureResolver.ResolveVenture(ch, retainer, queuedItem);
|
// collect items with the least current inventory first
|
||||||
if (reward == null)
|
if (list.Priority == Configuration.ListPriority.Balanced)
|
||||||
|
itemsOnList = itemsOnList.OrderBy(x => x.InventoryCount).ToList().AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
_pluginLog.Information($"Found {itemsOnList.Count} items on current list");
|
||||||
|
if (itemsOnList.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var itemOnList in itemsOnList)
|
||||||
{
|
{
|
||||||
_pluginLog.Information("Retainer can't complete venture");
|
_pluginLog.Information($"Checking venture info for itemId {itemOnList.ItemId}");
|
||||||
|
|
||||||
|
var (venture, reward) = _ventureResolver.ResolveVenture(ch, retainer, itemOnList.ItemId);
|
||||||
|
if (venture == null || reward == null)
|
||||||
|
{
|
||||||
|
_pluginLog.Information($"Retainer can't complete venture '{venture?.Name}'");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_chatGui.Print(
|
_chatGui.Print(
|
||||||
$"[ARC] Sending retainer {retainerName} to collect {reward.Quantity}x {venture!.Name}.");
|
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(
|
_pluginLog.Information(
|
||||||
$"Setting AR to use venture {venture.RowId}, which should retrieve {reward.Quantity}x {venture.Name}");
|
$"Setting AR to use venture {venture.RowId}, which should retrieve {reward.Quantity}x {venture.Name}");
|
||||||
_autoRetainerApi.SetVenture(venture.RowId);
|
|
||||||
|
|
||||||
|
if (!dryRun)
|
||||||
|
{
|
||||||
|
retainer.HasVenture = true;
|
||||||
retainer.LastVenture = venture.RowId;
|
retainer.LastVenture = venture.RowId;
|
||||||
queuedItem.RemainingQuantity =
|
|
||||||
Math.Max(0, queuedItem.RemainingQuantity - reward.Quantity);
|
if (list.Type == Configuration.ListType.CollectOneTime)
|
||||||
|
{
|
||||||
|
itemOnList.RequestedCount =
|
||||||
|
Math.Max(0, itemOnList.RequestedCount - reward.Quantity);
|
||||||
|
}
|
||||||
|
|
||||||
_pluginInterface.SavePluginConfig(_configuration);
|
_pluginInterface.SavePluginConfig(_configuration);
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
return venture.RowId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback: managed but no venture found
|
// fallback: managed but no venture found
|
||||||
if (retainer.LastVenture != 395)
|
if (retainer.LastVenture != QuickVentureId)
|
||||||
{
|
{
|
||||||
_chatGui.Print($"[ARC] No tasks left for retainer {retainerName}, sending to Quick Venture.");
|
_chatGui.Print(
|
||||||
|
new SeString(new UIForegroundPayload(579))
|
||||||
|
.Append(SeIconChar.Collectible.ToIconString())
|
||||||
|
.Append(new UIForegroundPayload(0))
|
||||||
|
.Append($" No tasks left for retainer ")
|
||||||
|
.Append(new UIForegroundPayload(1))
|
||||||
|
.Append(retainerName)
|
||||||
|
.Append(new UIForegroundPayload(0))
|
||||||
|
.Append(", sending to ")
|
||||||
|
.Append(new UIForegroundPayload(1))
|
||||||
|
.Append("Quick Venture")
|
||||||
|
.Append(new UIForegroundPayload(0))
|
||||||
|
.Append("."));
|
||||||
_pluginLog.Information($"No tasks left (previous venture = {retainer.LastVenture}), using QC");
|
_pluginLog.Information($"No tasks left (previous venture = {retainer.LastVenture}), using QC");
|
||||||
_autoRetainerApi.SetVenture(395);
|
|
||||||
|
|
||||||
retainer.LastVenture = 395;
|
if (!dryRun)
|
||||||
|
{
|
||||||
|
retainer.HasVenture = true;
|
||||||
|
retainer.LastVenture = QuickVentureId;
|
||||||
_pluginInterface.SavePluginConfig(_configuration);
|
_pluginInterface.SavePluginConfig(_configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return QuickVentureId;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_pluginLog.Information("Not changing venture plan, already 395");
|
{
|
||||||
|
_pluginLog.Information("Not changing venture, already a quick venture");
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <remarks>
|
||||||
|
/// This treats the retainer who is currently doing the venture as 'in-progress', since I believe the
|
||||||
|
/// relevant event is fired BEFORE the venture rewards are collected.
|
||||||
|
/// </remarks>
|
||||||
|
private Dictionary<uint, int> CalculateVenturesInProgress(Configuration.CharacterConfiguration character)
|
||||||
|
{
|
||||||
|
Dictionary<uint, int> inProgress = new Dictionary<uint, int>();
|
||||||
|
foreach (var retainer in character.Retainers)
|
||||||
|
{
|
||||||
|
if (retainer.Managed && retainer.HasVenture && retainer.LastVenture != 0)
|
||||||
|
{
|
||||||
|
uint ventureId = retainer.LastVenture;
|
||||||
|
if (ventureId == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var ventureForId = _gameCache.Ventures.SingleOrDefault(x => x.RowId == ventureId);
|
||||||
|
if (ventureForId == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint itemId = ventureForId.ItemId;
|
||||||
|
var (venture, reward) = _ventureResolver.ResolveVenture(character, retainer, itemId);
|
||||||
|
if (venture == null || reward == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (inProgress.TryGetValue(itemId, out int existingQuantity))
|
||||||
|
inProgress[itemId] = reward.Quantity + existingQuantity;
|
||||||
|
else
|
||||||
|
inProgress[itemId] = reward.Quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return inProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RetainerTaskButtonDraw(ulong characterId, string retainerName)
|
private void RetainerTaskButtonDraw(ulong characterId, string retainerName)
|
||||||
{
|
{
|
||||||
Configuration.CharacterConfiguration? characterConfiguration =
|
Configuration.CharacterConfiguration? characterConfiguration =
|
||||||
_configuration.Characters.FirstOrDefault(x => x.LocalContentId == characterId);
|
_configuration.Characters.FirstOrDefault(x => x.LocalContentId == characterId);
|
||||||
if (characterConfiguration is not { Managed: true })
|
if (characterConfiguration is not { Type: not Configuration.CharacterType.NotManaged })
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Configuration.RetainerConfiguration? retainer =
|
Configuration.RetainerConfiguration? retainer =
|
||||||
@ -145,7 +316,19 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
ImGuiComponents.IconButton(FontAwesomeIcon.Book);
|
ImGui.Text(SeIconChar.Collectible.ToIconString());
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
string text = "This retainer is managed by ARC.";
|
||||||
|
|
||||||
|
if (characterConfiguration.Type == Configuration.CharacterType.PartOfCharacterGroup)
|
||||||
|
{
|
||||||
|
var group = _configuration.CharacterGroups.Single(x => x.Id == characterConfiguration.CharacterGroupId);
|
||||||
|
text += $"\n\nCharacter Group: {group.Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SetTooltip(text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TerritoryChanged(ushort e) => Sync();
|
private void TerritoryChanged(ushort e) => Sync();
|
||||||
@ -154,6 +337,25 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin
|
|||||||
{
|
{
|
||||||
if (arguments == "sync")
|
if (arguments == "sync")
|
||||||
Sync();
|
Sync();
|
||||||
|
else if (arguments == "d")
|
||||||
|
{
|
||||||
|
var ch = _configuration.Characters.SingleOrDefault(x => x.LocalContentId == _clientState.LocalContentId);
|
||||||
|
if (ch == null || ch.Type == Configuration.CharacterType.NotManaged || ch.Retainers.Count == 0)
|
||||||
|
{
|
||||||
|
_chatGui.PrintError("No character to debug.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string retainerName = ch.Retainers.OrderBy(x => x.DisplayOrder).First().Name;
|
||||||
|
var venture = GetNextVenture(retainerName, true);
|
||||||
|
if (venture == QuickVentureId)
|
||||||
|
_chatGui.Print($"Next venture for {retainerName} is Quick Venture.");
|
||||||
|
else if (venture.HasValue)
|
||||||
|
_chatGui.Print(
|
||||||
|
$"Next venture for {retainerName} is {_gameCache.Ventures.First(x => x.RowId == venture.Value).Name}.");
|
||||||
|
else
|
||||||
|
_chatGui.Print($"Next venture for {retainerName} is (none).");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_configWindow.Toggle();
|
_configWindow.Toggle();
|
||||||
}
|
}
|
||||||
@ -167,7 +369,21 @@ public sealed partial class AutoRetainerControlPlugin : IDalamudPlugin
|
|||||||
_pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
|
_pluginInterface.UiBuilder.OpenConfigUi -= _configWindow.Toggle;
|
||||||
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
_pluginInterface.UiBuilder.Draw -= _windowSystem.Draw;
|
||||||
|
|
||||||
|
_iconCache.Dispose();
|
||||||
_autoRetainerApi.Dispose();
|
_autoRetainerApi.Dispose();
|
||||||
ECommonsMain.Dispose();
|
ECommonsMain.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class StockedItem
|
||||||
|
{
|
||||||
|
public required Configuration.QueuedItem QueuedItem { get; set; }
|
||||||
|
public required int InventoryCount { get; set; }
|
||||||
|
public uint ItemId => QueuedItem.ItemId;
|
||||||
|
|
||||||
|
public int RequestedCount
|
||||||
|
{
|
||||||
|
get => QueuedItem.RemainingQuantity;
|
||||||
|
set => QueuedItem.RemainingQuantity = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,49 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Dalamud.Configuration;
|
using Dalamud.Configuration;
|
||||||
|
using Dalamud.Game.Text;
|
||||||
|
|
||||||
namespace ARControl;
|
namespace ARControl;
|
||||||
|
|
||||||
internal sealed class Configuration : IPluginConfiguration
|
internal sealed class Configuration : IPluginConfiguration
|
||||||
{
|
{
|
||||||
public int Version { get; set; } = 1;
|
public int Version { get; set; }
|
||||||
|
|
||||||
public List<QueuedItem> QueuedItems { get; set; } = new();
|
|
||||||
public List<CharacterConfiguration> Characters { get; set; } = new();
|
public List<CharacterConfiguration> Characters { get; set; } = new();
|
||||||
|
public List<ItemList> ItemLists { get; set; } = new();
|
||||||
|
public List<CharacterGroup> CharacterGroups { get; set; } = new();
|
||||||
|
|
||||||
|
public sealed class ItemList
|
||||||
|
{
|
||||||
|
public required Guid Id { get; set; }
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public required ListType Type { get; set; } = ListType.CollectOneTime;
|
||||||
|
public required ListPriority Priority { get; set; } = ListPriority.InOrder;
|
||||||
|
public List<QueuedItem> Items { get; set; } = new();
|
||||||
|
|
||||||
|
public string GetIcon()
|
||||||
|
{
|
||||||
|
return Type switch
|
||||||
|
{
|
||||||
|
ListType.CollectOneTime => SeIconChar.BoxedNumber1.ToIconString(),
|
||||||
|
ListType.KeepStocked when Priority == ListPriority.Balanced => SeIconChar.EurekaLevel.ToIconString(),
|
||||||
|
ListType.KeepStocked => SeIconChar.Circle.ToIconString(),
|
||||||
|
_ => string.Empty
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ListType
|
||||||
|
{
|
||||||
|
CollectOneTime,
|
||||||
|
KeepStocked,
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ListPriority
|
||||||
|
{
|
||||||
|
InOrder,
|
||||||
|
Balanced,
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class QueuedItem
|
public sealed class QueuedItem
|
||||||
{
|
{
|
||||||
@ -16,12 +51,22 @@ internal sealed class Configuration : IPluginConfiguration
|
|||||||
public required int RemainingQuantity { get; set; }
|
public required int RemainingQuantity { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class CharacterGroup
|
||||||
|
{
|
||||||
|
public required Guid Id { get; set; }
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public List<Guid> ItemListIds { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class CharacterConfiguration
|
public sealed class CharacterConfiguration
|
||||||
{
|
{
|
||||||
public required ulong LocalContentId { get; set; }
|
public required ulong LocalContentId { get; set; }
|
||||||
public required string CharacterName { get; set; }
|
public required string CharacterName { get; set; }
|
||||||
public required string WorldName { get; set; }
|
public required string WorldName { get; set; }
|
||||||
public required bool Managed { get; set; }
|
|
||||||
|
public CharacterType Type { get; set; } = CharacterType.NotManaged;
|
||||||
|
public Guid CharacterGroupId { get; set; }
|
||||||
|
public List<Guid> ItemListIds { get; set; } = new();
|
||||||
|
|
||||||
public List<RetainerConfiguration> Retainers { get; set; } = new();
|
public List<RetainerConfiguration> Retainers { get; set; } = new();
|
||||||
public HashSet<uint> GatheredItems { get; set; } = new();
|
public HashSet<uint> GatheredItems { get; set; } = new();
|
||||||
@ -29,6 +74,21 @@ internal sealed class Configuration : IPluginConfiguration
|
|||||||
public override string ToString() => $"{CharacterName} @ {WorldName}";
|
public override string ToString() => $"{CharacterName} @ {WorldName}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum CharacterType
|
||||||
|
{
|
||||||
|
NotManaged,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The character's item list(s) are manually selected.
|
||||||
|
/// </summary>
|
||||||
|
Standalone,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// All item lists are managed through the character group.
|
||||||
|
/// </summary>
|
||||||
|
PartOfCharacterGroup
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class RetainerConfiguration
|
public sealed class RetainerConfiguration
|
||||||
{
|
{
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
@ -36,6 +96,7 @@ internal sealed class Configuration : IPluginConfiguration
|
|||||||
public int DisplayOrder { get; set; }
|
public int DisplayOrder { get; set; }
|
||||||
public int Level { get; set; }
|
public int Level { get; set; }
|
||||||
public uint Job { get; set; }
|
public uint Job { get; set; }
|
||||||
|
public bool HasVenture { get; set; }
|
||||||
public uint LastVenture { get; set; }
|
public uint LastVenture { get; set; }
|
||||||
public int ItemLevel { get; set; }
|
public int ItemLevel { get; set; }
|
||||||
public int Gathering { get; set; }
|
public int Gathering { get; set; }
|
||||||
|
@ -14,6 +14,7 @@ internal sealed class Venture
|
|||||||
var taskDetails = dataManager.GetExcelSheet<RetainerTaskNormal>()!.GetRow(retainerTask.Task)!;
|
var taskDetails = dataManager.GetExcelSheet<RetainerTaskNormal>()!.GetRow(retainerTask.Task)!;
|
||||||
var taskParameters = retainerTask.RetainerTaskParameter.Value!;
|
var taskParameters = retainerTask.RetainerTaskParameter.Value!;
|
||||||
ItemId = taskDetails.Item.Row;
|
ItemId = taskDetails.Item.Row;
|
||||||
|
IconId = taskDetails.Item.Value!.Icon;
|
||||||
Name = taskDetails.Item.Value!.Name.ToString();
|
Name = taskDetails.Item.Value!.Name.ToString();
|
||||||
Level = retainerTask.RetainerLevel;
|
Level = retainerTask.RetainerLevel;
|
||||||
ItemLevelCombat = retainerTask.RequiredItemLevel;
|
ItemLevelCombat = retainerTask.RequiredItemLevel;
|
||||||
@ -76,6 +77,7 @@ internal sealed class Venture
|
|||||||
}
|
}
|
||||||
|
|
||||||
public uint ItemId { get; }
|
public uint ItemId { get; }
|
||||||
|
public ushort IconId { get; }
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public byte Level { get; }
|
public byte Level { get; }
|
||||||
public ushort ItemLevelCombat { get; }
|
public ushort ItemLevelCombat { get; }
|
||||||
|
@ -15,18 +15,18 @@ internal sealed class VentureResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
public (Venture?, VentureReward?) ResolveVenture(Configuration.CharacterConfiguration character,
|
public (Venture?, VentureReward?) ResolveVenture(Configuration.CharacterConfiguration character,
|
||||||
Configuration.RetainerConfiguration retainer, Configuration.QueuedItem queuedItem)
|
Configuration.RetainerConfiguration retainer, uint itemId)
|
||||||
{
|
{
|
||||||
var venture = _gameCache.Ventures
|
var venture = _gameCache.Ventures
|
||||||
.Where(x => retainer.Level >= x.Level)
|
.Where(x => retainer.Level >= x.Level)
|
||||||
.FirstOrDefault(x => x.ItemId == queuedItem.ItemId && x.MatchesJob(retainer.Job));
|
.FirstOrDefault(x => x.ItemId == itemId && x.MatchesJob(retainer.Job));
|
||||||
if (venture == null)
|
if (venture == null)
|
||||||
{
|
{
|
||||||
_pluginLog.Information($"No applicable venture found for itemId {queuedItem.ItemId}");
|
_pluginLog.Information($"No applicable venture found for itemId {itemId}");
|
||||||
return (null, null);
|
return (null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
var itemToGather = _gameCache.ItemsToGather.FirstOrDefault(x => x.ItemId == queuedItem.ItemId);
|
var itemToGather = _gameCache.ItemsToGather.FirstOrDefault(x => x.ItemId == itemId);
|
||||||
if (itemToGather != null && !character.GatheredItems.Contains(itemToGather.GatheredItemId))
|
if (itemToGather != null && !character.GatheredItems.Contains(itemToGather.GatheredItemId))
|
||||||
{
|
{
|
||||||
_pluginLog.Information($"Character hasn't gathered {venture.Name} yet");
|
_pluginLog.Information($"Character hasn't gathered {venture.Name} yet");
|
||||||
@ -34,7 +34,7 @@ internal sealed class VentureResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
_pluginLog.Information(
|
_pluginLog.Information(
|
||||||
$"Found venture {venture.Name}, row = {venture.RowId}, checking if it is suitable");
|
$"Found venture {venture.Name}, row = {venture.RowId}, checking if we have high enough stats");
|
||||||
VentureReward? reward = null;
|
VentureReward? reward = null;
|
||||||
if (venture.CategoryName is "MIN" or "BTN")
|
if (venture.CategoryName is "MIN" or "BTN")
|
||||||
{
|
{
|
||||||
|
53
ARControl/IconCache.cs
Normal file
53
ARControl/IconCache.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Dalamud.Interface.Internal;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
|
namespace ARControl;
|
||||||
|
|
||||||
|
internal sealed class IconCache : IDisposable
|
||||||
|
{
|
||||||
|
private readonly ITextureProvider _textureProvider;
|
||||||
|
private readonly Dictionary<uint, TextureContainer> _textureWraps = new();
|
||||||
|
|
||||||
|
public IconCache(ITextureProvider textureProvider)
|
||||||
|
{
|
||||||
|
_textureProvider = textureProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDalamudTextureWrap? GetIcon(uint iconId)
|
||||||
|
{
|
||||||
|
if (_textureWraps.TryGetValue(iconId, out TextureContainer? container))
|
||||||
|
return container.Texture;
|
||||||
|
|
||||||
|
var iconTex = _textureProvider.GetIcon(iconId);
|
||||||
|
if (iconTex != null)
|
||||||
|
{
|
||||||
|
if (iconTex.ImGuiHandle != nint.Zero)
|
||||||
|
{
|
||||||
|
_textureWraps[iconId] = new TextureContainer { Texture = iconTex };
|
||||||
|
return iconTex;
|
||||||
|
}
|
||||||
|
|
||||||
|
iconTex.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_textureWraps[iconId] = new TextureContainer { Texture = null };
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
foreach (TextureContainer container in _textureWraps.Values)
|
||||||
|
container.Dispose();
|
||||||
|
|
||||||
|
_textureWraps.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class TextureContainer : IDisposable
|
||||||
|
{
|
||||||
|
public required IDalamudTextureWrap? Texture { get; init; }
|
||||||
|
|
||||||
|
public void Dispose() => Texture?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +1,55 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using ARControl.GameData;
|
using ARControl.GameData;
|
||||||
|
using Dalamud.Game.Text;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Colors;
|
using Dalamud.Interface.Colors;
|
||||||
using Dalamud.Interface.Components;
|
using Dalamud.Interface.Components;
|
||||||
|
using Dalamud.Interface.Internal;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using ECommons;
|
||||||
using ECommons.ImGuiMethods;
|
using ECommons.ImGuiMethods;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
using LLib;
|
||||||
|
|
||||||
namespace ARControl.Windows;
|
namespace ARControl.Windows;
|
||||||
|
|
||||||
internal sealed class ConfigWindow : Window
|
internal sealed class ConfigWindow : Window
|
||||||
{
|
{
|
||||||
private const byte MaxLevel = 90;
|
// TODO This should also allow retainers under max level
|
||||||
|
private const byte MinLevel = 10;
|
||||||
|
|
||||||
private static readonly Vector4 ColorGreen = ImGuiColors.HealerGreen;
|
private static readonly Vector4 ColorGreen = ImGuiColors.HealerGreen;
|
||||||
private static readonly Vector4 ColorRed = ImGuiColors.DalamudRed;
|
private static readonly Vector4 ColorRed = ImGuiColors.DalamudRed;
|
||||||
private static readonly Vector4 ColorGrey = ImGuiColors.DalamudGrey;
|
private static readonly Vector4 ColorGrey = ImGuiColors.DalamudGrey;
|
||||||
|
private static readonly string[] StockingTypeLabels = { "Collect Once", "Keep in Stock" };
|
||||||
|
|
||||||
|
private static readonly string[] PriorityLabels =
|
||||||
|
{ "Collect in order of the list", "Collect item with lowest inventory first" };
|
||||||
|
|
||||||
private readonly DalamudPluginInterface _pluginInterface;
|
private readonly DalamudPluginInterface _pluginInterface;
|
||||||
private readonly Configuration _configuration;
|
private readonly Configuration _configuration;
|
||||||
private readonly GameCache _gameCache;
|
private readonly GameCache _gameCache;
|
||||||
private readonly IClientState _clientState;
|
private readonly IClientState _clientState;
|
||||||
private readonly ICommandManager _commandManager;
|
private readonly ICommandManager _commandManager;
|
||||||
|
private readonly IconCache _iconCache;
|
||||||
private readonly IPluginLog _pluginLog;
|
private readonly IPluginLog _pluginLog;
|
||||||
|
|
||||||
|
private readonly Dictionary<Guid, TemporaryConfig> _currentEditPopups = new();
|
||||||
private string _searchString = string.Empty;
|
private string _searchString = string.Empty;
|
||||||
private Configuration.QueuedItem? _dragDropSource;
|
private TemporaryConfig _newGroup = new() { Name = string.Empty };
|
||||||
private bool _enableDragDrop;
|
|
||||||
|
private TemporaryConfig _newList = new()
|
||||||
|
{
|
||||||
|
Name = string.Empty,
|
||||||
|
ListType = Configuration.ListType.CollectOneTime,
|
||||||
|
ListPriority = Configuration.ListPriority.InOrder
|
||||||
|
};
|
||||||
|
|
||||||
private bool _checkPerCharacter = true;
|
private bool _checkPerCharacter = true;
|
||||||
private bool _onlyShowMissing = true;
|
private bool _onlyShowMissing = true;
|
||||||
|
|
||||||
@ -40,36 +59,226 @@ internal sealed class ConfigWindow : Window
|
|||||||
GameCache gameCache,
|
GameCache gameCache,
|
||||||
IClientState clientState,
|
IClientState clientState,
|
||||||
ICommandManager commandManager,
|
ICommandManager commandManager,
|
||||||
|
IconCache iconCache,
|
||||||
IPluginLog pluginLog)
|
IPluginLog pluginLog)
|
||||||
: base("ARC###ARControlConfig")
|
: base($"ARC {SeIconChar.Collectible.ToIconString()}###ARControlConfig")
|
||||||
{
|
{
|
||||||
_pluginInterface = pluginInterface;
|
_pluginInterface = pluginInterface;
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_gameCache = gameCache;
|
_gameCache = gameCache;
|
||||||
_clientState = clientState;
|
_clientState = clientState;
|
||||||
_commandManager = commandManager;
|
_commandManager = commandManager;
|
||||||
|
_iconCache = iconCache;
|
||||||
_pluginLog = pluginLog;
|
_pluginLog = pluginLog;
|
||||||
|
|
||||||
|
SizeConstraints = new()
|
||||||
|
{
|
||||||
|
MinimumSize = new Vector2(480, 300),
|
||||||
|
MaximumSize = new Vector2(9999, 9999),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
|
LImGui.AddPatreonIcon(_pluginInterface);
|
||||||
|
|
||||||
if (ImGui.BeginTabBar("ARConfigTabs"))
|
if (ImGui.BeginTabBar("ARConfigTabs"))
|
||||||
{
|
{
|
||||||
DrawItemQueue();
|
DrawVentureLists();
|
||||||
|
DrawCharacterGroups();
|
||||||
DrawCharacters();
|
DrawCharacters();
|
||||||
DrawGatheredItemsToCheck();
|
DrawGatheredItemsToCheck();
|
||||||
ImGui.EndTabBar();
|
ImGui.EndTabBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void DrawItemQueue()
|
private void DrawVentureLists()
|
||||||
{
|
{
|
||||||
if (ImGui.BeginTabItem("Venture Queue"))
|
if (ImGui.BeginTabItem("Venture Lists"))
|
||||||
{
|
{
|
||||||
if (ImGui.BeginCombo("Add Item...##VentureSelection", ""))
|
Configuration.ItemList? listToDelete = null;
|
||||||
|
foreach (var list in _configuration.ItemLists)
|
||||||
|
{
|
||||||
|
ImGui.PushID($"List{list.Id}");
|
||||||
|
|
||||||
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.Cog))
|
||||||
|
{
|
||||||
|
_currentEditPopups[list.Id] = new TemporaryConfig
|
||||||
|
{
|
||||||
|
Name = list.Name,
|
||||||
|
ListType = list.Type,
|
||||||
|
ListPriority = list.Priority,
|
||||||
|
};
|
||||||
|
ImGui.OpenPopup($"##EditList{list.Id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawVentureListEditorPopup(list, ref listToDelete);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
string label = $"{list.Name} {list.GetIcon()}";
|
||||||
|
|
||||||
|
if (ImGui.CollapsingHeader(label))
|
||||||
|
{
|
||||||
|
ImGui.Indent(30);
|
||||||
|
DrawVentureListItemSelection(list);
|
||||||
|
ImGui.Unindent(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listToDelete != null)
|
||||||
|
{
|
||||||
|
_configuration.ItemLists.Remove(listToDelete);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
DrawNewVentureList();
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawVentureListEditorPopup(Configuration.ItemList list, ref Configuration.ItemList? listToDelete)
|
||||||
|
{
|
||||||
|
var assignedCharacters = _configuration.Characters
|
||||||
|
.Where(x => x.Type == Configuration.CharacterType.Standalone && x.ItemListIds.Contains(list.Id))
|
||||||
|
.OrderBy(x => x.WorldName)
|
||||||
|
.ThenBy(x => x.LocalContentId)
|
||||||
|
.ToList();
|
||||||
|
var assignedGroups = _configuration.CharacterGroups
|
||||||
|
.Where(x => x.ItemListIds.Contains(list.Id))
|
||||||
|
.ToList();
|
||||||
|
if (_currentEditPopups.TryGetValue(list.Id, out TemporaryConfig? temporaryConfig) &&
|
||||||
|
ImGui.BeginPopup($"##EditList{list.Id}"))
|
||||||
|
{
|
||||||
|
var (save, canSave) = DrawVentureListEditor(temporaryConfig, list);
|
||||||
|
ImGui.BeginDisabled(!canSave || (list.Name == temporaryConfig.Name &&
|
||||||
|
list.Type == temporaryConfig.ListType &&
|
||||||
|
list.Priority == temporaryConfig.ListPriority));
|
||||||
|
save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save");
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
if (save && canSave)
|
||||||
|
{
|
||||||
|
list.Name = temporaryConfig.Name;
|
||||||
|
list.Type = temporaryConfig.ListType;
|
||||||
|
|
||||||
|
if (list.Type == Configuration.ListType.CollectOneTime)
|
||||||
|
list.Priority = Configuration.ListPriority.InOrder;
|
||||||
|
else
|
||||||
|
list.Priority = temporaryConfig.ListPriority;
|
||||||
|
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.BeginDisabled(assignedCharacters.Count > 0 || assignedGroups.Count > 0);
|
||||||
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Times, "Delete"))
|
||||||
|
{
|
||||||
|
listToDelete = list;
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
if ((assignedCharacters.Count > 0 || assignedGroups.Count > 0) &&
|
||||||
|
ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
|
{
|
||||||
|
ImGui.BeginTooltip();
|
||||||
|
ImGui.Text(
|
||||||
|
$"Remove this list from the {assignedCharacters.Count} character(s) and {assignedGroups.Count} group(s) using it before deleting it.");
|
||||||
|
foreach (var character in assignedCharacters)
|
||||||
|
ImGui.BulletText($"{character.CharacterName} @ {character.WorldName}");
|
||||||
|
foreach (var group in assignedGroups)
|
||||||
|
ImGui.BulletText($"{group.Name}");
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawNewVentureList()
|
||||||
|
{
|
||||||
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Plus, "Add Venture List"))
|
||||||
|
ImGui.OpenPopup("##AddList");
|
||||||
|
|
||||||
|
if (ImGui.BeginPopup("##AddList"))
|
||||||
|
{
|
||||||
|
(bool save, bool canSave) = DrawVentureListEditor(_newList, null);
|
||||||
|
|
||||||
|
ImGui.BeginDisabled(!canSave);
|
||||||
|
save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save");
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
if (save && canSave)
|
||||||
|
{
|
||||||
|
_configuration.ItemLists.Add(new Configuration.ItemList
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = _newList.Name,
|
||||||
|
Type = _newList.ListType,
|
||||||
|
Priority = _newList.ListPriority,
|
||||||
|
});
|
||||||
|
|
||||||
|
_newList = new()
|
||||||
|
{
|
||||||
|
Name = string.Empty,
|
||||||
|
ListType = Configuration.ListType.CollectOneTime,
|
||||||
|
ListPriority = Configuration.ListPriority.InOrder
|
||||||
|
};
|
||||||
|
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private (bool Save, bool CanSave) DrawVentureListEditor(TemporaryConfig temporaryConfig,
|
||||||
|
Configuration.ItemList? list)
|
||||||
|
{
|
||||||
|
string listName = temporaryConfig.Name;
|
||||||
|
bool save = ImGui.InputTextWithHint("", "List Name...", ref listName, 64,
|
||||||
|
ImGuiInputTextFlags.EnterReturnsTrue);
|
||||||
|
bool canSave = IsValidListName(listName, list);
|
||||||
|
temporaryConfig.Name = listName;
|
||||||
|
|
||||||
|
ImGui.PushID($"Type{list?.Id ?? Guid.Empty}");
|
||||||
|
int type = (int)temporaryConfig.ListType;
|
||||||
|
if (ImGui.Combo("", ref type, StockingTypeLabels, StockingTypeLabels.Length))
|
||||||
|
{
|
||||||
|
temporaryConfig.ListType = (Configuration.ListType)type;
|
||||||
|
if (temporaryConfig.ListType == Configuration.ListType.CollectOneTime)
|
||||||
|
temporaryConfig.ListPriority = Configuration.ListPriority.InOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
|
||||||
|
if (temporaryConfig.ListType == Configuration.ListType.KeepStocked)
|
||||||
|
{
|
||||||
|
ImGui.PushID($"Priority{list?.Id ?? Guid.Empty}");
|
||||||
|
int priority = (int)temporaryConfig.ListPriority;
|
||||||
|
if (ImGui.Combo("", ref priority, PriorityLabels, PriorityLabels.Length))
|
||||||
|
temporaryConfig.ListPriority = (Configuration.ListPriority)priority;
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (save, canSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawVentureListItemSelection(Configuration.ItemList list)
|
||||||
{
|
{
|
||||||
ImGuiEx.SetNextItemFullWidth();
|
ImGuiEx.SetNextItemFullWidth();
|
||||||
ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256);
|
if (ImGui.BeginCombo($"##VentureSelection{list.Id}", "Add Venture...", ImGuiComboFlags.HeightLarge))
|
||||||
|
{
|
||||||
|
ImGuiEx.SetNextItemFullWidth();
|
||||||
|
ImGui.InputTextWithHint("", "Filter...", ref _searchString, 256, ImGuiInputTextFlags.AutoSelectAll);
|
||||||
|
|
||||||
foreach (var ventures in _gameCache.Ventures
|
foreach (var ventures in _gameCache.Ventures
|
||||||
.Where(x => x.Name.ToLower().Contains(_searchString.ToLower()))
|
.Where(x => x.Name.ToLower().Contains(_searchString.ToLower()))
|
||||||
@ -79,15 +288,22 @@ internal sealed class ConfigWindow : Window
|
|||||||
.GroupBy(x => x.ItemId))
|
.GroupBy(x => x.ItemId))
|
||||||
{
|
{
|
||||||
var venture = ventures.First();
|
var venture = ventures.First();
|
||||||
|
IDalamudTextureWrap? icon = _iconCache.GetIcon(venture.IconId);
|
||||||
|
if (icon != null)
|
||||||
|
{
|
||||||
|
ImGui.Image(icon.ImGuiHandle, new Vector2(23, 23));
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
|
||||||
|
}
|
||||||
|
|
||||||
if (ImGui.Selectable(
|
if (ImGui.Selectable(
|
||||||
$"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})##SelectVenture{venture.RowId}"))
|
$"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})##SelectVenture{venture.RowId}"))
|
||||||
{
|
{
|
||||||
_configuration.QueuedItems.Add(new Configuration.QueuedItem
|
list.Items.Add(new Configuration.QueuedItem
|
||||||
{
|
{
|
||||||
ItemId = venture.ItemId,
|
ItemId = venture.ItemId,
|
||||||
RemainingQuantity = 0,
|
RemainingQuantity = 0,
|
||||||
});
|
});
|
||||||
_searchString = string.Empty;
|
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,22 +311,26 @@ internal sealed class ConfigWindow : Window
|
|||||||
ImGui.EndCombo();
|
ImGui.EndCombo();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Spacing();
|
||||||
|
|
||||||
ImGui.Indent(30);
|
|
||||||
|
|
||||||
Configuration.QueuedItem? itemToRemove = null;
|
Configuration.QueuedItem? itemToRemove = null;
|
||||||
Configuration.QueuedItem? itemToAdd = null;
|
Configuration.QueuedItem? itemToAdd = null;
|
||||||
int indexToAdd = 0;
|
int indexToAdd = 0;
|
||||||
for (int i = 0; i < _configuration.QueuedItems.Count; ++i)
|
float windowX = ImGui.GetContentRegionAvail().X;
|
||||||
|
for (int i = 0; i < list.Items.Count; ++i)
|
||||||
{
|
{
|
||||||
var item = _configuration.QueuedItems[i];
|
var item = list.Items[i];
|
||||||
ImGui.PushID($"QueueItem{i}");
|
ImGui.PushID($"QueueItem{i}");
|
||||||
var ventures = _gameCache.Ventures.Where(x => x.ItemId == item.ItemId).ToList();
|
var ventures = _gameCache.Ventures.Where(x => x.ItemId == item.ItemId).ToList();
|
||||||
var venture = ventures.First();
|
var venture = ventures.First();
|
||||||
|
|
||||||
if (!_enableDragDrop)
|
IDalamudTextureWrap? icon = _iconCache.GetIcon(venture.IconId);
|
||||||
|
if (icon != null)
|
||||||
{
|
{
|
||||||
|
ImGui.Image(icon.ImGuiHandle, new Vector2(23, 23));
|
||||||
|
ImGui.SameLine(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.SetNextItemWidth(130);
|
ImGui.SetNextItemWidth(130);
|
||||||
int quantity = item.RemainingQuantity;
|
int quantity = item.RemainingQuantity;
|
||||||
if (ImGui.InputInt($"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})",
|
if (ImGui.InputInt($"{venture.Name} ({string.Join(" ", ventures.Select(x => x.CategoryName))})",
|
||||||
@ -119,78 +339,62 @@ internal sealed class ConfigWindow : Window
|
|||||||
item.RemainingQuantity = quantity;
|
item.RemainingQuantity = quantity;
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImGui.Selectable($"{item.RemainingQuantity}x {venture.Name}");
|
|
||||||
|
|
||||||
if (ImGui.BeginDragDropSource())
|
ImGui.SameLine(windowX - 30);
|
||||||
|
ImGui.BeginDisabled(i == 0);
|
||||||
|
if (ImGuiComponents.IconButton($"##Up{i}", FontAwesomeIcon.ArrowUp))
|
||||||
{
|
{
|
||||||
ImGui.SetDragDropPayload("ArcDragDrop", nint.Zero, 0);
|
itemToAdd = item;
|
||||||
_dragDropSource = item;
|
indexToAdd = i - 1;
|
||||||
|
|
||||||
ImGui.EndDragDropSource();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.BeginDragDropTarget())
|
ImGui.EndDisabled();
|
||||||
{
|
|
||||||
if (_dragDropSource != null && ImGui.AcceptDragDropPayload("ArcDragDrop").NativePtr != null)
|
|
||||||
{
|
|
||||||
itemToAdd = _dragDropSource;
|
|
||||||
indexToAdd = i;
|
|
||||||
|
|
||||||
_dragDropSource = null;
|
ImGui.SameLine(0, 0);
|
||||||
|
ImGui.BeginDisabled(i == list.Items.Count - 1);
|
||||||
|
if (ImGuiComponents.IconButton($"##Down{i}", FontAwesomeIcon.ArrowDown))
|
||||||
|
{
|
||||||
|
itemToAdd = item;
|
||||||
|
indexToAdd = i + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndDragDropTarget();
|
ImGui.EndDisabled();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.OpenPopupOnItemClick($"###ctx{i}", ImGuiPopupFlags.MouseButtonRight);
|
ImGui.SameLine();
|
||||||
if (ImGui.BeginPopupContextItem($"###ctx{i}"))
|
if (ImGuiComponents.IconButton($"##Remove{i}", FontAwesomeIcon.Times))
|
||||||
{
|
|
||||||
if (ImGui.MenuItem($"Remove {venture.Name}"))
|
|
||||||
itemToRemove = item;
|
itemToRemove = item;
|
||||||
|
|
||||||
ImGui.EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.PopID();
|
ImGui.PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemToRemove != null)
|
if (itemToRemove != null)
|
||||||
{
|
{
|
||||||
_configuration.QueuedItems.Remove(itemToRemove);
|
list.Items.Remove(itemToRemove);
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemToAdd != null)
|
if (itemToAdd != null)
|
||||||
{
|
{
|
||||||
_pluginLog.Information($"Updating {itemToAdd.ItemId} → {indexToAdd}");
|
_pluginLog.Information($"Updating {itemToAdd.ItemId} → {indexToAdd}");
|
||||||
_configuration.QueuedItems.Remove(itemToAdd);
|
list.Items.Remove(itemToAdd);
|
||||||
_configuration.QueuedItems.Insert(indexToAdd, itemToAdd);
|
list.Items.Insert(indexToAdd, itemToAdd);
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.Unindent(30);
|
if (list.Items.Count > 0 && list.Type == Configuration.ListType.CollectOneTime)
|
||||||
|
|
||||||
if (_configuration.QueuedItems.Count > 0)
|
|
||||||
ImGui.Separator();
|
|
||||||
|
|
||||||
if (ImGuiComponents.IconButtonWithText(_enableDragDrop ? FontAwesomeIcon.Times : FontAwesomeIcon.Sort, _enableDragDrop ? "Disable Drag&Drop" : "Enable Drag&Drop"))
|
|
||||||
{
|
{
|
||||||
_enableDragDrop = !_enableDragDrop;
|
ImGui.Spacing();
|
||||||
}
|
ImGui.BeginDisabled(list.Items.All(x => x.RemainingQuantity > 0));
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Check, "Remove all finished items"))
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Check, "Remove all finished items"))
|
||||||
{
|
{
|
||||||
if (_configuration.QueuedItems.RemoveAll(q => q.RemainingQuantity == 0) > 0)
|
list.Items.RemoveAll(q => q.RemainingQuantity <= 0);
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndTabItem();
|
ImGui.EndDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCharacters()
|
private void DrawCharacters()
|
||||||
@ -208,9 +412,9 @@ internal sealed class ConfigWindow : Window
|
|||||||
{
|
{
|
||||||
ImGui.PushID($"Char{character.LocalContentId}");
|
ImGui.PushID($"Char{character.LocalContentId}");
|
||||||
|
|
||||||
ImGui.PushItemWidth(ImGui.GetFontSize() * 30);
|
ImGui.SetNextItemWidth(ImGui.GetFontSize() * 30);
|
||||||
Vector4 buttonColor = new Vector4();
|
Vector4 buttonColor = new Vector4();
|
||||||
if (character is { Managed: true, Retainers.Count: > 0 })
|
if (character is { Type: not Configuration.CharacterType.NotManaged, Retainers.Count: > 0 })
|
||||||
{
|
{
|
||||||
if (character.Retainers.All(x => x.Managed))
|
if (character.Retainers.All(x => x.Managed))
|
||||||
buttonColor = ImGuiColors.HealerGreen;
|
buttonColor = ImGuiColors.HealerGreen;
|
||||||
@ -222,24 +426,113 @@ internal sealed class ConfigWindow : Window
|
|||||||
|
|
||||||
if (ImGuiComponents.IconButton(FontAwesomeIcon.Book, buttonColor))
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.Book, buttonColor))
|
||||||
{
|
{
|
||||||
character.Managed = !character.Managed;
|
if (character.Type == Configuration.CharacterType.NotManaged)
|
||||||
|
{
|
||||||
|
character.Type = Configuration.CharacterType.Standalone;
|
||||||
|
character.CharacterGroupId = Guid.Empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
character.Type = Configuration.CharacterType.NotManaged;
|
||||||
|
character.CharacterGroupId = Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
|
|
||||||
if (ImGui.CollapsingHeader(
|
if (ImGui.CollapsingHeader(
|
||||||
$"{character.CharacterName} {(character.Managed ? $"({character.Retainers.Count(x => x.Managed)} / {character.Retainers.Count})" : "")}###{character.LocalContentId}"))
|
$"{character.CharacterName} {(character.Type != Configuration.CharacterType.NotManaged ? $"({character.Retainers.Count(x => x.Managed)} / {character.Retainers.Count})" : "")}###{character.LocalContentId}"))
|
||||||
{
|
{
|
||||||
ImGui.Indent(30);
|
ImGui.Indent(30);
|
||||||
foreach (var retainer in character.Retainers.Where(x => x.Job > 0).OrderBy(x => x.DisplayOrder))
|
|
||||||
{
|
|
||||||
ImGui.BeginDisabled(retainer.Level < MaxLevel);
|
|
||||||
|
|
||||||
bool managed = retainer.Managed && retainer.Level == MaxLevel;
|
List<(Guid Id, string Name)> groups =
|
||||||
ImGui.Text(_gameCache.Jobs[retainer.Job]);
|
new List<(Guid Id, string Name)> { (Guid.Empty, "No Group (manually assign lists)") }
|
||||||
|
.Concat(_configuration.CharacterGroups.Select(x => (x.Id, x.Name)))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
|
||||||
|
if (ImGui.BeginTabBar("CharOptions"))
|
||||||
|
{
|
||||||
|
if (character.Type != Configuration.CharacterType.NotManaged &&
|
||||||
|
ImGui.BeginTabItem("Venture Lists"))
|
||||||
|
{
|
||||||
|
int groupIndex = 0;
|
||||||
|
if (character.Type == Configuration.CharacterType.PartOfCharacterGroup)
|
||||||
|
groupIndex = groups.FindIndex(x => x.Id == character.CharacterGroupId);
|
||||||
|
if (ImGui.Combo("Character Group", ref groupIndex, groups.Select(x => x.Name).ToArray(),
|
||||||
|
groups.Count))
|
||||||
|
{
|
||||||
|
if (groupIndex == 0)
|
||||||
|
{
|
||||||
|
character.Type = Configuration.CharacterType.Standalone;
|
||||||
|
character.CharacterGroupId = Guid.Empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
character.Type = Configuration.CharacterType.PartOfCharacterGroup;
|
||||||
|
character.CharacterGroupId = groups[groupIndex].Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
if (groupIndex == 0)
|
||||||
|
{
|
||||||
|
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
|
||||||
|
if (character.ItemListIds == null)
|
||||||
|
character.ItemListIds = new();
|
||||||
|
DrawVentureListSelection(character.LocalContentId.ToString(),
|
||||||
|
character.ItemListIds);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.TextWrapped($"Retainers will participate in the following lists:");
|
||||||
|
ImGui.Indent(30);
|
||||||
|
|
||||||
|
var group = _configuration.CharacterGroups.Single(
|
||||||
|
x => x.Id == groups[groupIndex].Id);
|
||||||
|
var lists = group.ItemListIds
|
||||||
|
.Where(listId => listId != Guid.Empty)
|
||||||
|
.Select(listId => _configuration.ItemLists.SingleOrDefault(x => x.Id == listId))
|
||||||
|
.Where(list => list != null)
|
||||||
|
.Cast<Configuration.ItemList>()
|
||||||
|
.ToList();
|
||||||
|
if (lists.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var list in lists)
|
||||||
|
ImGui.BulletText($"{list.Name}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudRed, "(None)");
|
||||||
|
|
||||||
|
ImGui.Unindent(30);
|
||||||
|
ImGui.Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("Retainers"))
|
||||||
|
{
|
||||||
|
foreach (var retainer in character.Retainers.Where(x => x.Job > 0)
|
||||||
|
.OrderBy(x => x.DisplayOrder))
|
||||||
|
{
|
||||||
|
ImGui.BeginDisabled(retainer.Level < MinLevel);
|
||||||
|
|
||||||
|
bool managed = retainer.Managed && retainer.Level >= MinLevel;
|
||||||
|
|
||||||
|
IDalamudTextureWrap? icon = _iconCache.GetIcon(62000 + retainer.Job);
|
||||||
|
if (icon != null)
|
||||||
|
{
|
||||||
|
ImGui.Image(icon.ImGuiHandle, new Vector2(23, 23));
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGui.Checkbox($"{retainer.Name}###Retainer{retainer.Name}{retainer.DisplayOrder}",
|
}
|
||||||
|
|
||||||
|
if (ImGui.Checkbox(
|
||||||
|
$"{retainer.Name}###Retainer{retainer.Name}{retainer.DisplayOrder}",
|
||||||
ref managed))
|
ref managed))
|
||||||
{
|
{
|
||||||
retainer.Managed = managed;
|
retainer.Managed = managed;
|
||||||
@ -249,6 +542,13 @@ internal sealed class ConfigWindow : Window
|
|||||||
ImGui.EndDisabled();
|
ImGui.EndDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui.Unindent(30);
|
ImGui.Unindent(30);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,6 +560,186 @@ internal sealed class ConfigWindow : Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawCharacterGroups()
|
||||||
|
{
|
||||||
|
if (ImGui.BeginTabItem("Groups"))
|
||||||
|
{
|
||||||
|
Configuration.CharacterGroup? groupToDelete = null;
|
||||||
|
foreach (var group in _configuration.CharacterGroups)
|
||||||
|
{
|
||||||
|
ImGui.PushID($"##Group{group.Id}");
|
||||||
|
|
||||||
|
if (ImGuiComponents.IconButton(FontAwesomeIcon.Cog))
|
||||||
|
{
|
||||||
|
_currentEditPopups[group.Id] = new TemporaryConfig
|
||||||
|
{
|
||||||
|
Name = group.Name,
|
||||||
|
};
|
||||||
|
ImGui.OpenPopup($"##EditGroup{group.Id}");
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawCharacterGroupEditorPopup(group, out var assignedCharacters, ref groupToDelete);
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawCharacterGroup(group, assignedCharacters);
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupToDelete != null)
|
||||||
|
{
|
||||||
|
_configuration.CharacterGroups.Remove(groupToDelete);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
DrawNewCharacterGroup();
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawCharacterGroupEditorPopup(Configuration.CharacterGroup group,
|
||||||
|
out List<Configuration.CharacterConfiguration> assignedCharacters,
|
||||||
|
ref Configuration.CharacterGroup? groupToDelete)
|
||||||
|
{
|
||||||
|
assignedCharacters = _configuration.Characters
|
||||||
|
.Where(x => x.Type == Configuration.CharacterType.PartOfCharacterGroup &&
|
||||||
|
x.CharacterGroupId == group.Id)
|
||||||
|
.OrderBy(x => x.WorldName)
|
||||||
|
.ThenBy(x => x.LocalContentId)
|
||||||
|
.ToList();
|
||||||
|
if (_currentEditPopups.TryGetValue(group.Id, out TemporaryConfig? temporaryConfig) &&
|
||||||
|
ImGui.BeginPopup($"##EditGroup{group.Id}"))
|
||||||
|
{
|
||||||
|
(bool save, bool canSave) = DrawGroupEditor(temporaryConfig, group);
|
||||||
|
|
||||||
|
ImGui.BeginDisabled(!canSave || group.Name == temporaryConfig.Name);
|
||||||
|
save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save");
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
if (save && canSave)
|
||||||
|
{
|
||||||
|
group.Name = temporaryConfig.Name;
|
||||||
|
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.BeginDisabled(assignedCharacters.Count > 0);
|
||||||
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Times, "Delete"))
|
||||||
|
{
|
||||||
|
groupToDelete = group;
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
if (assignedCharacters.Count > 0 && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||||
|
{
|
||||||
|
ImGui.BeginTooltip();
|
||||||
|
ImGui.Text(
|
||||||
|
$"Remove the {assignedCharacters.Count} character(s) from this group before deleting it.");
|
||||||
|
foreach (var character in assignedCharacters)
|
||||||
|
ImGui.BulletText($"{character.CharacterName} @ {character.WorldName}");
|
||||||
|
ImGui.EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawCharacterGroup(Configuration.CharacterGroup group,
|
||||||
|
List<Configuration.CharacterConfiguration> assignedCharacters)
|
||||||
|
{
|
||||||
|
string countLabel = assignedCharacters.Count == 0 ? "no characters"
|
||||||
|
: assignedCharacters.Count == 1 ? "1 character"
|
||||||
|
: $"{assignedCharacters.Count} characters";
|
||||||
|
if (ImGui.CollapsingHeader($"{group.Name} ({countLabel})"))
|
||||||
|
{
|
||||||
|
ImGui.Indent(30);
|
||||||
|
if (ImGui.BeginTabBar("GroupOptions"))
|
||||||
|
{
|
||||||
|
if (ImGui.BeginTabItem("Venture Lists"))
|
||||||
|
{
|
||||||
|
DrawVentureListSelection(group.Id.ToString(), group.ItemListIds);
|
||||||
|
ImGui.EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginTabItem("Characters"))
|
||||||
|
{
|
||||||
|
ImGui.Text("Characters in this group:");
|
||||||
|
ImGui.Indent(30);
|
||||||
|
foreach (var character in assignedCharacters.OrderBy(x => x.WorldName)
|
||||||
|
.ThenBy(x => x.LocalContentId))
|
||||||
|
ImGui.TextUnformatted($"{character.CharacterName} @ {character.WorldName}");
|
||||||
|
ImGui.Unindent(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndTabBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Unindent(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawNewCharacterGroup()
|
||||||
|
{
|
||||||
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Plus, "Add Group"))
|
||||||
|
ImGui.OpenPopup("##AddGroup");
|
||||||
|
|
||||||
|
if (ImGui.BeginPopup("##AddGroup"))
|
||||||
|
{
|
||||||
|
(bool save, bool canSave) = DrawGroupEditor(_newGroup, null);
|
||||||
|
|
||||||
|
ImGui.BeginDisabled(!canSave);
|
||||||
|
save |= ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Save, "Save");
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
if (save && canSave)
|
||||||
|
{
|
||||||
|
_configuration.CharacterGroups.Add(new Configuration.CharacterGroup
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
Name = _newGroup.Name,
|
||||||
|
ItemListIds = new(),
|
||||||
|
});
|
||||||
|
|
||||||
|
_newGroup = new() { Name = string.Empty };
|
||||||
|
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private (bool Save, bool CanSave) DrawGroupEditor(TemporaryConfig group,
|
||||||
|
Configuration.CharacterGroup? existingGroup)
|
||||||
|
{
|
||||||
|
string name = group.Name;
|
||||||
|
bool save = ImGui.InputTextWithHint("", "Group Name...", ref name, 64, ImGuiInputTextFlags.EnterReturnsTrue);
|
||||||
|
bool canSave = IsValidGroupName(name, existingGroup);
|
||||||
|
|
||||||
|
group.Name = name;
|
||||||
|
return (save, canSave);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsValidGroupName(string name, Configuration.CharacterGroup? existingGroup)
|
||||||
|
{
|
||||||
|
return name.Length >= 2 &&
|
||||||
|
!name.Contains('%') &&
|
||||||
|
!_configuration.CharacterGroups.Any(x => x != existingGroup && name.EqualsIgnoreCase(x.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsValidListName(string name, Configuration.ItemList? existingList)
|
||||||
|
{
|
||||||
|
return name.Length >= 2 &&
|
||||||
|
!name.Contains('%') &&
|
||||||
|
!_configuration.ItemLists.Any(x => x != existingList && name.EqualsIgnoreCase(x.Name));
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawGatheredItemsToCheck()
|
private void DrawGatheredItemsToCheck()
|
||||||
{
|
{
|
||||||
if (ImGui.BeginTabItem("Locked Items"))
|
if (ImGui.BeginTabItem("Locked Items"))
|
||||||
@ -269,7 +749,8 @@ internal sealed class ConfigWindow : Window
|
|||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|
||||||
var itemsToCheck =
|
var itemsToCheck =
|
||||||
_configuration.QueuedItems
|
_configuration.ItemLists
|
||||||
|
.SelectMany(x => x.Items)
|
||||||
.Select(x => x.ItemId)
|
.Select(x => x.ItemId)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.Select(itemId => new
|
.Select(itemId => new
|
||||||
@ -287,10 +768,10 @@ internal sealed class ConfigWindow : Window
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var charactersToCheck = _configuration.Characters
|
var charactersToCheck = _configuration.Characters
|
||||||
.Where(x => x.Managed)
|
.Where(x => x.Type != Configuration.CharacterType.NotManaged)
|
||||||
.OrderBy(x => x.WorldName)
|
.OrderBy(x => x.WorldName)
|
||||||
.ThenBy(x => x.LocalContentId)
|
.ThenBy(x => x.LocalContentId)
|
||||||
.Select(x => new CheckedCharacter(x, itemsToCheck))
|
.Select(x => new CheckedCharacter(_configuration, x, itemsToCheck))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (_checkPerCharacter)
|
if (_checkPerCharacter)
|
||||||
@ -379,6 +860,129 @@ internal sealed class ConfigWindow : Window
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawVentureListSelection(string id, List<Guid> selectedLists)
|
||||||
|
{
|
||||||
|
ImGui.PushID($"##ListSelection{id}");
|
||||||
|
|
||||||
|
List<(Guid Id, string Name, Configuration.ItemList List)> itemLists = new List<Configuration.ItemList>
|
||||||
|
{
|
||||||
|
new Configuration.ItemList
|
||||||
|
{
|
||||||
|
Id = Guid.Empty,
|
||||||
|
Name = "---",
|
||||||
|
Type = Configuration.ListType.CollectOneTime,
|
||||||
|
Priority = Configuration.ListPriority.InOrder,
|
||||||
|
}
|
||||||
|
}.Concat(_configuration.ItemLists)
|
||||||
|
.Select(x => (x.Id, x.Name, x)).ToList();
|
||||||
|
int? itemToRemove = null;
|
||||||
|
int? itemToAdd = null;
|
||||||
|
int indexToAdd = 0;
|
||||||
|
float windowX = ImGui.GetContentRegionAvail().X;
|
||||||
|
for (int i = 0; i < selectedLists.Count; ++i)
|
||||||
|
{
|
||||||
|
ImGui.PushID($"##{id}_Item{i}");
|
||||||
|
var listId = selectedLists[i];
|
||||||
|
var listIndex = itemLists.FindIndex(x => x.Id == listId);
|
||||||
|
|
||||||
|
ImGui.SetNextItemWidth(windowX - 76);
|
||||||
|
if (ImGui.Combo("", ref listIndex, itemLists.Select(x => x.Name).ToArray(), itemLists.Count))
|
||||||
|
{
|
||||||
|
selectedLists[i] = itemLists[listIndex].Id;
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.BeginDisabled(i == 0);
|
||||||
|
if (ImGuiComponents.IconButton($"##Up{i}", FontAwesomeIcon.ArrowUp))
|
||||||
|
{
|
||||||
|
itemToAdd = i;
|
||||||
|
indexToAdd = i - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
ImGui.SameLine(0, 0);
|
||||||
|
ImGui.BeginDisabled(i == selectedLists.Count - 1);
|
||||||
|
if (ImGuiComponents.IconButton($"##Down{i}", FontAwesomeIcon.ArrowDown))
|
||||||
|
{
|
||||||
|
itemToAdd = i;
|
||||||
|
indexToAdd = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGuiComponents.IconButton($"##Remove{i}", FontAwesomeIcon.Times))
|
||||||
|
itemToRemove = i;
|
||||||
|
|
||||||
|
if (listIndex > 0)
|
||||||
|
{
|
||||||
|
if (selectedLists.Take(i).Any(x => x == listId))
|
||||||
|
{
|
||||||
|
ImGui.Indent(30);
|
||||||
|
ImGui.TextColored(ImGuiColors.DalamudYellow, "This entry is a duplicate and will be ignored.");
|
||||||
|
ImGui.Unindent(30);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var list = itemLists[listIndex].List;
|
||||||
|
ImGui.Indent(30);
|
||||||
|
ImGui.Text(list.Type == Configuration.ListType.CollectOneTime
|
||||||
|
? $"{list.GetIcon()} Items on this list will be collected once."
|
||||||
|
: $"{list.GetIcon()} Items on this list will be kept in stock on each character.");
|
||||||
|
ImGui.Spacing();
|
||||||
|
foreach (var item in list.Items)
|
||||||
|
{
|
||||||
|
var venture = _gameCache.Ventures.First(x => x.ItemId == item.ItemId);
|
||||||
|
ImGui.Text($"{item.RemainingQuantity}x {venture.Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Unindent(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemToRemove != null)
|
||||||
|
{
|
||||||
|
selectedLists.RemoveAt(itemToRemove.Value);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemToAdd != null)
|
||||||
|
{
|
||||||
|
Guid listId = selectedLists[itemToAdd.Value];
|
||||||
|
selectedLists.RemoveAt(itemToAdd.Value);
|
||||||
|
selectedLists.Insert(indexToAdd, listId);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
var unusedLists = itemLists.Where(x => x.Id != Guid.Empty && !selectedLists.Contains(x.Id)).ToList();
|
||||||
|
ImGui.BeginDisabled(unusedLists.Count == 0);
|
||||||
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Plus, "Add Venture List to this Group"))
|
||||||
|
ImGui.OpenPopup($"##AddItem{id}");
|
||||||
|
|
||||||
|
if (ImGui.BeginPopupContextItem($"##AddItem{id}"))
|
||||||
|
{
|
||||||
|
foreach (var list in unusedLists)
|
||||||
|
{
|
||||||
|
if (ImGui.MenuItem($"{list.Name}##{list.Id}"))
|
||||||
|
{
|
||||||
|
selectedLists.Add(list.Id);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndDisabled();
|
||||||
|
|
||||||
|
ImGui.PopID();
|
||||||
|
}
|
||||||
|
|
||||||
private void Save()
|
private void Save()
|
||||||
{
|
{
|
||||||
_pluginInterface.SavePluginConfig(_configuration);
|
_pluginInterface.SavePluginConfig(_configuration);
|
||||||
@ -386,16 +990,44 @@ internal sealed class ConfigWindow : Window
|
|||||||
|
|
||||||
private sealed class CheckedCharacter
|
private sealed class CheckedCharacter
|
||||||
{
|
{
|
||||||
public CheckedCharacter(Configuration.CharacterConfiguration character,
|
public CheckedCharacter(Configuration configuration, Configuration.CharacterConfiguration character,
|
||||||
List<CheckedItem> itemsToCheck)
|
List<CheckedItem> itemsToCheck)
|
||||||
{
|
{
|
||||||
Character = character;
|
Character = character;
|
||||||
|
|
||||||
|
List<Guid> itemListIds = new();
|
||||||
|
if (character.Type == Configuration.CharacterType.Standalone)
|
||||||
|
{
|
||||||
|
itemListIds = character.ItemListIds;
|
||||||
|
}
|
||||||
|
else if (character.Type == Configuration.CharacterType.PartOfCharacterGroup)
|
||||||
|
{
|
||||||
|
var group = configuration.CharacterGroups.SingleOrDefault(x => x.Id == character.CharacterGroupId);
|
||||||
|
if (group != null)
|
||||||
|
itemListIds = group.ItemListIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemIdsOnLists = itemListIds.Where(listId => listId != Guid.Empty)
|
||||||
|
.Select(listId => configuration.ItemLists.SingleOrDefault(x => x.Id == listId))
|
||||||
|
.Where(list => list != null)
|
||||||
|
.SelectMany(list => list!.Items)
|
||||||
|
.Select(x => x.ItemId)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
foreach (var item in itemsToCheck)
|
foreach (var item in itemsToCheck)
|
||||||
{
|
{
|
||||||
|
// check if the item is on any relevant list
|
||||||
|
if (!itemIdsOnLists.Contains(item.ItemId))
|
||||||
|
{
|
||||||
|
Items[item.ItemId] = ColorGrey;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we are the correct job
|
||||||
bool enabled = character.Retainers.Any(x => item.Ventures.Any(v => v.MatchesJob(x.Job)));
|
bool enabled = character.Retainers.Any(x => item.Ventures.Any(v => v.MatchesJob(x.Job)));
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
|
// do we have it gathered on this char?
|
||||||
if (character.GatheredItems.Contains(item.GatheredItem.GatheredItemId))
|
if (character.GatheredItems.Contains(item.GatheredItem.GatheredItemId))
|
||||||
Items[item.ItemId] = ColorGreen;
|
Items[item.ItemId] = ColorGreen;
|
||||||
else
|
else
|
||||||
@ -423,4 +1055,11 @@ internal sealed class ConfigWindow : Window
|
|||||||
public required List<Venture> Ventures { get; init; }
|
public required List<Venture> Ventures { get; init; }
|
||||||
public required uint ItemId { get; init; }
|
public required uint ItemId { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class TemporaryConfig
|
||||||
|
{
|
||||||
|
public required string Name { get; set; }
|
||||||
|
public Configuration.ListType ListType { get; set; }
|
||||||
|
public Configuration.ListPriority ListPriority { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
"requested": "[2.1.12, )",
|
"requested": "[2.1.12, )",
|
||||||
"resolved": "2.1.12",
|
"resolved": "2.1.12",
|
||||||
"contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
|
"contentHash": "Sc0PVxvgg4NQjcI8n10/VfUQBAS4O+Fw2pZrAqBdRMbthYGeogzu5+xmIGCGmsEZ/ukMOBuAqiNiB5qA3MRalg=="
|
||||||
|
},
|
||||||
|
"llib": {
|
||||||
|
"type": "Project"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
1
LLib
Submodule
1
LLib
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit abbbec4f26b1a8903b0cd7aa04f00d557602eaf3
|
Loading…
Reference in New Issue
Block a user