punish v6.8.18.0
This commit is contained in:
commit
cfb4dea47e
316 changed files with 554088 additions and 0 deletions
|
@ -0,0 +1,428 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Dalamud.Plugin;
|
||||
using Questionable.Controller;
|
||||
using Questionable.Data;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
using Questionable.Validation;
|
||||
using Questionable.Windows.QuestComponents;
|
||||
|
||||
namespace Questionable.Windows.JournalComponents;
|
||||
|
||||
internal sealed class QuestJournalComponent
|
||||
{
|
||||
private sealed record FilteredSection(JournalData.Section Section, List<FilteredCategory> Categories);
|
||||
|
||||
private sealed record FilteredCategory(JournalData.Category Category, List<FilteredGenre> Genres);
|
||||
|
||||
private sealed record FilteredGenre(JournalData.Genre Genre, List<IQuestInfo> Quests);
|
||||
|
||||
private sealed record JournalCounts(int Available, int Total, int Obtainable, int Completed)
|
||||
{
|
||||
public JournalCounts()
|
||||
: this(0, 0, 0, 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class FilterConfiguration
|
||||
{
|
||||
public string SearchText = string.Empty;
|
||||
|
||||
public bool AvailableOnly;
|
||||
|
||||
public bool HideNoPaths;
|
||||
|
||||
public bool AdvancedFiltersActive
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!AvailableOnly)
|
||||
{
|
||||
return HideNoPaths;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public FilterConfiguration WithoutName()
|
||||
{
|
||||
return new FilterConfiguration
|
||||
{
|
||||
AvailableOnly = AvailableOnly,
|
||||
HideNoPaths = HideNoPaths
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<JournalData.Genre, JournalCounts> _genreCounts = new Dictionary<JournalData.Genre, JournalCounts>();
|
||||
|
||||
private readonly Dictionary<JournalData.Category, JournalCounts> _categoryCounts = new Dictionary<JournalData.Category, JournalCounts>();
|
||||
|
||||
private readonly Dictionary<JournalData.Section, JournalCounts> _sectionCounts = new Dictionary<JournalData.Section, JournalCounts>();
|
||||
|
||||
private readonly JournalData _journalData;
|
||||
|
||||
private readonly QuestRegistry _questRegistry;
|
||||
|
||||
private readonly QuestFunctions _questFunctions;
|
||||
|
||||
private readonly UiUtils _uiUtils;
|
||||
|
||||
private readonly QuestTooltipComponent _questTooltipComponent;
|
||||
|
||||
private readonly IDalamudPluginInterface _pluginInterface;
|
||||
|
||||
private readonly QuestJournalUtils _questJournalUtils;
|
||||
|
||||
private readonly QuestValidator _questValidator;
|
||||
|
||||
private List<FilteredSection> _filteredSections = new List<FilteredSection>();
|
||||
|
||||
internal FilterConfiguration Filter { get; } = new FilterConfiguration();
|
||||
|
||||
public QuestJournalComponent(JournalData journalData, QuestRegistry questRegistry, QuestFunctions questFunctions, UiUtils uiUtils, QuestTooltipComponent questTooltipComponent, IDalamudPluginInterface pluginInterface, QuestJournalUtils questJournalUtils, QuestValidator questValidator)
|
||||
{
|
||||
_journalData = journalData;
|
||||
_questRegistry = questRegistry;
|
||||
_questFunctions = questFunctions;
|
||||
_uiUtils = uiUtils;
|
||||
_questTooltipComponent = questTooltipComponent;
|
||||
_pluginInterface = pluginInterface;
|
||||
_questJournalUtils = questJournalUtils;
|
||||
_questValidator = questValidator;
|
||||
}
|
||||
|
||||
public void DrawQuests()
|
||||
{
|
||||
using ImRaii.IEndObject endObject = ImRaii.TabItem("Quests");
|
||||
if (!endObject)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (ImGui.CollapsingHeader("Explanation", ImGuiTreeNodeFlags.DefaultOpen))
|
||||
{
|
||||
ImGui.Text("The list below contains all quests that appear in your journal.");
|
||||
ImGui.BulletText("'Supported' lists quests that Questionable can do for you");
|
||||
ImGui.BulletText("'Completed' lists quests your current character has completed.");
|
||||
ImGui.BulletText("Not all quests can be completed even if they're listed as available, e.g. starting city quest chains.");
|
||||
ImGui.Spacing();
|
||||
ImGui.Separator();
|
||||
ImGui.Spacing();
|
||||
}
|
||||
QuestJournalUtils.ShowFilterContextMenu(this);
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||
if (ImGui.InputTextWithHint(string.Empty, "Search quests and categories", ref Filter.SearchText, 256))
|
||||
{
|
||||
UpdateFilter();
|
||||
}
|
||||
if (_filteredSections.Count > 0)
|
||||
{
|
||||
using (ImRaii.IEndObject endObject2 = ImRaii.Table("Quests", 3, ImGuiTableFlags.NoSavedSettings))
|
||||
{
|
||||
if (!endObject2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.NoHide);
|
||||
ImGui.TableSetupColumn("Supported", ImGuiTableColumnFlags.WidthFixed, 120f * ImGui.GetIO().FontGlobalScale);
|
||||
ImGui.TableSetupColumn("Completed", ImGuiTableColumnFlags.WidthFixed, 120f * ImGui.GetIO().FontGlobalScale);
|
||||
ImGui.TableHeadersRow();
|
||||
foreach (FilteredSection filteredSection in _filteredSections)
|
||||
{
|
||||
DrawSection(filteredSection);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
ImGui.Text("No quest or category matches your search.");
|
||||
}
|
||||
|
||||
private void DrawSection(FilteredSection filter)
|
||||
{
|
||||
var (count, num5, total, count2) = _sectionCounts.GetValueOrDefault(filter.Section, new JournalCounts());
|
||||
if (num5 == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
bool num6 = ImGui.TreeNodeEx(filter.Section.Name, ImGuiTreeNodeFlags.SpanFullWidth);
|
||||
ImGui.TableNextColumn();
|
||||
DrawCount(count, num5);
|
||||
ImGui.TableNextColumn();
|
||||
DrawCount(count2, total);
|
||||
if (!num6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (FilteredCategory category in filter.Categories)
|
||||
{
|
||||
DrawCategory(category);
|
||||
}
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
private void DrawCategory(FilteredCategory filter)
|
||||
{
|
||||
var (count, num5, total, count2) = _categoryCounts.GetValueOrDefault(filter.Category, new JournalCounts());
|
||||
if (num5 == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
bool num6 = ImGui.TreeNodeEx(filter.Category.Name, ImGuiTreeNodeFlags.SpanFullWidth);
|
||||
ImGui.TableNextColumn();
|
||||
DrawCount(count, num5);
|
||||
ImGui.TableNextColumn();
|
||||
DrawCount(count2, total);
|
||||
if (!num6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (FilteredGenre genre in filter.Genres)
|
||||
{
|
||||
DrawGenre(genre);
|
||||
}
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
private void DrawGenre(FilteredGenre filter)
|
||||
{
|
||||
var (count, num5, total, count2) = _genreCounts.GetValueOrDefault(filter.Genre, new JournalCounts());
|
||||
if (num5 == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
bool num6 = ImGui.TreeNodeEx(filter.Genre.Name, ImGuiTreeNodeFlags.SpanFullWidth);
|
||||
ImGui.TableNextColumn();
|
||||
DrawCount(count, num5);
|
||||
ImGui.TableNextColumn();
|
||||
DrawCount(count2, total);
|
||||
if (!num6)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (IQuestInfo quest in filter.Quests)
|
||||
{
|
||||
DrawQuest(quest);
|
||||
}
|
||||
ImGui.TreePop();
|
||||
}
|
||||
|
||||
private void DrawQuest(IQuestInfo questInfo)
|
||||
{
|
||||
_questRegistry.TryGetQuest(questInfo.QuestId, out Quest quest);
|
||||
ImGui.TableNextRow();
|
||||
ImGui.TableNextColumn();
|
||||
ImU8String id = new ImU8String(3, 2);
|
||||
id.AppendFormatted(questInfo.Name);
|
||||
id.AppendLiteral(" (");
|
||||
id.AppendFormatted(questInfo.QuestId);
|
||||
id.AppendLiteral(")");
|
||||
ImGui.TreeNodeEx(id, ImGuiTreeNodeFlags.NoTreePushOnOpen | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.SpanFullWidth);
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
_questTooltipComponent.Draw(questInfo);
|
||||
}
|
||||
_questJournalUtils.ShowContextMenu(questInfo, quest, "QuestJournalComponent");
|
||||
ImGui.TableNextColumn();
|
||||
float num;
|
||||
using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
|
||||
{
|
||||
num = ImGui.GetColumnWidth() / 2f - ImGui.CalcTextSize(FontAwesomeIcon.Check.ToIconString()).X;
|
||||
}
|
||||
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + num);
|
||||
if (_questFunctions.IsQuestRemoved(questInfo.QuestId))
|
||||
{
|
||||
_uiUtils.ChecklistItem(string.Empty, ImGuiColors.DalamudGrey, FontAwesomeIcon.Minus);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (quest != null)
|
||||
{
|
||||
QuestRoot root = quest.Root;
|
||||
if (root != null && !root.Disabled)
|
||||
{
|
||||
List<ValidationIssue> issues = _questValidator.GetIssues(quest.Id);
|
||||
if (issues.Any((ValidationIssue x) => x.Severity == EIssueSeverity.Error))
|
||||
{
|
||||
_uiUtils.ChecklistItem(string.Empty, ImGuiColors.DalamudRed, FontAwesomeIcon.ExclamationTriangle);
|
||||
}
|
||||
else if (issues.Count > 0)
|
||||
{
|
||||
_uiUtils.ChecklistItem(string.Empty, ImGuiColors.ParsedBlue, FontAwesomeIcon.InfoCircle);
|
||||
}
|
||||
else
|
||||
{
|
||||
_uiUtils.ChecklistItem(string.Empty, complete: true);
|
||||
}
|
||||
goto IL_0215;
|
||||
}
|
||||
}
|
||||
_uiUtils.ChecklistItem(string.Empty, complete: false);
|
||||
}
|
||||
goto IL_0215;
|
||||
IL_0215:
|
||||
ImGui.TableNextColumn();
|
||||
var (color, icon, text) = _uiUtils.GetQuestStyle(questInfo.QuestId);
|
||||
_uiUtils.ChecklistItem(text, color, icon);
|
||||
}
|
||||
|
||||
private static void DrawCount(int count, int total)
|
||||
{
|
||||
string text = 9999.ToString(CultureInfo.CurrentCulture);
|
||||
ImGui.PushFont(UiBuilder.MonoFont);
|
||||
if (total == 0)
|
||||
{
|
||||
Vector4 col = ImGuiColors.DalamudGrey;
|
||||
ImU8String text2 = new ImU8String(3, 2);
|
||||
text2.AppendFormatted("-".PadLeft(text.Length));
|
||||
text2.AppendLiteral(" / ");
|
||||
text2.AppendFormatted("-".PadLeft(text.Length));
|
||||
ImGui.TextColored(in col, text2);
|
||||
}
|
||||
else
|
||||
{
|
||||
string text3 = count.ToString(CultureInfo.CurrentCulture).PadLeft(text.Length) + " / " + total.ToString(CultureInfo.CurrentCulture).PadLeft(text.Length);
|
||||
if (count == total)
|
||||
{
|
||||
ImGui.TextColored(ImGuiColors.ParsedGreen, text3);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextUnformatted(text3);
|
||||
}
|
||||
}
|
||||
ImGui.PopFont();
|
||||
}
|
||||
|
||||
public void UpdateFilter()
|
||||
{
|
||||
_filteredSections = (from x in _journalData.Sections
|
||||
select FilterSection(x, Filter) into x
|
||||
where x.Categories.Count > 0
|
||||
select x).ToList();
|
||||
RefreshCounts();
|
||||
}
|
||||
|
||||
private FilteredSection FilterSection(JournalData.Section section, FilterConfiguration filter)
|
||||
{
|
||||
IEnumerable<FilteredCategory> source = ((!IsCategorySectionGenreMatch(filter, section.Name)) ? section.Categories.Select((JournalData.Category category) => FilterCategory(category, filter)) : section.Categories.Select((JournalData.Category x) => FilterCategory(x, filter.WithoutName())));
|
||||
return new FilteredSection(section, source.Where((FilteredCategory x) => x.Genres.Count > 0).ToList());
|
||||
}
|
||||
|
||||
private FilteredCategory FilterCategory(JournalData.Category category, FilterConfiguration filter)
|
||||
{
|
||||
IEnumerable<FilteredGenre> source = ((!IsCategorySectionGenreMatch(filter, category.Name)) ? category.Genres.Select((JournalData.Genre genre) => FilterGenre(genre, filter)) : category.Genres.Select((JournalData.Genre x) => FilterGenre(x, filter.WithoutName())));
|
||||
return new FilteredCategory(category, source.Where((FilteredGenre x) => x.Quests.Count > 0).ToList());
|
||||
}
|
||||
|
||||
private FilteredGenre FilterGenre(JournalData.Genre genre, FilterConfiguration filter)
|
||||
{
|
||||
IEnumerable<IQuestInfo> source = ((!IsCategorySectionGenreMatch(filter, genre.Name)) ? genre.Quests.Where((IQuestInfo x) => IsQuestMatch(filter, x)) : genre.Quests.Where((IQuestInfo x) => IsQuestMatch(filter.WithoutName(), x)));
|
||||
return new FilteredGenre(genre, source.ToList());
|
||||
}
|
||||
|
||||
internal void RefreshCounts()
|
||||
{
|
||||
_genreCounts.Clear();
|
||||
_categoryCounts.Clear();
|
||||
_sectionCounts.Clear();
|
||||
foreach (JournalData.Genre genre in _journalData.Genres)
|
||||
{
|
||||
Quest quest;
|
||||
int available = genre.Quests.Count((IQuestInfo x) => _questRegistry.TryGetQuest(x.QuestId, out quest) && !quest.Root.Disabled && !_questFunctions.IsQuestRemoved(x.QuestId));
|
||||
int total = genre.Quests.Count((IQuestInfo x) => !_questFunctions.IsQuestRemoved(x.QuestId));
|
||||
int obtainable = genre.Quests.Count((IQuestInfo x) => !_questFunctions.IsQuestUnobtainable(x.QuestId));
|
||||
int completed = genre.Quests.Count((IQuestInfo x) => _questFunctions.IsQuestComplete(x.QuestId));
|
||||
_genreCounts[genre] = new JournalCounts(available, total, obtainable, completed);
|
||||
}
|
||||
foreach (JournalData.Category category in _journalData.Categories)
|
||||
{
|
||||
List<JournalCounts> source = (from x in _genreCounts
|
||||
where category.Genres.Contains(x.Key)
|
||||
select x.Value).ToList();
|
||||
int available2 = source.Sum((JournalCounts x) => x.Available);
|
||||
int total2 = source.Sum((JournalCounts x) => x.Total);
|
||||
int obtainable2 = source.Sum((JournalCounts x) => x.Obtainable);
|
||||
int completed2 = source.Sum((JournalCounts x) => x.Completed);
|
||||
_categoryCounts[category] = new JournalCounts(available2, total2, obtainable2, completed2);
|
||||
}
|
||||
foreach (JournalData.Section section in _journalData.Sections)
|
||||
{
|
||||
List<JournalCounts> source2 = (from x in _categoryCounts
|
||||
where section.Categories.Contains(x.Key)
|
||||
select x.Value).ToList();
|
||||
int available3 = source2.Sum((JournalCounts x) => x.Available);
|
||||
int total3 = source2.Sum((JournalCounts x) => x.Total);
|
||||
int obtainable3 = source2.Sum((JournalCounts x) => x.Obtainable);
|
||||
int completed3 = source2.Sum((JournalCounts x) => x.Completed);
|
||||
_sectionCounts[section] = new JournalCounts(available3, total3, obtainable3, completed3);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ClearCounts(int type, int code)
|
||||
{
|
||||
foreach (KeyValuePair<JournalData.Genre, JournalCounts> item in _genreCounts.ToList())
|
||||
{
|
||||
_genreCounts[item.Key] = item.Value with
|
||||
{
|
||||
Completed = 0
|
||||
};
|
||||
}
|
||||
foreach (KeyValuePair<JournalData.Category, JournalCounts> item2 in _categoryCounts.ToList())
|
||||
{
|
||||
_categoryCounts[item2.Key] = item2.Value with
|
||||
{
|
||||
Completed = 0
|
||||
};
|
||||
}
|
||||
foreach (KeyValuePair<JournalData.Section, JournalCounts> item3 in _sectionCounts.ToList())
|
||||
{
|
||||
_sectionCounts[item3.Key] = item3.Value with
|
||||
{
|
||||
Completed = 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsCategorySectionGenreMatch(FilterConfiguration filter, string name)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filter.SearchText))
|
||||
{
|
||||
return name.Contains(filter.SearchText, StringComparison.CurrentCultureIgnoreCase);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsQuestMatch(FilterConfiguration filter, IQuestInfo questInfo)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(filter.SearchText) && !questInfo.Name.Contains(filter.SearchText, StringComparison.CurrentCultureIgnoreCase) && !(questInfo.QuestId.ToString() == filter.SearchText))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (filter.AvailableOnly && !_questFunctions.IsReadyToAcceptQuest(questInfo.QuestId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (filter.HideNoPaths && (!_questRegistry.TryGetQuest(questInfo.QuestId, out Quest quest) || quest.Root.Disabled))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue