1
0
Fork 0
forked from aly/qstbak
qstbak/Questionable/Questionable.Windows.ConfigComponents/SinglePlayerDutyConfigComponent.cs
2026-08-17 20:29:32 +10:00

772 lines
30 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin;
using Dalamud.Plugin.Services;
using LLib.GameData;
using Lumina.Excel.Sheets;
using Microsoft.Extensions.Logging;
using Questionable.Controller;
using Questionable.Data;
using Questionable.Model;
using Questionable.Model.Questing;
using SmartNav.Model;
namespace Questionable.Windows.ConfigComponents;
internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
{
private sealed record SinglePlayerDutyInfo(string Name, IQuestInfo QuestInfo, TerritoryData.ContentFinderConditionData ContentFinderConditionData, byte Index, bool EnabledByDefault, string[] Notes, bool Enabled)
{
public EExpansionVersion Expansion => QuestInfo.Expansion;
public uint JournalGenreId => (uint)(((int?)QuestInfo.JournalGenre) ?? (-1));
public ushort SortKey => QuestInfo.SortKey;
public uint ContentFinderConditionId => ContentFinderConditionData.ContentFinderConditionId;
public uint TerritoryId => ContentFinderConditionData.TerritoryId;
public bool IsLimsaStart
{
get
{
uint contentFinderConditionId = ContentFinderConditionId;
if (contentFinderConditionId == 313 || contentFinderConditionId - 332 <= 2)
{
return true;
}
return false;
}
}
public bool IsGridaniaStart
{
get
{
uint contentFinderConditionId = ContentFinderConditionId;
if (contentFinderConditionId - 296 <= 3)
{
return true;
}
return false;
}
}
public bool IsUldahStart
{
get
{
uint contentFinderConditionId = ContentFinderConditionId;
if (contentFinderConditionId == 312 || contentFinderConditionId - 335 <= 2)
{
return true;
}
return false;
}
}
public bool IsOtherRoleQuest
{
get
{
uint contentFinderConditionId = ContentFinderConditionId;
if (contentFinderConditionId == 845 || contentFinderConditionId == 1016)
{
return true;
}
return false;
}
}
}
private const string SinglePlayerDutyClipboardPrefix = "qst:single:";
private static readonly List<(EClassJob ClassJob, string Name)> RoleQuestCategories;
private readonly string[] _retryDifficulties = new string[3] { "Normal", "Easy", "Very Easy" };
private readonly TerritoryData _territoryData;
private readonly QuestRegistry _questRegistry;
private readonly QuestData _questData;
private readonly IDataManager _dataManager;
private readonly ClassJobUtils _classJobUtils;
private readonly ILogger<SinglePlayerDutyConfigComponent> _logger;
private ImmutableDictionary<EAetheryteLocation, List<SinglePlayerDutyInfo>> _startingCityBattles = ImmutableDictionary<EAetheryteLocation, List<SinglePlayerDutyInfo>>.Empty;
private ImmutableDictionary<EExpansionVersion, List<SinglePlayerDutyInfo>> _mainScenarioBattles = ImmutableDictionary<EExpansionVersion, List<SinglePlayerDutyInfo>>.Empty;
private ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>> _jobQuestBattles = ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>>.Empty;
private ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>> _roleQuestBattles = ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>>.Empty;
private ImmutableList<SinglePlayerDutyInfo> _otherRoleQuestBattles = ImmutableList<SinglePlayerDutyInfo>.Empty;
private ImmutableList<(string Label, List<SinglePlayerDutyInfo>)> _otherQuestBattles = ImmutableList<(string, List<SinglePlayerDutyInfo>)>.Empty;
private bool _needsReload = true;
private int _selectedTab;
public SinglePlayerDutyConfigComponent(IDalamudPluginInterface pluginInterface, Configuration configuration, TerritoryData territoryData, QuestRegistry questRegistry, QuestData questData, IDataManager dataManager, ClassJobUtils classJobUtils, ILogger<SinglePlayerDutyConfigComponent> logger)
: base(pluginInterface, configuration)
{
_territoryData = territoryData;
_questRegistry = questRegistry;
_questData = questData;
_dataManager = dataManager;
_classJobUtils = classJobUtils;
_logger = logger;
_questRegistry.Reloaded += delegate
{
_needsReload = true;
};
}
public void Reload()
{
List<ElementId> list = (from x in _territoryData.GetAllQuestsWithQuestBattles()
group x by x.QuestId into x
where x.Count() > 1
select x.Key).ToList();
List<SinglePlayerDutyInfo> list2 = new List<SinglePlayerDutyInfo>();
Dictionary<EAetheryteLocation, List<SinglePlayerDutyInfo>> dictionary = new Dictionary<EAetheryteLocation, List<SinglePlayerDutyInfo>>
{
{
EAetheryteLocation.Limsa,
new List<SinglePlayerDutyInfo>()
},
{
EAetheryteLocation.Gridania,
new List<SinglePlayerDutyInfo>()
},
{
EAetheryteLocation.Uldah,
new List<SinglePlayerDutyInfo>()
}
};
List<SinglePlayerDutyInfo> list3 = new List<SinglePlayerDutyInfo>();
Dictionary<ElementId, EClassJob> dictionary2 = (from x in Enum.GetValues<EClassJob>()
where x != EClassJob.Adventurer && !x.IsCrafter() && !x.IsGatherer()
where x.IsClass() || !x.HasBaseClass()
select x).SelectMany((EClassJob x) => from y in _questRegistry.GetKnownClassJobQuests(x, includeRoleQuests: false)
select (QuestId: y.QuestId, ClassJob: x)).ToDictionary<(ElementId, EClassJob), ElementId, EClassJob>(((ElementId QuestId, EClassJob ClassJob) x) => x.QuestId, ((ElementId QuestId, EClassJob ClassJob) x) => x.ClassJob);
Dictionary<EClassJob, List<SinglePlayerDutyInfo>> dictionary3 = dictionary2.Values.Distinct().ToDictionary((EClassJob x) => x, (EClassJob _) => new List<SinglePlayerDutyInfo>());
Dictionary<ElementId, List<EClassJob>> dictionary4 = (from x in RoleQuestCategories.SelectMany<(EClassJob, string), (ElementId, EClassJob)>(((EClassJob ClassJob, string Name) x) => from y in _questData.GetRoleQuests(x.ClassJob)
select (QuestId: y.QuestId, ClassJob: x.ClassJob))
group x by x.QuestId).ToDictionary((IGrouping<ElementId, (ElementId QuestId, EClassJob ClassJob)> x) => x.Key, (IGrouping<ElementId, (ElementId QuestId, EClassJob ClassJob)> x) => x.Select(((ElementId QuestId, EClassJob ClassJob) y) => y.ClassJob).ToList());
Dictionary<EClassJob, List<SinglePlayerDutyInfo>> dictionary5 = RoleQuestCategories.ToDictionary<(EClassJob, string), EClassJob, List<SinglePlayerDutyInfo>>(((EClassJob ClassJob, string Name) x) => x.ClassJob, ((EClassJob ClassJob, string Name) _) => new List<SinglePlayerDutyInfo>());
List<SinglePlayerDutyInfo> list4 = new List<SinglePlayerDutyInfo>();
foreach (var allQuestsWithQuestBattle in _territoryData.GetAllQuestsWithQuestBattles())
{
ElementId item = allQuestsWithQuestBattle.QuestId;
byte item2 = allQuestsWithQuestBattle.Index;
TerritoryData.ContentFinderConditionData item3 = allQuestsWithQuestBattle.Data;
IQuestInfo questInfo = _questData.GetQuestInfo(item);
(bool QuestExists, bool EnabledByDefault, byte Index, string[] Notes) tuple = FindDutyOptions(item, item2);
bool item4 = tuple.QuestExists;
bool item5 = tuple.EnabledByDefault;
string[] item6 = tuple.Notes;
string text = ConfigComponent.FormatLevel(questInfo.Level) + " " + questInfo.Name;
if (!string.IsNullOrEmpty(item3.Name) && !questInfo.Name.EndsWith(item3.Name, StringComparison.Ordinal))
{
text = text + " (" + item3.Name + ")";
}
if (list.Contains(item))
{
text += $" (Part {item2 + 1})";
}
else
{
uint contentFinderConditionId = item3.ContentFinderConditionId;
if ((contentFinderConditionId == 674 || contentFinderConditionId == 691) ? true : false)
{
text += " (Melee/Phys. Ranged)";
}
}
SinglePlayerDutyInfo singlePlayerDutyInfo = new SinglePlayerDutyInfo(text, questInfo, item3, item2, item5, item6, item4);
EClassJob value;
List<EClassJob> value2;
if (singlePlayerDutyInfo.IsLimsaStart)
{
dictionary[EAetheryteLocation.Limsa].Add(singlePlayerDutyInfo);
}
else if (singlePlayerDutyInfo.IsGridaniaStart)
{
dictionary[EAetheryteLocation.Gridania].Add(singlePlayerDutyInfo);
}
else if (singlePlayerDutyInfo.IsUldahStart)
{
dictionary[EAetheryteLocation.Uldah].Add(singlePlayerDutyInfo);
}
else if (questInfo.IsMainScenarioQuest)
{
list2.Add(singlePlayerDutyInfo);
}
else if (dictionary2.TryGetValue(item, out value))
{
dictionary3[value].Add(singlePlayerDutyInfo);
}
else if (dictionary4.TryGetValue(item, out value2))
{
foreach (EClassJob item7 in value2)
{
dictionary5[item7].Add(singlePlayerDutyInfo);
}
}
else if (singlePlayerDutyInfo.IsOtherRoleQuest)
{
list4.Add(singlePlayerDutyInfo);
}
else
{
list3.Add(singlePlayerDutyInfo);
}
}
_startingCityBattles = dictionary.ToImmutableDictionary((KeyValuePair<EAetheryteLocation, List<SinglePlayerDutyInfo>> x) => x.Key, (KeyValuePair<EAetheryteLocation, List<SinglePlayerDutyInfo>> x) => x.Value.OrderBy((SinglePlayerDutyInfo y) => y.SortKey).ToList());
_mainScenarioBattles = (from x in list2
group x by x.Expansion).ToImmutableDictionary((IGrouping<EExpansionVersion, SinglePlayerDutyInfo> x) => x.Key, (IGrouping<EExpansionVersion, SinglePlayerDutyInfo> x) => (from y in x
orderby y.JournalGenreId, y.SortKey, y.Index
select y).ToList());
_jobQuestBattles = dictionary3.Where((KeyValuePair<EClassJob, List<SinglePlayerDutyInfo>> x) => x.Value.Count > 0).ToImmutableDictionary((KeyValuePair<EClassJob, List<SinglePlayerDutyInfo>> x) => x.Key, (KeyValuePair<EClassJob, List<SinglePlayerDutyInfo>> x) => (from y in x.Value.DistinctBy((SinglePlayerDutyInfo y) => y.ContentFinderConditionId)
orderby y.JournalGenreId, y.SortKey, y.Index
select y).ToList());
_roleQuestBattles = dictionary5.ToImmutableDictionary((KeyValuePair<EClassJob, List<SinglePlayerDutyInfo>> x) => x.Key, (KeyValuePair<EClassJob, List<SinglePlayerDutyInfo>> x) => (from y in x.Value
orderby y.JournalGenreId, y.SortKey, y.Index
select y).ToList());
_otherRoleQuestBattles = list4.ToImmutableList();
_otherQuestBattles = (from x in list3
orderby x.JournalGenreId, x.SortKey, x.Index
group x by x.JournalGenreId into x
select (BuildJournalGenreLabel(x.Key), x.ToList())).ToImmutableList();
}
private (bool QuestExists, bool EnabledByDefault, byte Index, string[] Notes) FindDutyOptions(ElementId questId, byte index)
{
if (!_questRegistry.TryGetQuest(questId, out Questionable.Model.Quest quest))
{
_logger.LogDebug("Disabling quest battle for quest {QuestId}, unknown quest", questId);
return (QuestExists: false, EnabledByDefault: false, Index: index, Notes: Array.Empty<string>());
}
if (quest.Root.Disabled)
{
_logger.LogDebug("Disabling quest battle for quest {QuestId}, quest is disabled", questId);
return (QuestExists: false, EnabledByDefault: false, Index: index, Notes: Array.Empty<string>());
}
if ((from x in quest.AllSteps()
select x.Step).FirstOrDefault((QuestStep x) => x.InteractionType == EInteractionType.SinglePlayerDuty && x.SinglePlayerDutyIndex == index) == null)
{
_logger.LogWarning("Disabling quest battle for quest {QuestId}, no battle with index {Index} found", questId, index);
return (QuestExists: false, EnabledByDefault: false, Index: index, Notes: Array.Empty<string>());
}
ushort key = (ushort)((questId is QuestId questId2) ? questId2.Value : 0);
bool item = false;
string[] item2 = Array.Empty<string>();
if (DutyRegistry.SinglePlayerDuties.TryGetValue(key, out SinglePlayerDutyEntry[] value))
{
SinglePlayerDutyEntry singlePlayerDutyEntry = value.FirstOrDefault((SinglePlayerDutyEntry e) => e.Index == index);
if (singlePlayerDutyEntry != null)
{
item = singlePlayerDutyEntry.Enabled;
item2 = singlePlayerDutyEntry.Notes;
}
}
return (QuestExists: true, EnabledByDefault: item, Index: index, Notes: item2);
}
private string BuildJournalGenreLabel(uint journalGenreId)
{
JournalGenre row = _dataManager.GetExcelSheet<JournalGenre>().GetRow(journalGenreId);
JournalCategory value = row.JournalCategory.Value;
string text = row.Name.ExtractText();
return value.Name.ExtractText() + " ※ " + text;
}
public override void DrawTab()
{
if (_needsReload)
{
_needsReload = false;
Reload();
}
UiThemeUtils.SectionHeader("Quest Battle Settings");
ImGui.Spacing();
(Vector2 ContentStartPos, float AvailableWidth, ImDrawListPtr DrawList) tuple = UiThemeUtils.BeginCard();
Vector2 item = tuple.ContentStartPos;
float item2 = tuple.AvailableWidth;
ImDrawListPtr item3 = tuple.DrawList;
bool value = base.Configuration.SinglePlayerDuties.RunSoloInstancesWithBossMod;
if (UiThemeUtils.WrappedCheckbox("Run quest battles with BossMod", ref value, "Work in Progress:\n- Will always use BossMod for combat (ignoring the configured combat module).\n- Only a small subset of quest battles have been tested - most of which are in the MSQ."))
{
base.Configuration.SinglePlayerDuties.RunSoloInstancesWithBossMod = value;
Save();
}
using (ImRaii.Disabled(!value))
{
ImGui.Spacing();
int currentItem = (int)base.Configuration.SinglePlayerDuties.RetryDifficulty;
ImGui.SetNextItemWidth(MathF.Min(ImGui.GetContentRegionAvail().X * 0.4f, 260f));
if (UiThemeUtils.ThemedCombo("Difficulty when retrying a failed quest battle", ref currentItem, _retryDifficulties, _retryDifficulties.Length))
{
base.Configuration.SinglePlayerDuties.RetryDifficulty = (Configuration.ERetryDifficulty)currentItem;
Save();
}
ImGui.SameLine();
UiThemeUtils.InfoIcon("Not all quest battles offer Easy or Very Easy difficulty.");
ImGui.Spacing();
int maxRetries = base.Configuration.SinglePlayerDuties.MaxRetries;
if (ImGui.RadioButton("Do not retry failed quest battles", maxRetries == 0))
{
base.Configuration.SinglePlayerDuties.MaxRetries = 0;
Save();
}
bool flag = maxRetries > 0;
if (ImGui.RadioButton("Retry", flag))
{
base.Configuration.SinglePlayerDuties.MaxRetries = Math.Max(1, maxRetries);
Save();
}
if (flag)
{
ImGui.SameLine();
ImGui.SetNextItemWidth(80f);
int data = maxRetries;
if (ImGui.InputInt("time(s)##retryCount", ref data, 1) && data >= 1)
{
base.Configuration.SinglePlayerDuties.MaxRetries = data;
Save();
}
}
if (ImGui.RadioButton("Retry indefinitely", maxRetries == -1))
{
base.Configuration.SinglePlayerDuties.MaxRetries = -1;
Save();
}
if (maxRetries == -1)
{
ImGui.SameLine();
UiThemeUtils.InfoIcon("Warning: Your gear may break if you retry endlessly!");
}
}
UiThemeUtils.EndCard(item, item2, item3);
UiThemeUtils.SectionSpacing();
using (ImRaii.Disabled(!value))
{
UiThemeUtils.SectionHeader("Quest Battle Overrides");
ImGui.Spacing();
(Vector2 ContentStartPos, float AvailableWidth, ImDrawListPtr DrawList) tuple2 = UiThemeUtils.BeginCard();
Vector2 item4 = tuple2.ContentStartPos;
float item5 = tuple2.AvailableWidth;
ImDrawListPtr item6 = tuple2.DrawList;
(int enabledCount, int totalCount) mainScenarioQuestCounts = GetMainScenarioQuestCounts();
int item7 = mainScenarioQuestCounts.enabledCount;
int item8 = mainScenarioQuestCounts.totalCount;
(int enabledCount, int totalCount) jobQuestCounts = GetJobQuestCounts();
int item9 = jobQuestCounts.enabledCount;
int item10 = jobQuestCounts.totalCount;
(int enabledCount, int totalCount) roleQuestCounts = GetRoleQuestCounts();
int item11 = roleQuestCounts.enabledCount;
int item12 = roleQuestCounts.totalCount;
(int enabledCount, int totalCount) otherQuestCounts = GetOtherQuestCounts();
int item13 = otherQuestCounts.enabledCount;
int item14 = otherQuestCounts.totalCount;
InlineArray4<string> buffer = default(InlineArray4<string>);
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray4<string>, string>(ref buffer, 0) = $"Main Scenario Quests ({item7}/{item8})";
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray4<string>, string>(ref buffer, 1) = $"Class/Job Quests ({item9}/{item10})";
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray4<string>, string>(ref buffer, 2) = $"Role Quests ({item11}/{item12})";
global::_003CPrivateImplementationDetails_003E.InlineArrayElementRef<InlineArray4<string>, string>(ref buffer, 3) = $"Other Quests ({item13}/{item14})";
ReadOnlySpan<string> labels = global::_003CPrivateImplementationDetails_003E.InlineArrayAsReadOnlySpan<InlineArray4<string>, string>(in buffer, 4);
_selectedTab = UiThemeUtils.DrawTabBar(labels, _selectedTab);
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - ImGui.GetStyle().ItemSpacing.Y);
switch (_selectedTab)
{
case 0:
DrawMainScenarioConfigTable();
break;
case 1:
DrawJobQuestConfigTable();
break;
case 2:
DrawRoleQuestConfigTable();
break;
case 3:
DrawOtherQuestConfigTable();
break;
}
DrawEnableAllButton();
ImGui.SameLine();
DrawClipboardButtons("qst:single:", base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds, base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds);
ImGui.SameLine();
if (UiThemeUtils.DestructiveButton(FontAwesomeIcon.Undo, "Reset to defaults"))
{
base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Clear();
base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Clear();
Save();
}
UiThemeUtils.EndCard(item4, item5, item6);
}
}
private void DrawMainScenarioConfigTable()
{
using ImRaii.ChildDisposable childDisposable = BeginChildArea();
if (!childDisposable)
{
return;
}
Dictionary<string, bool> headerStates = base.Configuration.SinglePlayerDuties.HeaderStates;
var (value, value2) = GetQuestBattleCounts(_startingCityBattles[EAetheryteLocation.Limsa]);
if (DrawPersistentAccordion($"Limsa Lominsa ({ConfigComponent.FormatLevel(5)} - {ConfigComponent.FormatLevel(14)})", $"{value}/{value2}", "Limsa", headerStates))
{
DrawQuestTable("LimsaLominsa", _startingCityBattles[EAetheryteLocation.Limsa]);
}
var (value3, value4) = GetQuestBattleCounts(_startingCityBattles[EAetheryteLocation.Gridania]);
if (DrawPersistentAccordion($"Gridania ({ConfigComponent.FormatLevel(5)} - {ConfigComponent.FormatLevel(14)})", $"{value3}/{value4}", "Gridania", headerStates))
{
DrawQuestTable("Gridania", _startingCityBattles[EAetheryteLocation.Gridania]);
}
var (value5, value6) = GetQuestBattleCounts(_startingCityBattles[EAetheryteLocation.Uldah]);
if (DrawPersistentAccordion($"Ul'dah ({ConfigComponent.FormatLevel(4)} - {ConfigComponent.FormatLevel(14)})", $"{value5}/{value6}", "Uldah", headerStates))
{
DrawQuestTable("Uldah", _startingCityBattles[EAetheryteLocation.Uldah]);
}
EExpansionVersion[] values = Enum.GetValues<EExpansionVersion>();
for (int i = 0; i < values.Length; i++)
{
EExpansionVersion eExpansionVersion = values[i];
if (_mainScenarioBattles.TryGetValue(eExpansionVersion, out List<SinglePlayerDutyInfo> value7))
{
var (value8, value9) = GetQuestBattleCounts(value7);
if (DrawPersistentAccordion(eExpansionVersion.ToFriendlyString(), $"{value8}/{value9}", eExpansionVersion.ToString(), headerStates))
{
DrawQuestTable($"Duties{eExpansionVersion}", value7);
}
}
}
}
private void DrawJobQuestConfigTable()
{
using ImRaii.ChildDisposable childDisposable = BeginChildArea();
if (!childDisposable)
{
return;
}
Dictionary<string, bool> headerStates = base.Configuration.SinglePlayerDuties.HeaderStates;
int num = 0;
foreach (var (eClassJob, num2) in _classJobUtils.SortedClassJobs)
{
if (!eClassJob.IsCrafter() && !eClassJob.IsGatherer() && _jobQuestBattles.TryGetValue(eClassJob, out List<SinglePlayerDutyInfo> value))
{
if (num2 != num)
{
num = num2;
ImGui.Spacing();
ImGui.Separator();
ImGui.Spacing();
}
string text = eClassJob.ToFriendlyString();
if (eClassJob.IsClass())
{
text = text + " / " + eClassJob.AsJob().ToFriendlyString();
}
var (value2, value3) = GetQuestBattleCounts(value);
if (DrawPersistentAccordion(text, $"{value2}/{value3}", eClassJob.ToString(), headerStates))
{
DrawQuestTable($"JobQuests{eClassJob}", value);
}
}
}
}
private void DrawRoleQuestConfigTable()
{
using ImRaii.ChildDisposable childDisposable = BeginChildArea();
if (!childDisposable)
{
return;
}
Dictionary<string, bool> headerStates = base.Configuration.SinglePlayerDuties.HeaderStates;
foreach (var (eClassJob, label) in RoleQuestCategories)
{
if (_roleQuestBattles.TryGetValue(eClassJob, out List<SinglePlayerDutyInfo> value))
{
var (value2, value3) = GetQuestBattleCounts(value);
if (DrawPersistentAccordion(label, $"{value2}/{value3}", $"Role_{eClassJob}", headerStates))
{
DrawQuestTable($"RoleQuests{eClassJob}", value);
}
}
}
var (value4, value5) = GetQuestBattleCounts(_otherRoleQuestBattles);
if (DrawPersistentAccordion("General Role Quests", $"{value4}/{value5}", "Role_General", headerStates))
{
DrawQuestTable("RoleQuestsGeneral", _otherRoleQuestBattles);
}
}
private void DrawOtherQuestConfigTable()
{
using ImRaii.ChildDisposable childDisposable = BeginChildArea();
if (!childDisposable)
{
return;
}
Dictionary<string, bool> headerStates = base.Configuration.SinglePlayerDuties.HeaderStates;
foreach (var (text, dutyInfos) in _otherQuestBattles)
{
var (value, value2) = GetQuestBattleCounts(dutyInfos);
if (DrawPersistentAccordion(text, $"{value}/{value2}", "Other_" + text, headerStates))
{
DrawQuestTable("Other" + text, dutyInfos);
}
}
}
private void DrawQuestTable(string label, IReadOnlyList<SinglePlayerDutyInfo> dutyInfos)
{
using ImRaii.TableDisposable tableDisposable = UiThemeUtils.BeginThemedTable(label, 2, ImGuiTableFlags.SizingFixedFit);
if (!(bool)tableDisposable)
{
return;
}
ImGui.TableSetupColumn("Quest", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Options", ImGuiTableColumnFlags.WidthFixed, 200f);
foreach (SinglePlayerDutyInfo dutyInfo in dutyInfos)
{
ImGui.TableNextRow();
string[] array = (dutyInfo.EnabledByDefault ? SupportedCfcOptions : UnsupportedCfcOptions);
int currentItem = 0;
if (base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Contains(dutyInfo.ContentFinderConditionId))
{
currentItem = 1;
}
if (base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Contains(dutyInfo.ContentFinderConditionId))
{
currentItem = 2;
}
if (ImGui.TableNextColumn())
{
ImGui.AlignTextToFramePadding();
float reservedRightWidth = ((!dutyInfo.Enabled || dutyInfo.Notes.Length != 0) ? (ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.X) : 0f);
UiThemeUtils.RowLabel(dutyInfo.Name, reservedRightWidth);
if (!dutyInfo.Enabled)
{
ImGui.SameLine();
using (ImRaii.PushFont(UiBuilder.IconFont))
{
ImGui.TextColored(in UiThemeUtils.StatusLocked, FontAwesomeIcon.Times.ToIconString());
}
if (ImGui.IsItemHovered())
{
using (ImRaii.Tooltip())
{
ImGui.PushTextWrapPos(400f);
ImGui.Text("Questionable doesn't include support for this quest.");
ImGui.PopTextWrapPos();
}
}
}
else if (dutyInfo.Notes.Length != 0)
{
ConfigComponent.DrawNotes(dutyInfo.EnabledByDefault, dutyInfo.Notes);
}
}
if (!ImGui.TableNextColumn())
{
continue;
}
ImU8String id = new ImU8String(6, 1);
id.AppendLiteral("##Duty");
id.AppendFormatted(dutyInfo.ContentFinderConditionId);
using (ImRaii.PushId(id))
{
using (ImRaii.Disabled(!dutyInfo.Enabled))
{
ImGui.SetNextItemWidth(-1f);
if (UiThemeUtils.ThemedCombo(string.Empty, ref currentItem, array, array.Length))
{
base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Remove(dutyInfo.ContentFinderConditionId);
base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Remove(dutyInfo.ContentFinderConditionId);
switch (currentItem)
{
case 1:
base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Add(dutyInfo.ContentFinderConditionId);
break;
case 2:
base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Add(dutyInfo.ContentFinderConditionId);
break;
}
Save();
}
}
}
}
}
private static ImRaii.ChildDisposable BeginChildArea()
{
Vector2 contentRegionAvail = ImGui.GetContentRegionAvail();
return ImRaii.Child("DutyConfiguration", new Vector2(contentRegionAvail.X, MathF.Max(contentRegionAvail.Y - 30f - 12f, 200f)), border: true);
}
private bool DrawPersistentAccordion(string label, string? rightText, string stateKey, Dictionary<string, bool> headerStates)
{
bool open = headerStates.GetValueOrDefault(stateKey, defaultValue: false);
UiThemeUtils.ThemedAccordion(stateKey, label, rightText, ref open);
if (open != headerStates.GetValueOrDefault(stateKey, defaultValue: false))
{
headerStates[stateKey] = open;
Save();
}
return open;
}
private void DrawEnableAllButton()
{
if (UiThemeUtils.IconTextButton(FontAwesomeIcon.CheckCircle, "Enable All"))
{
base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Clear();
base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Clear();
foreach (SinglePlayerDutyInfo allEnabledSinglePlayerDuty in GetAllEnabledSinglePlayerDuties())
{
base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Add(allEnabledSinglePlayerDuty.ContentFinderConditionId);
}
Save();
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Enable all of the quest battles, use at your own risk.");
}
}
private IEnumerable<SinglePlayerDutyInfo> GetAllEnabledSinglePlayerDuties()
{
return from x in _startingCityBattles.Values.SelectMany((List<SinglePlayerDutyInfo> x) => x).Concat(_mainScenarioBattles.Values.SelectMany((List<SinglePlayerDutyInfo> x) => x)).Concat(_jobQuestBattles.Values.SelectMany((List<SinglePlayerDutyInfo> x) => x))
.Concat(_roleQuestBattles.Values.SelectMany((List<SinglePlayerDutyInfo> x) => x))
.Concat(_otherRoleQuestBattles)
.Concat(_otherQuestBattles.SelectMany<(string, List<SinglePlayerDutyInfo>), SinglePlayerDutyInfo>(((string Label, List<SinglePlayerDutyInfo>) x) => x.Item2))
where x.Enabled
select x;
}
private (int enabledCount, int totalCount) GetQuestBattleCounts(IReadOnlyList<SinglePlayerDutyInfo> dutyInfos)
{
int num = 0;
int num2 = 0;
foreach (SinglePlayerDutyInfo dutyInfo in dutyInfos)
{
if (dutyInfo.Enabled)
{
num2++;
if (base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Contains(dutyInfo.ContentFinderConditionId) || (!base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Contains(dutyInfo.ContentFinderConditionId) && dutyInfo.EnabledByDefault))
{
num++;
}
}
}
return (enabledCount: num, totalCount: num2);
}
private (int enabledCount, int totalCount) GetMainScenarioQuestCounts()
{
int num = 0;
int num2 = 0;
foreach (List<SinglePlayerDutyInfo> value in _startingCityBattles.Values)
{
(int enabledCount, int totalCount) questBattleCounts = GetQuestBattleCounts(value);
int item = questBattleCounts.enabledCount;
int item2 = questBattleCounts.totalCount;
num += item;
num2 += item2;
}
foreach (List<SinglePlayerDutyInfo> value2 in _mainScenarioBattles.Values)
{
(int enabledCount, int totalCount) questBattleCounts2 = GetQuestBattleCounts(value2);
int item3 = questBattleCounts2.enabledCount;
int item4 = questBattleCounts2.totalCount;
num += item3;
num2 += item4;
}
return (enabledCount: num, totalCount: num2);
}
private (int enabledCount, int totalCount) GetJobQuestCounts()
{
int num = 0;
int num2 = 0;
foreach (List<SinglePlayerDutyInfo> value in _jobQuestBattles.Values)
{
(int enabledCount, int totalCount) questBattleCounts = GetQuestBattleCounts(value);
int item = questBattleCounts.enabledCount;
int item2 = questBattleCounts.totalCount;
num += item;
num2 += item2;
}
return (enabledCount: num, totalCount: num2);
}
private (int enabledCount, int totalCount) GetRoleQuestCounts()
{
int num = 0;
int num2 = 0;
foreach (List<SinglePlayerDutyInfo> value in _roleQuestBattles.Values)
{
(int enabledCount, int totalCount) questBattleCounts = GetQuestBattleCounts(value);
int item = questBattleCounts.enabledCount;
int item2 = questBattleCounts.totalCount;
num += item;
num2 += item2;
}
(int enabledCount, int totalCount) questBattleCounts2 = GetQuestBattleCounts(_otherRoleQuestBattles);
int item3 = questBattleCounts2.enabledCount;
int item4 = questBattleCounts2.totalCount;
num += item3;
num2 += item4;
return (enabledCount: num, totalCount: num2);
}
private (int enabledCount, int totalCount) GetOtherQuestCounts()
{
int num = 0;
int num2 = 0;
foreach (var otherQuestBattle in _otherQuestBattles)
{
List<SinglePlayerDutyInfo> item = otherQuestBattle.Item2;
(int enabledCount, int totalCount) questBattleCounts = GetQuestBattleCounts(item);
int item2 = questBattleCounts.enabledCount;
int item3 = questBattleCounts.totalCount;
num += item2;
num2 += item3;
}
return (enabledCount: num, totalCount: num2);
}
static SinglePlayerDutyConfigComponent()
{
int num = 5;
List<(EClassJob, string)> list = new List<(EClassJob, string)>(num);
CollectionsMarshal.SetCount(list, num);
Span<(EClassJob, string)> span = CollectionsMarshal.AsSpan(list);
span[0] = (EClassJob.Paladin, "Tank Role Quests");
span[1] = (EClassJob.WhiteMage, "Healer Role Quests");
span[2] = (EClassJob.Lancer, "Melee Role Quests");
span[3] = (EClassJob.Bard, "Physical Ranged Role Quests");
span[4] = (EClassJob.BlackMage, "Magical Ranged Role Quests");
RoleQuestCategories = list;
}
}