qstbak/Questionable/Questionable.Windows.QuestComponents/QuestSequenceComponent.cs
2026-08-17 20:29:32 +10:00

736 lines
29 KiB
C#

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.Components;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Services;
using Lumina.Excel.Sheets;
using Microsoft.Extensions.Logging;
using Questionable.Controller;
using Questionable.Data;
using Questionable.Functions;
using Questionable.Model;
using Questionable.Model.Questing;
namespace Questionable.Windows.QuestComponents;
internal sealed class QuestSequenceComponent
{
private readonly QuestData _questData;
private readonly QuestRegistry _questRegistry;
private readonly QuestPriorityResolver _priorityResolver;
private readonly QuestFunctions _questFunctions;
private readonly IDataManager _dataManager;
private readonly ILogger<QuestSequenceComponent> _logger;
private string _questLookupInput = string.Empty;
private ElementId? _lookedUpQuestId;
private int _hoveredSequenceId = -1;
public bool HasLookedUpQuest => _lookedUpQuestId != null;
public QuestSequenceComponent(QuestData questData, QuestRegistry questRegistry, QuestPriorityResolver priorityResolver, QuestFunctions questFunctions, IDataManager dataManager, ILogger<QuestSequenceComponent> logger)
{
_questData = questData;
_questRegistry = questRegistry;
_priorityResolver = priorityResolver;
_questFunctions = questFunctions;
_dataManager = dataManager;
_logger = logger;
}
public static void DrawCustomHeader(ref bool isOpen)
{
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
float x = ImGui.GetContentRegionAvail().X;
float num = ImGui.GetFrameHeightWithSpacing() + ImGui.GetStyle().ItemSpacing.Y * 1.5f;
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
windowDrawList.AddRectFilledMultiColor(cursorScreenPos, cursorScreenPos + new Vector2(x, num), ImGui.ColorConvertFloat4ToU32(new Vector4(0.22f, 0.2f, 0.28f, 0.85f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.18f, 0.16f, 0.24f, 0.85f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.18f, 0.16f, 0.24f, 0.85f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.22f, 0.2f, 0.28f, 0.85f)));
Vector2 p = cursorScreenPos + new Vector2(0f, num);
Vector2 p2 = cursorScreenPos + new Vector2(x, num);
Vector4 accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.5f;
windowDrawList.AddLine(p, p2, ImGui.ColorConvertFloat4ToU32(accentColor), 2f);
float textLineHeight = ImGui.GetTextLineHeight();
float num2 = (num - textLineHeight) * 0.5f;
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + num2);
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + 10f);
ImGui.TextColored(in UiThemeUtils.PrimaryTextColor, "Quest Sequence Viewer");
ImGui.SameLine(x - 35f);
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - num2 + ImGui.GetStyle().ItemSpacing.Y);
using (ImRaii.PushColor(ImGuiCol.Button, Vector4.Zero))
{
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, new Vector4(0.8f, 0.3f, 0.3f, 0.4f)))
{
using (ImRaii.PushColor(ImGuiCol.ButtonActive, new Vector4(0.9f, 0.2f, 0.2f, 0.6f)))
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.Times))
{
isOpen = false;
}
}
}
}
ImGui.SetCursorPosY(cursorScreenPos.Y + num - ImGui.GetCursorScreenPos().Y + ImGui.GetCursorPosY());
}
public static void DrawWindowBorder()
{
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
Vector2 windowPos = ImGui.GetWindowPos();
Vector2 windowSize = ImGui.GetWindowSize();
Vector2 pMin = windowPos - new Vector2(1f, 1f);
Vector2 pMax = windowPos + windowSize + new Vector2(1f, 1f);
Vector4 accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.15f;
windowDrawList.AddRect(pMin, pMax, ImGui.ColorConvertFloat4ToU32(accentColor), 5f, ImDrawFlags.None, 3f);
Vector2 pMax2 = windowPos + windowSize;
accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.4f;
windowDrawList.AddRect(windowPos, pMax2, ImGui.ColorConvertFloat4ToU32(accentColor), 4f, ImDrawFlags.None, 1.5f);
}
public void DrawCurrentQuestTab()
{
QuestReference currentQuest = _priorityResolver.GetCurrentQuest();
ElementId elementId = currentQuest.CurrentQuest;
byte? currentSequence = currentQuest.Sequence;
if (elementId == null)
{
(QuestId, byte)? currentQuestWithoutPath = _questFunctions.GetCurrentQuestWithoutPath();
if (currentQuestWithoutPath.HasValue)
{
(QuestId, byte) valueOrDefault = currentQuestWithoutPath.GetValueOrDefault();
elementId = valueOrDefault.Item1;
currentSequence = valueOrDefault.Item2;
}
}
if (elementId != null)
{
DrawQuestSequences(elementId, currentSequence);
}
else
{
Vector4 accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.7f;
DrawEmptyState(FontAwesomeIcon.QuestionCircle, "No Active Quest", "Accept a quest to view its sequence information.", accentColor);
}
if (!(elementId is QuestId questId))
{
return;
}
ImGui.Spacing();
if (ImGui.Button("Copy filename"))
{
if (_questData.TryGetQuestInfo(questId, out IQuestInfo questInfo))
{
ImGui.SetClipboardText(GetSequenceFilename(questId.Value, questInfo.Name));
}
else
{
ImGui.SetClipboardText(GetSequenceFilename(questId.Value, questId.Value.ToString(CultureInfo.InvariantCulture)));
}
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Copies filename as QuestID_QuestNameWithSpaces.json");
}
}
public void DrawQuestLookupTab()
{
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
float y = ImGui.GetFrameHeightWithSpacing() + ImGui.GetStyle().ItemSpacing.Y * 3f;
float x = ImGui.GetContentRegionAvail().X;
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
windowDrawList.AddRectFilledMultiColor(cursorScreenPos, cursorScreenPos + new Vector2(x, y), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor));
Vector2 pMax = cursorScreenPos + new Vector2(x, y);
Vector4 accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.2f;
windowDrawList.AddRect(cursorScreenPos, pMax, ImGui.ColorConvertFloat4ToU32(accentColor), 4f, ImDrawFlags.None, 1f);
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetStyle().ItemSpacing.Y * 1.5f);
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + 10f);
using (ImRaii.PushFont(UiBuilder.IconFont))
{
ImGui.TextColored(in UiThemeUtils.AccentColor, FontAwesomeIcon.Search.ToIconString());
}
ImGui.SameLine();
float x2 = ImGui.GetStyle().ItemSpacing.X;
float num = 10f;
float num2 = 10f;
float num3 = ImGui.CalcTextSize("Search").X + ImGui.CalcTextSize(FontAwesomeIcon.Search.ToIconString()).X + ImGui.GetStyle().FramePadding.X * 4f + x2;
ImGui.SetNextItemWidth(x - num3 - x2 * 3f - num - num2);
using (ImRaii.PushColor(ImGuiCol.FrameBg, new Vector4(0.08f, 0.06f, 0.12f, 0.8f)))
{
using (ImRaii.PushColor(ImGuiCol.FrameBgHovered, new Vector4(0.12f, 0.1f, 0.18f, 0.9f)))
{
using (ImRaii.PushColor(ImGuiCol.FrameBgActive, new Vector4(0.15f, 0.13f, 0.22f, 1f)))
{
bool flag = ImGui.InputTextWithHint("##QuestLookup", "Enter quest ID...", ref _questLookupInput, 10, ImGuiInputTextFlags.EnterReturnsTrue);
ImGui.SameLine();
using (ImRaii.PushColor(ImGuiCol.Button, new Vector4(0.25f, 0.22f, 0.32f, 0.8f)))
{
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, new Vector4(0.35f, 0.3f, 0.45f, 0.9f)))
{
using (ImRaii.PushColor(ImGuiCol.ButtonActive, new Vector4(0.4f, 0.35f, 0.5f, 1f)))
{
bool flag2 = ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Search, "Search");
if (flag || flag2)
{
if (ushort.TryParse(_questLookupInput, out var result))
{
_lookedUpQuestId = new QuestId(result);
}
else
{
_lookedUpQuestId = null;
}
}
}
}
}
}
}
}
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetStyle().ItemSpacing.Y * 1.5f);
ImGui.Spacing();
ImGui.Spacing();
if (_lookedUpQuestId != null)
{
DrawQuestSequences(_lookedUpQuestId, null);
return;
}
accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.7f;
DrawEmptyState(FontAwesomeIcon.Search, "Enter a Quest ID", "Use the search box above to look up any quest by its ID.", accentColor);
}
private static void DrawEmptyState(FontAwesomeIcon icon, string title, string message, Vector4 iconColor)
{
float y = ImGui.GetContentRegionAvail().Y;
float x = ImGui.GetContentRegionAvail().X;
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + y * 0.25f);
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
ImGui.PushFont(UiBuilder.IconFont);
string text = icon.ToIconString();
Vector2 vector = ImGui.CalcTextSize(text);
vector *= 2.5f;
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
Vector2 vector2 = new Vector2(x * 0.5f, 0f) + cursorScreenPos + new Vector2(0f, vector.Y * 0.5f);
for (int num = 3; num > 0; num--)
{
Vector4 col = new Vector4(iconColor.X, iconColor.Y, iconColor.Z, iconColor.W * 0.1f * (float)num);
ImGui.SetCursorScreenPos(vector2 - vector * 0.5f - new Vector2(num * 2, num * 2));
ImGui.TextColored(in col, text);
}
ImGui.SetCursorScreenPos(vector2 - vector * 0.5f);
ImGui.TextColored(in iconColor, text);
ImGui.PopFont();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + vector.Y * 0.5f + 20f);
Vector2 vector3 = ImGui.CalcTextSize(title);
Vector2 vector4 = new Vector2((x - vector3.X) * 0.5f, 0f) + ImGui.GetCursorScreenPos();
windowDrawList.AddText(vector4 + new Vector2(1f, 1f), ImGui.ColorConvertFloat4ToU32(new Vector4(0f, 0f, 0f, 0.5f)), title);
ImGui.SetCursorPosX((x - vector3.X) * 0.5f);
ImGui.TextColored(in UiThemeUtils.PrimaryTextColor, title);
ImGui.Spacing();
ImGui.Spacing();
ImGui.SetCursorPosX(MathF.Max(0f, (x - ImGui.CalcTextSize(message).X) * 0.5f));
UiThemeUtils.WrappedTextColored(UiThemeUtils.DimTextColor, message);
}
private void DrawQuestSequences(ElementId questElementId, byte? currentSequence)
{
if (!(questElementId is QuestId questId))
{
DrawErrorState("Invalid Quest ID Type", "This viewer only supports regular quest IDs.");
return;
}
if (!_questData.TryGetQuestInfo(questElementId, out IQuestInfo questInfo))
{
DrawErrorState($"Quest {questId.Value} Not Found", "This quest ID does not exist in the game data.");
return;
}
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
float num = ImGui.GetFrameHeightWithSpacing() * 1.8f;
float x = ImGui.GetContentRegionAvail().X;
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
windowDrawList.AddRectFilledMultiColor(cursorScreenPos, cursorScreenPos + new Vector2(x, num), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor));
Vector2 pMin = cursorScreenPos;
Vector2 pMax = cursorScreenPos + new Vector2(x, num);
Vector4 accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.25f;
windowDrawList.AddRect(pMin, pMax, ImGui.ColorConvertFloat4ToU32(accentColor), 4f, ImDrawFlags.None, 1f);
float textLineHeight = ImGui.GetTextLineHeight();
float num2 = (num - textLineHeight) * 0.5f;
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + num2);
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + 10f);
ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextColored(in UiThemeUtils.AccentColor, FontAwesomeIcon.Book.ToIconString());
ImGui.PopFont();
ImGui.SameLine();
float x2 = ImGui.GetStyle().ItemSpacing.X;
ImU8String text = new ImU8String(6, 1);
text.AppendLiteral("(ID: ");
text.AppendFormatted(questId.Value);
text.AppendLiteral(")");
float num3 = ImGui.CalcTextSize(text).X + x2 + 8f + ImGui.GetFrameHeight() + x2;
if (currentSequence.HasValue)
{
float num4 = num3;
float num5 = ImGui.CalcTextSize("-").X + x2 * 2f;
ImU8String text2 = new ImU8String(17, 1);
text2.AppendLiteral("Active: Sequence ");
text2.AppendFormatted(currentSequence.Value);
num3 = num4 + (num5 + ImGui.CalcTextSize(text2).X + x2);
}
num3 += 12f;
UiThemeUtils.RowLabel(questInfo.Name, num3, UiThemeUtils.PrimaryTextColor);
ImGui.SameLine();
ImU8String text3 = new ImU8String(6, 1);
text3.AppendLiteral("(ID: ");
text3.AppendFormatted(questId.Value);
text3.AppendLiteral(")");
ImGui.TextColored(in UiThemeUtils.DimTextColor, text3);
ImGui.SameLine();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + 8f);
using (ImRaii.PushColor(ImGuiCol.Button, new Vector4(0.18f, 0.16f, 0.22f, 0.8f)))
{
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, new Vector4(0.28f, 0.24f, 0.32f, 0.95f)))
{
using (ImRaii.PushColor(ImGuiCol.ButtonActive, new Vector4(0.35f, 0.3f, 0.45f, 1f)))
{
if (ImGuiComponents.IconButton(FontAwesomeIcon.Copy))
{
ImGui.SetClipboardText(GetSequenceFilename(questId.Value, questInfo.Name));
}
if (ImGui.IsItemHovered())
{
ImGui.SetTooltip("Copies filename as QuestID_QuestNameWithSpaces.json");
}
}
}
}
if (currentSequence.HasValue)
{
ImGui.SameLine();
ImGui.TextColored(in UiThemeUtils.MutedTextColor, "-");
ImGui.SameLine();
float num6 = (float)ImGui.GetTime();
float num7 = 0.85f + MathF.Sin(num6 * 3f) * 0.15f;
accentColor = new Vector4(0.5f * num7, 1f * num7, 0.6f * num7, 1f);
ImU8String text4 = new ImU8String(17, 1);
text4.AppendLiteral("Active: Sequence ");
text4.AppendFormatted(currentSequence.Value);
ImGui.TextColored(in accentColor, text4);
}
ImGui.SetCursorPosY(cursorScreenPos.Y + num - ImGui.GetCursorScreenPos().Y + ImGui.GetCursorPosY());
ImGui.Spacing();
try
{
Lumina.Excel.Sheets.Quest? quest = _dataManager.GetExcelSheet<Lumina.Excel.Sheets.Quest>()?.GetRowOrDefault((uint)(questId.Value + 65536));
if (!quest.HasValue)
{
DrawErrorState("Quest Not Found in Game Data", "Unable to load quest information from Lumina.");
return;
}
List<int> list = (from result in quest.Value.TodoParams.Where((Lumina.Excel.Sheets.Quest.TodoParamsStruct todoParamsStruct) => todoParamsStruct.ToDoCompleteSeq > 0 && todoParamsStruct.ToDoCompleteSeq < byte.MaxValue).Select((Func<Lumina.Excel.Sheets.Quest.TodoParamsStruct, int>)((Lumina.Excel.Sheets.Quest.TodoParamsStruct todoParamsStruct) => todoParamsStruct.ToDoCompleteSeq)).Distinct()
orderby result
select result).ToList();
if (list.Count == 0)
{
DrawErrorState("No Sequence Data Available", "This quest may not have traditional sequences.");
return;
}
int num8 = list.Max();
int num9 = num8 + 1;
Questionable.Model.Quest quest2;
bool flag = _questRegistry.TryGetQuest(questElementId, out quest2);
HashSet<int> hashSet = new HashSet<int>();
Dictionary<int, (int, string)> dictionary = new Dictionary<int, (int, string)>();
bool flag2 = false;
if (flag && quest2 != null && quest2.Root.QuestSequence.Count > 0)
{
foreach (QuestSequence item in quest2.Root.QuestSequence)
{
if (item.Sequence == byte.MaxValue)
{
flag2 = true;
dictionary[255] = (item.Steps.Count, item.Comment);
}
else
{
hashSet.Add(item.Sequence);
dictionary[item.Sequence] = (item.Steps.Count, item.Comment);
}
}
}
int num10 = hashSet.Count + (flag2 ? 1 : 0);
int num11 = num9 + 1;
float num12 = (flag ? ((float)num10 / (float)num11 * 100f) : 0f);
Vector4 vector;
if (!(num12 >= 100f))
{
if (!(num12 >= 50f))
{
if (!(num12 < 1f))
{
vector = new Vector4(1f, 0.5f, 0.5f, 1f);
}
else
{
accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.7f;
vector = accentColor;
}
}
else
{
vector = new Vector4(1f, 0.9f, 0.5f, 1f);
}
}
else
{
vector = new Vector4(0.5f, 1f, 0.6f, 1f);
}
Vector4 coverageColor = vector;
DrawSummaryCards(num9, num8, flag, num12, coverageColor, num10, num11);
ImGui.Spacing();
ImGui.Spacing();
DrawSequenceGrid(num8, currentSequence, hashSet, dictionary, flag2);
}
catch (Exception ex)
{
DrawErrorState("Error Loading Quest Data", ex.Message + "\nCheck logs for details.");
_logger.LogWarning(ex, "Failed to read quest sequence data from Lumina for {QuestId}", questId);
}
}
private static void DrawErrorState(string title, string message)
{
float y = ImGui.GetContentRegionAvail().Y;
float x = ImGui.GetContentRegionAvail().X;
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + y * 0.25f);
float num = (float)ImGui.GetTime();
float num2 = 0.7f + MathF.Sin(num * 2f) * 0.3f;
ImGui.PushFont(UiBuilder.IconFont);
string text = FontAwesomeIcon.ExclamationTriangle.ToIconString();
Vector2 vector = ImGui.CalcTextSize(text);
ImGui.SetCursorPosX((x - (vector * 2f).X) * 0.5f);
ImGui.TextColored(new Vector4(1f * num2, 0.4f * num2, 0.4f * num2, 1f), text);
ImGui.PopFont();
ImGui.Spacing();
ImGui.Spacing();
ImGui.SetCursorPosX(MathF.Max(0f, (x - ImGui.CalcTextSize(title).X) * 0.5f));
UiThemeUtils.WrappedTextColored(new Vector4(1f, 0.5f, 0.5f, 1f), title);
ImGui.Spacing();
ImGui.SetCursorPosX(MathF.Max(0f, (x - ImGui.CalcTextSize(message).X) * 0.5f));
UiThemeUtils.WrappedTextColored(UiThemeUtils.DimTextColor, message);
}
private static void DrawSummaryCards(int totalSequences, int maxSeq, bool hasQuestPath, float coverage, Vector4 coverageColor, int implementedCount, int expectedCount)
{
using ImRaii.TableDisposable tableDisposable = UiThemeUtils.BeginThemedTable("SummaryCards", 2);
if (!tableDisposable)
{
return;
}
ImGui.TableSetupColumn("GameData", ImGuiTableColumnFlags.WidthStretch, 0.4f);
ImGui.TableSetupColumn("QuestPath", ImGuiTableColumnFlags.WidthStretch, 0.6f);
ImGui.TableNextRow();
ImGui.TableNextColumn();
DrawCard(80f, new Vector4(0.6f, 0.85f, 1f, 1f), FontAwesomeIcon.Gamepad, "Expected Sequences", delegate
{
ImGui.Spacing();
ImGui.Indent(10f);
ImU8String text = new ImU8String(6, 0);
text.AppendLiteral("Count:");
ImGui.TextColored(in UiThemeUtils.PrimaryTextColor, text);
ImGui.SameLine();
Vector4 col = new Vector4(0.7f, 0.9f, 1f, 1f);
ImU8String text2 = new ImU8String(0, 1);
text2.AppendFormatted(totalSequences);
ImGui.TextColored(in col, text2);
ImGui.Spacing();
ImU8String text3 = new ImU8String(6, 0);
text3.AppendLiteral("Range:");
ImGui.TextColored(in UiThemeUtils.PrimaryTextColor, text3);
ImGui.SameLine();
col = new Vector4(0.7f, 0.9f, 1f, 1f);
ImU8String text4 = new ImU8String(9, 1);
text4.AppendLiteral("0 → ");
text4.AppendFormatted(maxSeq);
text4.AppendLiteral(", 255");
ImGui.TextColored(in col, text4);
ImGui.Unindent(10f);
});
ImGui.TableNextColumn();
DrawCard(80f, new Vector4(0.5f, 1f, 0.6f, 1f), FontAwesomeIcon.Code, "Implementation Status", delegate
{
if (hasQuestPath)
{
ImGui.Indent(10f);
ImGui.TextColored(in UiThemeUtils.PrimaryTextColor, "Progress:");
ImGui.SameLine();
ref Vector4 col = ref coverageColor;
ImU8String text = new ImU8String(0, 1);
text.AppendFormatted(implementedCount);
ImGui.TextColored(in col, text);
ImGui.SameLine();
ImGui.TextColored(in UiThemeUtils.DimTextColor, "/");
ImGui.SameLine();
ImU8String text2 = new ImU8String(0, 1);
text2.AppendFormatted(expectedCount);
ImGui.TextColored(in UiThemeUtils.PrimaryTextColor, text2);
ImGui.SameLine();
ref Vector4 col2 = ref coverageColor;
ImU8String text3 = new ImU8String(3, 1);
text3.AppendLiteral("(");
text3.AppendFormatted(coverage, "F0");
text3.AppendLiteral("%)");
ImGui.TextColored(in col2, text3);
ImGui.Spacing();
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
float x = ImGui.GetContentRegionAvail().X - 10f;
using (ImRaii.PushColor(ImGuiCol.PlotHistogram, coverageColor))
{
using (ImRaii.PushColor(ImGuiCol.FrameBg, new Vector4(0.08f, 0.06f, 0.12f, 0.8f)))
{
ImGui.ProgressBar(coverage / 100f, new Vector2(x, 16f), "");
}
}
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
Vector2 pMax = cursorScreenPos + new Vector2(x, 16f);
Vector4 accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.3f;
windowDrawList.AddRect(cursorScreenPos, pMax, ImGui.ColorConvertFloat4ToU32(accentColor), 2f);
ImGui.Unindent(10f);
}
else
{
ImGui.Spacing();
ImGui.Indent(10f);
ImGui.PushFont(UiBuilder.IconFont);
Vector4 accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.8f;
ImGui.TextColored(in accentColor, FontAwesomeIcon.Ban.ToIconString());
ImGui.PopFont();
ImGui.SameLine();
accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.8f;
ImGui.TextColored(in accentColor, "Not Implemented");
ImGui.Spacing();
ImGui.TextColored(in UiThemeUtils.DimTextColor, "No quest path data available");
ImGui.Unindent(10f);
}
});
}
private static void DrawCard(float height, Vector4 accentColor, FontAwesomeIcon icon, string title, System.Action content)
{
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
float x = ImGui.GetContentRegionAvail().X;
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
windowDrawList.AddRectFilledMultiColor(cursorScreenPos, cursorScreenPos + new Vector2(x, height), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor), ImGui.ColorConvertFloat4ToU32(UiThemeUtils.CardBackgroundColor));
Vector2 pMin = cursorScreenPos;
Vector2 pMax = cursorScreenPos + new Vector2(x, height);
Vector4 accentColor2 = UiThemeUtils.AccentColor;
accentColor2.W = 0.2f;
windowDrawList.AddRect(pMin, pMax, ImGui.ColorConvertFloat4ToU32(accentColor2), 4f, ImDrawFlags.None, 1f);
windowDrawList.AddLine(cursorScreenPos, cursorScreenPos + new Vector2(x, 0f), ImGui.ColorConvertFloat4ToU32(accentColor), 3f);
float num = cursorScreenPos.Y + 10f;
ImGui.SetCursorScreenPos(new Vector2(cursorScreenPos.X + 10f, num));
ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextColored(in accentColor, icon.ToIconString());
ImGui.PopFont();
ImGui.SameLine();
ImGui.TextColored(in UiThemeUtils.PrimaryTextColor, title);
ImGui.SetCursorScreenPos(new Vector2(cursorScreenPos.X + 10f, num + 24f));
content();
ImGui.SetCursorScreenPos(new Vector2(cursorScreenPos.X, cursorScreenPos.Y + height + 4f));
}
private void DrawSequenceGrid(int maxSeq, byte? currentSequence, HashSet<int> implementedSequences, Dictionary<int, (int StepCount, string? Comment)> sequenceDetails, bool hasEndSequence)
{
int val = maxSeq + 2;
float x = ImGui.GetContentRegionAvail().X;
int val2 = Math.Max(4, Math.Min(8, (int)(x / 100f)));
val2 = Math.Min(val2, val);
float y = ImGui.GetContentRegionAvail().Y;
using (ImRaii.PushColor(ImGuiCol.ChildBg, new Vector4(0.08f, 0.06f, 0.12f, 0.6f)))
{
Vector4 accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.2f;
using (ImRaii.PushColor(ImGuiCol.Border, accentColor))
{
using ImRaii.ChildDisposable childDisposable = ImRaii.Child("SequenceGrid", new Vector2(-1f, y), border: true, ImGuiWindowFlags.None);
if (!(bool)childDisposable)
{
return;
}
accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.2f;
using (ImRaii.PushColor(ImGuiCol.TableBorderStrong, accentColor))
{
accentColor = UiThemeUtils.AccentColor;
accentColor.W = 0.15f;
using (ImRaii.PushColor(ImGuiCol.TableBorderLight, accentColor))
{
using ImRaii.TableDisposable tableDisposable = UiThemeUtils.BeginThemedTable("SequenceGridTable", val2, ImGuiTableFlags.SizingStretchSame);
if (!(bool)tableDisposable)
{
return;
}
int num = 0;
for (int i = 0; i <= maxSeq; i++)
{
if (num % val2 == 0)
{
ImGui.TableNextRow();
}
ImGui.TableNextColumn();
DrawSequenceCell(i, currentSequence, implementedSequences, sequenceDetails);
num++;
}
if (num % val2 == 0)
{
ImGui.TableNextRow();
}
ImGui.TableNextColumn();
DrawSequenceCell(255, currentSequence, implementedSequences, sequenceDetails, hasEndSequence);
for (num++; num % val2 != 0; num++)
{
ImGui.TableNextColumn();
}
}
}
}
}
}
private void DrawSequenceCell(int sequenceId, byte? currentSequence, HashSet<int> implementedSequences, Dictionary<int, (int StepCount, string? Comment)> sequenceDetails, bool? forcedImplemented = null)
{
bool flag = currentSequence.HasValue && sequenceId == currentSequence.Value;
bool flag2 = forcedImplemented ?? implementedSequences.Contains(sequenceId);
bool flag3 = _hoveredSequenceId == sequenceId;
string text = ((sequenceId == 255) ? "255" : $"{sequenceId}");
Vector4 input;
Vector4 input2;
if (flag)
{
input = (flag3 ? new Vector4(0.18f, 0.55f, 0.25f, 0.8f) : new Vector4(0.15f, 0.48f, 0.22f, 0.7f));
input2 = new Vector4(0.5f, 1f, 0.6f, flag3 ? 0.8f : 0.5f);
}
else if (flag2)
{
input = (flag3 ? new Vector4(0.14f, 0.38f, 0.18f, 0.6f) : new Vector4(0.12f, 0.34f, 0.16f, 0.5f));
input2 = new Vector4(0.5f, 1f, 0.6f, flag3 ? 0.5f : 0.25f);
}
else
{
input = (flag3 ? new Vector4(0.5f, 0.18f, 0.18f, 0.6f) : new Vector4(0.45f, 0.15f, 0.15f, 0.5f));
input2 = new Vector4(1f, 0.5f, 0.5f, flag3 ? 0.6f : 0.3f);
}
Vector2 cursorScreenPos = ImGui.GetCursorScreenPos();
Vector2 vector = new Vector2(ImGui.GetContentRegionAvail().X, 75f);
ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList();
windowDrawList.AddRectFilled(cursorScreenPos, cursorScreenPos + vector, ImGui.ColorConvertFloat4ToU32(input), 3f);
if (flag3)
{
windowDrawList.AddRect(cursorScreenPos - new Vector2(1f, 1f), cursorScreenPos + vector + new Vector2(1f, 1f), ImGui.ColorConvertFloat4ToU32(new Vector4(input2.X, input2.Y, input2.Z, input2.W * 0.3f)), 3f, ImDrawFlags.None, 3f);
}
windowDrawList.AddRect(cursorScreenPos, cursorScreenPos + vector, ImGui.ColorConvertFloat4ToU32(input2), 3f, ImDrawFlags.None, flag3 ? 2f : 1.5f);
float x = vector.X;
Vector2 vector2 = ImGui.CalcTextSize(text);
Vector4 input3 = (flag ? new Vector4(0.98f, 0.98f, 1f, 1f) : new Vector4(0.9f, 0.9f, 0.98f, 1f));
float y = cursorScreenPos.Y + (vector.Y - vector2.Y) * 0.5f;
windowDrawList.AddText(new Vector2(cursorScreenPos.X + (x - vector2.X) * 0.5f, y), ImGui.ColorConvertFloat4ToU32(input3), text);
ImGui.SetCursorScreenPos(cursorScreenPos);
ImU8String strId = new ImU8String(5, 1);
strId.AppendLiteral("##Seq");
strId.AppendFormatted(sequenceId);
ImGui.InvisibleButton(strId, vector);
if (ImGui.IsItemHovered())
{
_hoveredSequenceId = sequenceId;
using (ImRaii.Tooltip())
{
using (ImRaii.PushColor(ImGuiCol.Text, UiThemeUtils.PrimaryTextColor))
{
ImU8String text2 = new ImU8String(9, 1);
text2.AppendLiteral("Sequence ");
text2.AppendFormatted(sequenceId);
ImGui.Text(text2);
}
ImGui.Separator();
if (flag2 && sequenceDetails.TryGetValue(sequenceId, out (int, string) value))
{
ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextColored(new Vector4(0.5f, 1f, 0.6f, 1f), FontAwesomeIcon.CheckCircle.ToIconString());
ImGui.PopFont();
ImGui.SameLine();
ImGui.TextColored(new Vector4(0.5f, 1f, 0.6f, 1f), "Implemented");
ImGui.Spacing();
ImU8String text3 = new ImU8String(6, 0);
text3.AppendLiteral("Steps:");
ImGui.TextColored(in UiThemeUtils.PrimaryTextColor, text3);
ImGui.SameLine();
Vector4 col = new Vector4(0.7f, 0.9f, 1f, 1f);
ImU8String text4 = new ImU8String(0, 1);
text4.AppendFormatted(value.Item1);
ImGui.TextColored(in col, text4);
if (!string.IsNullOrEmpty(value.Item2))
{
ImGui.Separator();
ImGui.PushTextWrapPos(250f);
ImGui.TextColored(in UiThemeUtils.DimTextColor, value.Item2);
ImGui.PopTextWrapPos();
}
}
else if (!flag2)
{
ImGui.PushFont(UiBuilder.IconFont);
ImGui.TextColored(new Vector4(1f, 0.5f, 0.5f, 1f), FontAwesomeIcon.TimesCircle.ToIconString());
ImGui.PopFont();
ImGui.SameLine();
ImGui.TextColored(new Vector4(1f, 0.5f, 0.5f, 1f), "Not Implemented");
ImGui.Spacing();
ImGui.PushTextWrapPos(250f);
ImGui.TextColored(in UiThemeUtils.DimTextColor, "This sequence is missing from the quest path.");
ImGui.PopTextWrapPos();
}
if (flag)
{
ImGui.Separator();
ImGui.TextColored(new Vector4(1f, 0.85f, 0.5f, 1f), "► Currently Active");
}
}
}
else if (_hoveredSequenceId == sequenceId)
{
_hoveredSequenceId = -1;
}
ImGui.SetCursorScreenPos(cursorScreenPos + new Vector2(0f, vector.Y));
}
internal static string GetSequenceFilename(int questId, string questName)
{
string value = (questName ?? string.Empty).Trim();
return $"{questId}_{value}.json";
}
public void SetLookedUpQuest(ElementId? id)
{
_lookedUpQuestId = id;
}
}