916 lines
35 KiB
C#
916 lines
35 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Collections.ObjectModel;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Runtime.InteropServices;
|
|
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 LLib.GameData;
|
|
using Lumina.Excel.Sheets;
|
|
using Microsoft.Extensions.Logging;
|
|
using Questionable.Controller;
|
|
using Questionable.Data;
|
|
using Questionable.Model;
|
|
using Questionable.Model.Common;
|
|
using Questionable.Model.Questing;
|
|
|
|
namespace Questionable.Windows.ConfigComponents;
|
|
|
|
internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
|
{
|
|
private sealed record SinglePlayerDutyInfo(string Name, IQuestInfo QuestInfo, TerritoryData.ContentFinderConditionData ContentFinderConditionData, SinglePlayerDutyOptions Options, 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 byte Index => Options.Index;
|
|
|
|
public bool EnabledByDefault => Options.Enabled;
|
|
|
|
public ReadOnlyCollection<string> Notes => Options.Notes.AsReadOnly();
|
|
|
|
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 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;
|
|
|
|
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;
|
|
}
|
|
|
|
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 Enabled, SinglePlayerDutyOptions Options) tuple = FindDutyOptions(item, item2);
|
|
bool item4 = tuple.Enabled;
|
|
SinglePlayerDutyOptions item5 = tuple.Options;
|
|
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 {item5.Index + 1})";
|
|
}
|
|
else
|
|
{
|
|
uint contentFinderConditionId = item3.ContentFinderConditionId;
|
|
if ((contentFinderConditionId == 674 || contentFinderConditionId == 691) ? true : false)
|
|
{
|
|
text += " (Melee/Phys. Ranged)";
|
|
}
|
|
}
|
|
SinglePlayerDutyInfo singlePlayerDutyInfo = new SinglePlayerDutyInfo(text, questInfo, item3, item5, 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 item6 in value2)
|
|
{
|
|
dictionary5[item6].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 Enabled, SinglePlayerDutyOptions Options) FindDutyOptions(ElementId questId, byte index)
|
|
{
|
|
SinglePlayerDutyOptions singlePlayerDutyOptions = new SinglePlayerDutyOptions
|
|
{
|
|
Index = 0,
|
|
Enabled = false
|
|
};
|
|
if (_questRegistry.TryGetQuest(questId, out Questionable.Model.Quest quest))
|
|
{
|
|
if (quest.Root.Disabled)
|
|
{
|
|
_logger.LogDebug("Disabling quest battle for quest {QuestId}, quest is disabled", questId);
|
|
return (Enabled: false, Options: singlePlayerDutyOptions);
|
|
}
|
|
QuestStep questStep = (from x in quest.AllSteps()
|
|
select x.Step).FirstOrDefault((QuestStep x) => x.InteractionType == EInteractionType.SinglePlayerDuty && x.SinglePlayerDutyIndex == index);
|
|
if (questStep == null)
|
|
{
|
|
_logger.LogWarning("Disabling quest battle for quest {QuestId}, no battle with index {Index} found", questId, index);
|
|
return (Enabled: false, Options: singlePlayerDutyOptions);
|
|
}
|
|
return (Enabled: true, Options: questStep.SinglePlayerDutyOptions ?? singlePlayerDutyOptions);
|
|
}
|
|
_logger.LogDebug("Disabling quest battle for quest {QuestId}, unknown quest", questId);
|
|
return (Enabled: false, Options: singlePlayerDutyOptions);
|
|
}
|
|
|
|
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()
|
|
{
|
|
using ImRaii.IEndObject endObject = ImRaii.TabItem("Quest Battles###QuestBattles");
|
|
if (!endObject)
|
|
{
|
|
return;
|
|
}
|
|
bool v = base.Configuration.SinglePlayerDuties.RunSoloInstancesWithBossMod;
|
|
if (ImGui.Checkbox("Run quest battles with BossMod", ref v))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.RunSoloInstancesWithBossMod = v;
|
|
Save();
|
|
}
|
|
using (ImRaii.PushIndent(ImGui.GetFrameHeight() + ImGui.GetStyle().ItemInnerSpacing.X))
|
|
{
|
|
using (ImRaii.PushColor(ImGuiCol.Text, ImGuiColors.DalamudRed))
|
|
{
|
|
ImGui.TextUnformatted("Work in Progress:");
|
|
ImGui.BulletText("Will always use BossMod for combat (ignoring the configured combat module).");
|
|
ImGui.BulletText("Only a small subset of quest battles have been tested - most of which are in the MSQ.");
|
|
ImGui.BulletText("When retrying a failed battle, it will always start at 'Normal' difficulty.");
|
|
ImGui.BulletText("Please don't enable this option when using a BossMod fork (such as Reborn);\nwith the missing combat module configuration, it is unlikely to be compatible.");
|
|
}
|
|
}
|
|
ImGui.Separator();
|
|
using (ImRaii.Disabled(!v))
|
|
{
|
|
ImGui.Text("Questionable includes a default list of quest battles that work if BossMod is installed.");
|
|
ImGui.Text("The included list of quest battles can change with each update.");
|
|
ImGui.Separator();
|
|
ImGui.Text("You can override the settings for each individual quest battle:");
|
|
using ImRaii.IEndObject endObject2 = ImRaii.TabBar("QuestionableConfigTabs");
|
|
if (endObject2)
|
|
{
|
|
DrawMainScenarioConfigTable();
|
|
DrawJobQuestConfigTable();
|
|
DrawRoleQuestConfigTable();
|
|
DrawOtherQuestConfigTable();
|
|
}
|
|
DrawEnableAllButton();
|
|
ImGui.SameLine();
|
|
DrawClipboardButtons();
|
|
ImGui.SameLine();
|
|
DrawResetButton();
|
|
}
|
|
}
|
|
|
|
private void DrawMainScenarioConfigTable()
|
|
{
|
|
(int enabledCount, int totalCount) mainScenarioQuestCounts = GetMainScenarioQuestCounts();
|
|
int item = mainScenarioQuestCounts.enabledCount;
|
|
int item2 = mainScenarioQuestCounts.totalCount;
|
|
ImU8String label = new ImU8String(30, 2);
|
|
label.AppendLiteral("Main Scenario Quests (");
|
|
label.AppendFormatted(item);
|
|
label.AppendLiteral("/");
|
|
label.AppendFormatted(item2);
|
|
label.AppendLiteral(")###MSQ");
|
|
using ImRaii.IEndObject endObject = ImRaii.TabItem(label);
|
|
if (!endObject)
|
|
{
|
|
return;
|
|
}
|
|
using ImRaii.IEndObject endObject2 = BeginChildArea();
|
|
if (!endObject2)
|
|
{
|
|
return;
|
|
}
|
|
(int enabledCount, int totalCount) questBattleCounts = GetQuestBattleCounts(_startingCityBattles[EAetheryteLocation.Limsa]);
|
|
int item3 = questBattleCounts.enabledCount;
|
|
int item4 = questBattleCounts.totalCount;
|
|
string obj = $"Limsa Lominsa ({ConfigComponent.FormatLevel(5)} - {ConfigComponent.FormatLevel(14)}) ({item3}/{item4})";
|
|
string key = "Limsa";
|
|
ImGui.SetNextItemOpen(base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false), ImGuiCond.Always);
|
|
if (ImGui.CollapsingHeader(obj))
|
|
{
|
|
if (!base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key] = true;
|
|
Save();
|
|
}
|
|
DrawQuestTable("LimsaLominsa", _startingCityBattles[EAetheryteLocation.Limsa]);
|
|
}
|
|
else if (base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key] = false;
|
|
Save();
|
|
}
|
|
(int enabledCount, int totalCount) questBattleCounts2 = GetQuestBattleCounts(_startingCityBattles[EAetheryteLocation.Gridania]);
|
|
int item5 = questBattleCounts2.enabledCount;
|
|
int item6 = questBattleCounts2.totalCount;
|
|
string obj2 = $"Gridania ({ConfigComponent.FormatLevel(5)} - {ConfigComponent.FormatLevel(14)}) ({item5}/{item6})";
|
|
string key2 = "Gridania";
|
|
ImGui.SetNextItemOpen(base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key2, defaultValue: false), ImGuiCond.Always);
|
|
if (ImGui.CollapsingHeader(obj2))
|
|
{
|
|
if (!base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key2, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key2] = true;
|
|
Save();
|
|
}
|
|
DrawQuestTable("Gridania", _startingCityBattles[EAetheryteLocation.Gridania]);
|
|
}
|
|
else if (base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key2, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key2] = false;
|
|
Save();
|
|
}
|
|
(int enabledCount, int totalCount) questBattleCounts3 = GetQuestBattleCounts(_startingCityBattles[EAetheryteLocation.Uldah]);
|
|
int item7 = questBattleCounts3.enabledCount;
|
|
int item8 = questBattleCounts3.totalCount;
|
|
string obj3 = $"Ul'dah ({ConfigComponent.FormatLevel(4)} - {ConfigComponent.FormatLevel(14)}) ({item7}/{item8})";
|
|
string key3 = "Uldah";
|
|
ImGui.SetNextItemOpen(base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key3, defaultValue: false), ImGuiCond.Always);
|
|
if (ImGui.CollapsingHeader(obj3))
|
|
{
|
|
if (!base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key3, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key3] = true;
|
|
Save();
|
|
}
|
|
DrawQuestTable("Uldah", _startingCityBattles[EAetheryteLocation.Uldah]);
|
|
}
|
|
else if (base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key3, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key3] = false;
|
|
Save();
|
|
}
|
|
EExpansionVersion[] values = Enum.GetValues<EExpansionVersion>();
|
|
for (int i = 0; i < values.Length; i++)
|
|
{
|
|
EExpansionVersion eExpansionVersion = values[i];
|
|
if (!_mainScenarioBattles.TryGetValue(eExpansionVersion, out List<SinglePlayerDutyInfo> value))
|
|
{
|
|
continue;
|
|
}
|
|
(int enabledCount, int totalCount) questBattleCounts4 = GetQuestBattleCounts(value);
|
|
int item9 = questBattleCounts4.enabledCount;
|
|
int item10 = questBattleCounts4.totalCount;
|
|
string obj4 = $"{eExpansionVersion.ToFriendlyString()} ({item9}/{item10})";
|
|
string key4 = eExpansionVersion.ToString();
|
|
ImGui.SetNextItemOpen(base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key4, defaultValue: false), ImGuiCond.Always);
|
|
if (ImGui.CollapsingHeader(obj4))
|
|
{
|
|
if (!base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key4, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key4] = true;
|
|
Save();
|
|
}
|
|
DrawQuestTable($"Duties{eExpansionVersion}", value);
|
|
}
|
|
else if (base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key4, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key4] = false;
|
|
Save();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawJobQuestConfigTable()
|
|
{
|
|
(int enabledCount, int totalCount) jobQuestCounts = GetJobQuestCounts();
|
|
int item = jobQuestCounts.enabledCount;
|
|
int item2 = jobQuestCounts.totalCount;
|
|
ImU8String label = new ImU8String(32, 2);
|
|
label.AppendLiteral("Class/Job Quests (");
|
|
label.AppendFormatted(item);
|
|
label.AppendLiteral("/");
|
|
label.AppendFormatted(item2);
|
|
label.AppendLiteral(")###JobQuests");
|
|
using ImRaii.IEndObject endObject = ImRaii.TabItem(label);
|
|
if (!endObject)
|
|
{
|
|
return;
|
|
}
|
|
using ImRaii.IEndObject endObject2 = BeginChildArea();
|
|
if (!endObject2)
|
|
{
|
|
return;
|
|
}
|
|
int num = 0;
|
|
foreach (var (eClassJob, num2) in _classJobUtils.SortedClassJobs)
|
|
{
|
|
if (eClassJob.IsCrafter() || eClassJob.IsGatherer() || !_jobQuestBattles.TryGetValue(eClassJob, out List<SinglePlayerDutyInfo> value))
|
|
{
|
|
continue;
|
|
}
|
|
if (num2 != num)
|
|
{
|
|
num = num2;
|
|
ImGui.Spacing();
|
|
ImGui.Separator();
|
|
ImGui.Spacing();
|
|
}
|
|
string text = eClassJob.ToFriendlyString();
|
|
if (eClassJob.IsClass())
|
|
{
|
|
text = text + " / " + eClassJob.AsJob().ToFriendlyString();
|
|
}
|
|
(int enabledCount, int totalCount) questBattleCounts = GetQuestBattleCounts(value);
|
|
int item3 = questBattleCounts.enabledCount;
|
|
int item4 = questBattleCounts.totalCount;
|
|
string obj = $"{text} ({item3}/{item4})";
|
|
string key = eClassJob.ToString();
|
|
ImGui.SetNextItemOpen(base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false), ImGuiCond.Always);
|
|
if (ImGui.CollapsingHeader(obj))
|
|
{
|
|
if (!base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key] = true;
|
|
Save();
|
|
}
|
|
DrawQuestTable($"JobQuests{eClassJob}", value);
|
|
}
|
|
else if (base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key] = false;
|
|
Save();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawRoleQuestConfigTable()
|
|
{
|
|
(int enabledCount, int totalCount) roleQuestCounts = GetRoleQuestCounts();
|
|
int item = roleQuestCounts.enabledCount;
|
|
int item2 = roleQuestCounts.totalCount;
|
|
ImU8String label = new ImU8String(28, 2);
|
|
label.AppendLiteral("Role Quests (");
|
|
label.AppendFormatted(item);
|
|
label.AppendLiteral("/");
|
|
label.AppendFormatted(item2);
|
|
label.AppendLiteral(")###RoleQuests");
|
|
using ImRaii.IEndObject endObject = ImRaii.TabItem(label);
|
|
if (!endObject)
|
|
{
|
|
return;
|
|
}
|
|
using ImRaii.IEndObject endObject2 = BeginChildArea();
|
|
if (!endObject2)
|
|
{
|
|
return;
|
|
}
|
|
foreach (var (eClassJob, value) in RoleQuestCategories)
|
|
{
|
|
if (!_roleQuestBattles.TryGetValue(eClassJob, out List<SinglePlayerDutyInfo> value2))
|
|
{
|
|
continue;
|
|
}
|
|
(int enabledCount, int totalCount) questBattleCounts = GetQuestBattleCounts(value2);
|
|
int item3 = questBattleCounts.enabledCount;
|
|
int item4 = questBattleCounts.totalCount;
|
|
string obj = $"{value} ({item3}/{item4})";
|
|
string key = $"Role_{eClassJob}";
|
|
ImGui.SetNextItemOpen(base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false), ImGuiCond.Always);
|
|
if (ImGui.CollapsingHeader(obj))
|
|
{
|
|
if (!base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key] = true;
|
|
Save();
|
|
}
|
|
DrawQuestTable($"RoleQuests{eClassJob}", value2);
|
|
}
|
|
else if (base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key] = false;
|
|
Save();
|
|
}
|
|
}
|
|
(int enabledCount, int totalCount) questBattleCounts2 = GetQuestBattleCounts(_otherRoleQuestBattles);
|
|
int item5 = questBattleCounts2.enabledCount;
|
|
int item6 = questBattleCounts2.totalCount;
|
|
string obj2 = $"General Role Quests ({item5}/{item6})";
|
|
string key2 = "Role_General";
|
|
ImGui.SetNextItemOpen(base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key2, defaultValue: false), ImGuiCond.Always);
|
|
if (ImGui.CollapsingHeader(obj2))
|
|
{
|
|
if (!base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key2, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key2] = true;
|
|
Save();
|
|
}
|
|
DrawQuestTable("RoleQuestsGeneral", _otherRoleQuestBattles);
|
|
}
|
|
else if (base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key2, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key2] = false;
|
|
Save();
|
|
}
|
|
}
|
|
|
|
private void DrawOtherQuestConfigTable()
|
|
{
|
|
(int enabledCount, int totalCount) otherQuestCounts = GetOtherQuestCounts();
|
|
int item = otherQuestCounts.enabledCount;
|
|
int item2 = otherQuestCounts.totalCount;
|
|
ImU8String label = new ImU8String(29, 2);
|
|
label.AppendLiteral("Other Quests (");
|
|
label.AppendFormatted(item);
|
|
label.AppendLiteral("/");
|
|
label.AppendFormatted(item2);
|
|
label.AppendLiteral(")###MiscQuests");
|
|
using ImRaii.IEndObject endObject = ImRaii.TabItem(label);
|
|
if (!endObject)
|
|
{
|
|
return;
|
|
}
|
|
using ImRaii.IEndObject endObject2 = BeginChildArea();
|
|
if (!endObject2)
|
|
{
|
|
return;
|
|
}
|
|
foreach (var otherQuestBattle in _otherQuestBattles)
|
|
{
|
|
string item3 = otherQuestBattle.Label;
|
|
List<SinglePlayerDutyInfo> item4 = otherQuestBattle.Item2;
|
|
(int enabledCount, int totalCount) questBattleCounts = GetQuestBattleCounts(item4);
|
|
int item5 = questBattleCounts.enabledCount;
|
|
int item6 = questBattleCounts.totalCount;
|
|
string obj = $"{item3} ({item5}/{item6})";
|
|
string key = "Other_" + item3;
|
|
ImGui.SetNextItemOpen(base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false), ImGuiCond.Always);
|
|
if (ImGui.CollapsingHeader(obj))
|
|
{
|
|
if (!base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key] = true;
|
|
Save();
|
|
}
|
|
DrawQuestTable("Other" + item3, item4);
|
|
}
|
|
else if (base.Configuration.SinglePlayerDuties.HeaderStates.GetValueOrDefault(key, defaultValue: false))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.HeaderStates[key] = false;
|
|
Save();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawQuestTable(string label, IReadOnlyList<SinglePlayerDutyInfo> dutyInfos)
|
|
{
|
|
using ImRaii.IEndObject endObject = ImRaii.Table(label, 2, ImGuiTableFlags.SizingFixedFit);
|
|
if (!ImRaii.IEndObject.op_True(endObject))
|
|
{
|
|
return;
|
|
}
|
|
ImGui.TableSetupColumn("Quest", ImGuiTableColumnFlags.WidthStretch);
|
|
ImGui.TableSetupColumn("Options", ImGuiTableColumnFlags.WidthFixed, 200f);
|
|
foreach (SinglePlayerDutyInfo dutyInfo in dutyInfos)
|
|
{
|
|
ImGui.TableNextRow();
|
|
string[] items = (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;
|
|
}
|
|
ImU8String text;
|
|
if (ImGui.TableNextColumn())
|
|
{
|
|
ImGui.AlignTextToFramePadding();
|
|
ImGui.TextUnformatted(dutyInfo.Name);
|
|
if (ImGui.IsItemHovered() && base.Configuration.Advanced.AdditionalStatusInformation)
|
|
{
|
|
using ImRaii.IEndObject endObject2 = ImRaii.Tooltip();
|
|
if (endObject2)
|
|
{
|
|
ImGui.TextUnformatted(dutyInfo.Name);
|
|
ImGui.Separator();
|
|
text = new ImU8String(13, 1);
|
|
text.AppendLiteral("TerritoryId: ");
|
|
text.AppendFormatted(dutyInfo.TerritoryId);
|
|
ImGui.BulletText(text);
|
|
text = new ImU8String(26, 1);
|
|
text.AppendLiteral("ContentFinderConditionId: ");
|
|
text.AppendFormatted(dutyInfo.ContentFinderConditionId);
|
|
ImGui.BulletText(text);
|
|
}
|
|
}
|
|
if (!dutyInfo.Enabled)
|
|
{
|
|
ImGuiComponents.HelpMarker("Questionable doesn't include support for this quest.", FontAwesomeIcon.Times, ImGuiColors.DalamudRed);
|
|
}
|
|
else if (dutyInfo.Notes.Count > 0)
|
|
{
|
|
ConfigComponent.DrawNotes(dutyInfo.EnabledByDefault, dutyInfo.Notes);
|
|
}
|
|
}
|
|
if (!ImGui.TableNextColumn())
|
|
{
|
|
continue;
|
|
}
|
|
text = new ImU8String(6, 1);
|
|
text.AppendLiteral("##Duty");
|
|
text.AppendFormatted(dutyInfo.ContentFinderConditionId);
|
|
using (ImRaii.PushId(text))
|
|
{
|
|
using (ImRaii.Disabled(!dutyInfo.Enabled))
|
|
{
|
|
ImGui.SetNextItemWidth(200f);
|
|
if (ImGui.Combo(string.Empty, ref currentItem, in items, items.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.IEndObject BeginChildArea()
|
|
{
|
|
return ImRaii.Child("DutyConfiguration", new Vector2(675f, 400f), border: true);
|
|
}
|
|
|
|
private void DrawEnableAllButton()
|
|
{
|
|
if (ImGuiComponents.IconButtonWithText(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 void DrawClipboardButtons()
|
|
{
|
|
using (ImRaii.Disabled(base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Count + base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Count == 0))
|
|
{
|
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Copy, "Export to clipboard"))
|
|
{
|
|
IEnumerable<string> first = base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Select((uint x) => $"{"+"}{x}");
|
|
IEnumerable<string> second = base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Select((uint x) => $"{"-"}{x}");
|
|
ImGui.SetClipboardText("qst:single:" + 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:single:", StringComparison.InvariantCulture)))
|
|
{
|
|
if (!ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Paste, "Import from Clipboard"))
|
|
{
|
|
return;
|
|
}
|
|
text = text.Substring("qst:single:".Length);
|
|
string text2 = Encoding.UTF8.GetString(Convert.FromBase64String(text));
|
|
base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Clear();
|
|
base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.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.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Add(result);
|
|
}
|
|
if (text3.StartsWith("-", StringComparison.InvariantCulture) && uint.TryParse(text3.AsSpan("-".Length), CultureInfo.InvariantCulture, out var result2))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Add(result2);
|
|
}
|
|
}
|
|
Save();
|
|
}
|
|
}
|
|
|
|
private void DrawResetButton()
|
|
{
|
|
using (ImRaii.Disabled(!ImGui.IsKeyDown(ImGuiKey.ModCtrl)))
|
|
{
|
|
if (ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Undo, "Reset to default"))
|
|
{
|
|
base.Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Clear();
|
|
base.Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Clear();
|
|
Save();
|
|
}
|
|
}
|
|
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
|
{
|
|
ImGui.SetTooltip("Hold CTRL to enable this button.");
|
|
}
|
|
}
|
|
|
|
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);
|
|
int num2 = 0;
|
|
span[num2] = (EClassJob.Paladin, "Tank Role Quests");
|
|
num2++;
|
|
span[num2] = (EClassJob.WhiteMage, "Healer Role Quests");
|
|
num2++;
|
|
span[num2] = (EClassJob.Lancer, "Melee Role Quests");
|
|
num2++;
|
|
span[num2] = (EClassJob.Bard, "Physical Ranged Role Quests");
|
|
num2++;
|
|
span[num2] = (EClassJob.BlackMage, "Magical Ranged Role Quests");
|
|
RoleQuestCategories = list;
|
|
}
|
|
}
|