using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Numerics; using System.Text; using Dalamud.Bindings.ImGui; using Dalamud.Interface; using Dalamud.Interface.Colors; using Dalamud.Interface.Components; using Dalamud.Interface.Utility.Raii; using Dalamud.Plugin; using Dalamud.Plugin.Services; using Dalamud.Utility; using Lumina.Excel.Sheets; using Questionable.Controller; using Questionable.Data; using Questionable.External; using Questionable.Model; using Questionable.Model.Questing; namespace Questionable.Windows.ConfigComponents; internal sealed class DutyConfigComponent : ConfigComponent { private sealed record DutyInfo(uint CfcId, uint TerritoryId, string Name); private const string DutyClipboardPrefix = "qst:duty:"; private readonly QuestRegistry _questRegistry; private readonly AutoDutyIpc _autoDutyIpc; private readonly Dictionary> _contentFinderConditionNames; public DutyConfigComponent(IDalamudPluginInterface pluginInterface, Configuration configuration, IDataManager dataManager, QuestRegistry questRegistry, AutoDutyIpc autoDutyIpc, TerritoryData territoryData) : base(pluginInterface, configuration) { _questRegistry = questRegistry; _autoDutyIpc = autoDutyIpc; _contentFinderConditionNames = (from x in dataManager.GetExcelSheet() where x.RowId != 0 && !x.Unknown16 orderby x.Unknown15 select x.Content.ValueNullable into x where x.HasValue select x.Value into x select new { Expansion = (EExpansionVersion)x.TerritoryType.Value.ExVersion.RowId, CfcId = x.RowId, Name = (territoryData.GetContentFinderCondition(x.RowId)?.Name ?? "?"), TerritoryId = x.TerritoryType.RowId, ContentType = x.ContentType.RowId, Level = x.ClassJobLevelRequired, SortKey = x.SortKey } into x group x by x.Expansion).ToDictionary(x => x.Key, x => x.Select(y => new DutyInfo(y.CfcId, y.TerritoryId, ConfigComponent.FormatLevel(y.Level) + " " + y.Name)).ToList()); } public override void DrawTab() { using ImRaii.IEndObject endObject = ImRaii.TabItem("Duties###Duties"); if (!endObject) { return; } bool v = base.Configuration.Duties.RunInstancedContentWithAutoDuty; if (ImGui.Checkbox("Run instanced content with AutoDuty and BossMod", ref v)) { base.Configuration.Duties.RunInstancedContentWithAutoDuty = v; Save(); } ImGui.SameLine(); ImGuiComponents.HelpMarker("The combat module used for this is configured by AutoDuty, ignoring whichever selection you've made in Questionable's \"General\" configuration."); ImGui.Separator(); using (ImRaii.Disabled(!v)) { ImGui.Text("Questionable includes a default list of duties that work if AutoDuty and BossMod are installed."); ImGui.Text("The included list of duties can change with each update, and is based on the following spreadsheet:"); if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.GlobeEurope, "Open AutoDuty spreadsheet")) { Util.OpenLink("https://docs.google.com/spreadsheets/d/151RlpqRcCpiD_VbQn6Duf-u-S71EP7d0mx3j1PDNoNA/edit?pli=1#gid=0"); } ImGui.Separator(); ImGui.Text("You can override the settings for each individual dungeon/trial:"); DrawConfigTable(v); DrawEnableAllButton(); ImGui.SameLine(); DrawClipboardButtons(); ImGui.SameLine(); DrawResetButton(); } } private void DrawConfigTable(bool runInstancedContentWithAutoDuty) { using ImRaii.IEndObject endObject = ImRaii.Child("DutyConfiguration", new Vector2(650f, 400f), border: true); if (!endObject) { return; } EExpansionVersion[] values = Enum.GetValues(); for (int i = 0; i < values.Length; i++) { EExpansionVersion eExpansionVersion = values[i]; (int enabledCount, int totalCount) dutyCountsForExpansion = GetDutyCountsForExpansion(eExpansionVersion); int item = dutyCountsForExpansion.enabledCount; int item2 = dutyCountsForExpansion.totalCount; string obj = ((item2 > 0) ? $"{eExpansionVersion.ToFriendlyString()} ({item}/{item2})" : eExpansionVersion.ToFriendlyString()); string key = eExpansionVersion.ToString(); ImGui.SetNextItemOpen(base.Configuration.Duties.ExpansionHeaderStates.GetValueOrDefault(key, defaultValue: false), ImGuiCond.Always); if (ImGui.CollapsingHeader(obj)) { if (!base.Configuration.Duties.ExpansionHeaderStates.GetValueOrDefault(key, defaultValue: false)) { base.Configuration.Duties.ExpansionHeaderStates[key] = true; Save(); } ImU8String table = new ImU8String(6, 1); table.AppendLiteral("Duties"); table.AppendFormatted(eExpansionVersion); using ImRaii.IEndObject endObject2 = ImRaii.Table(table, 2, ImGuiTableFlags.SizingFixedFit); if (!ImRaii.IEndObject.op_True(endObject2)) { continue; } ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthStretch); ImGui.TableSetupColumn("Options", ImGuiTableColumnFlags.WidthFixed, 200f); if (!_contentFinderConditionNames.TryGetValue(eExpansionVersion, out List value)) { continue; } foreach (var (num3, value2, text2) in value) { if (!_questRegistry.TryGetDutyByContentFinderConditionId(num3, out DutyOptions dutyOptions)) { continue; } ImGui.TableNextRow(); string[] items = (dutyOptions.Enabled ? SupportedCfcOptions : UnsupportedCfcOptions); int currentItem = 0; if (base.Configuration.Duties.WhitelistedDutyCfcIds.Contains(num3)) { currentItem = 1; } if (base.Configuration.Duties.BlacklistedDutyCfcIds.Contains(num3)) { currentItem = 2; } if (ImGui.TableNextColumn()) { ImGui.AlignTextToFramePadding(); ImGui.TextUnformatted(text2); if (ImGui.IsItemHovered() && base.Configuration.Advanced.AdditionalStatusInformation) { using ImRaii.IEndObject endObject3 = ImRaii.Tooltip(); if (endObject3) { ImGui.TextUnformatted(text2); ImGui.Separator(); table = new ImU8String(13, 1); table.AppendLiteral("TerritoryId: "); table.AppendFormatted(value2); ImGui.BulletText(table); table = new ImU8String(26, 1); table.AppendLiteral("ContentFinderConditionId: "); table.AppendFormatted(num3); ImGui.BulletText(table); } } if (runInstancedContentWithAutoDuty && !_autoDutyIpc.HasPath(num3)) { ImGuiComponents.HelpMarker("This duty is not supported by AutoDuty", FontAwesomeIcon.Times, ImGuiColors.DalamudRed); } else if (dutyOptions.Notes.Count > 0) { ConfigComponent.DrawNotes(dutyOptions.Enabled, dutyOptions.Notes); } } if (!ImGui.TableNextColumn()) { continue; } table = new ImU8String(9, 1); table.AppendLiteral("##Dungeon"); table.AppendFormatted(num3); using (ImRaii.PushId(table)) { ImGui.SetNextItemWidth(200f); if (ImGui.Combo(string.Empty, ref currentItem, in items, items.Length)) { base.Configuration.Duties.WhitelistedDutyCfcIds.Remove(num3); base.Configuration.Duties.BlacklistedDutyCfcIds.Remove(num3); switch (currentItem) { case 1: base.Configuration.Duties.WhitelistedDutyCfcIds.Add(num3); break; case 2: base.Configuration.Duties.BlacklistedDutyCfcIds.Add(num3); break; } Save(); } } } } else if (base.Configuration.Duties.ExpansionHeaderStates.GetValueOrDefault(key, defaultValue: false)) { base.Configuration.Duties.ExpansionHeaderStates[key] = false; Save(); } } } private (int enabledCount, int totalCount) GetDutyCountsForExpansion(EExpansionVersion expansion) { if (!_contentFinderConditionNames.TryGetValue(expansion, out List value)) { return (enabledCount: 0, totalCount: 0); } int num = 0; int num2 = 0; foreach (var (num5, _, _) in value) { if (_questRegistry.TryGetDutyByContentFinderConditionId(num5, out DutyOptions dutyOptions)) { num2++; if (base.Configuration.Duties.WhitelistedDutyCfcIds.Contains(num5) || (!base.Configuration.Duties.BlacklistedDutyCfcIds.Contains(num5) && dutyOptions.Enabled)) { num++; } } } return (enabledCount: num, totalCount: num2); } private void DrawEnableAllButton() { if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.CheckCircle, "Enable All")) { base.Configuration.Duties.BlacklistedDutyCfcIds.Clear(); base.Configuration.Duties.WhitelistedDutyCfcIds.Clear(); foreach (List value in _contentFinderConditionNames.Values) { foreach (var (num3, _, _) in value) { if (_questRegistry.TryGetDutyByContentFinderConditionId(num3, out DutyOptions _)) { base.Configuration.Duties.WhitelistedDutyCfcIds.Add(num3); } } } Save(); } if (ImGui.IsItemHovered()) { ImGui.SetTooltip("Enable all of the duties, use at your own risk."); } } private void DrawClipboardButtons() { using (ImRaii.Disabled(base.Configuration.Duties.WhitelistedDutyCfcIds.Count + base.Configuration.Duties.BlacklistedDutyCfcIds.Count == 0)) { if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Copy, "Export to clipboard")) { IEnumerable first = base.Configuration.Duties.WhitelistedDutyCfcIds.Select((uint x) => $"{"+"}{x}"); IEnumerable second = base.Configuration.Duties.BlacklistedDutyCfcIds.Select((uint x) => $"{"-"}{x}"); ImGui.SetClipboardText("qst:duty:" + Convert.ToBase64String(Encoding.UTF8.GetBytes(string.Join(";", first.Concat(second))))); } } ImGui.SameLine(); string text = ImGui.GetClipboardText().Trim(); using (ImRaii.Disabled(string.IsNullOrEmpty(text) || !text.StartsWith("qst:duty:", StringComparison.InvariantCulture))) { if (!ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Paste, "Import from Clipboard")) { return; } text = text.Substring("qst:duty:".Length); string text2 = Encoding.UTF8.GetString(Convert.FromBase64String(text)); base.Configuration.Duties.WhitelistedDutyCfcIds.Clear(); base.Configuration.Duties.BlacklistedDutyCfcIds.Clear(); string[] array = text2.Split(";"); foreach (string text3 in array) { if (text3.StartsWith("+", StringComparison.InvariantCulture) && uint.TryParse(text3.AsSpan("+".Length), CultureInfo.InvariantCulture, out var result)) { base.Configuration.Duties.WhitelistedDutyCfcIds.Add(result); } if (text3.StartsWith("-", StringComparison.InvariantCulture) && uint.TryParse(text3.AsSpan("-".Length), CultureInfo.InvariantCulture, out var result2)) { base.Configuration.Duties.BlacklistedDutyCfcIds.Add(result2); } } } } private void DrawResetButton() { using (ImRaii.Disabled(!ImGui.IsKeyDown(ImGuiKey.ModCtrl))) { if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Undo, "Reset to default")) { base.Configuration.Duties.WhitelistedDutyCfcIds.Clear(); base.Configuration.Duties.BlacklistedDutyCfcIds.Clear(); Save(); } } if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) { ImGui.SetTooltip("Hold CTRL to enable this button."); } } }