using System; using System.Collections.Generic; 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 QuestFunctions _questFunctions; private readonly IDataManager _dataManager; private readonly ILogger _logger; private string _questLookupInput = string.Empty; private ElementId? _lookedUpQuestId; private int _hoveredSequenceId = -1; public QuestSequenceComponent(QuestData questData, QuestRegistry questRegistry, QuestFunctions questFunctions, IDataManager dataManager, ILogger logger) { _questData = questData; _questRegistry = questRegistry; _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))); windowDrawList.AddLine(cursorScreenPos + new Vector2(0f, num), cursorScreenPos + new Vector2(x, num), ImGui.ColorConvertFloat4ToU32(new Vector4(0.7f, 0.6f, 0.9f, 0.5f)), 2f); float textLineHeight = ImGui.GetTextLineHeight(); float num2 = (num - textLineHeight) * 0.5f; ImGui.SetCursorPosY(ImGui.GetCursorPosY() + num2); ImGui.SetCursorPosX(ImGui.GetCursorPosX() + 10f); ImGui.TextColored(new Vector4(0.98f, 0.98f, 1f, 1f), "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(); windowDrawList.AddRect(windowPos - new Vector2(1f, 1f), windowPos + windowSize + new Vector2(1f, 1f), ImGui.ColorConvertFloat4ToU32(new Vector4(0.7f, 0.6f, 0.9f, 0.15f)), 5f, ImDrawFlags.None, 3f); windowDrawList.AddRect(windowPos, windowPos + windowSize, ImGui.ColorConvertFloat4ToU32(new Vector4(0.7f, 0.6f, 0.9f, 0.4f)), 4f, ImDrawFlags.None, 1.5f); } public void DrawCurrentQuestTab() { QuestReference currentQuest = _questFunctions.GetCurrentQuest(); (ElementId, byte) tuple = (currentQuest.CurrentQuest, currentQuest.Sequence); if (tuple.Item1 != null) { DrawQuestSequences(tuple.Item1, tuple.Item2); } else { DrawEmptyState(FontAwesomeIcon.QuestionCircle, "No Active Quest", "Accept a quest to view its sequence information.", new Vector4(0.6f, 0.5f, 0.8f, 0.7f)); } } 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(new Vector4(0.12f, 0.1f, 0.16f, 0.6f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.1f, 0.08f, 0.14f, 0.6f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.1f, 0.08f, 0.14f, 0.6f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.12f, 0.1f, 0.16f, 0.6f))); windowDrawList.AddRect(cursorScreenPos, cursorScreenPos + new Vector2(x, y), ImGui.ColorConvertFloat4ToU32(new Vector4(0.6f, 0.5f, 0.8f, 0.2f)), 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(new Vector4(0.7f, 0.6f, 0.9f, 1f), 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); } else { DrawEmptyState(FontAwesomeIcon.Search, "Enter a Quest ID", "Use the search box above to look up any quest by its ID.", new Vector4(0.6f, 0.5f, 0.8f, 0.7f)); } } 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(new Vector4(0.95f, 0.95f, 1f, 1f), title); ImGui.Spacing(); ImGui.Spacing(); ImGui.SetCursorPosX((x - ImGui.CalcTextSize(message).X) * 0.5f); ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.8f, 1f), 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(new Vector4(0.12f, 0.1f, 0.16f, 0.7f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.1f, 0.08f, 0.14f, 0.7f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.1f, 0.08f, 0.14f, 0.7f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.12f, 0.1f, 0.16f, 0.7f))); windowDrawList.AddRect(cursorScreenPos, cursorScreenPos + new Vector2(x, num), ImGui.ColorConvertFloat4ToU32(new Vector4(0.6f, 0.5f, 0.8f, 0.25f)), 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(new Vector4(0.7f, 0.6f, 0.9f, 1f), FontAwesomeIcon.Book.ToIconString()); ImGui.PopFont(); ImGui.SameLine(); ImGui.TextColored(new Vector4(0.98f, 0.98f, 1f, 1f), questInfo.Name); ImGui.SameLine(); Vector4 col = new Vector4(0.7f, 0.7f, 0.8f, 1f); ImU8String text = new ImU8String(6, 1); text.AppendLiteral("(ID: "); text.AppendFormatted(questId.Value); text.AppendLiteral(")"); ImGui.TextColored(in col, text); if (currentSequence.HasValue) { ImGui.SameLine(); ImGui.TextColored(new Vector4(0.5f, 0.5f, 0.6f, 1f), "—"); ImGui.SameLine(); float num3 = (float)ImGui.GetTime(); float num4 = 0.85f + MathF.Sin(num3 * 3f) * 0.15f; col = new Vector4(0.5f * num4, 1f * num4, 0.6f * num4, 1f); text = new ImU8String(17, 1); text.AppendLiteral("Active: Sequence "); text.AppendFormatted(currentSequence.Value); ImGui.TextColored(in col, text); } ImGui.SetCursorPosY(cursorScreenPos.Y + num - ImGui.GetCursorScreenPos().Y + ImGui.GetCursorPosY()); ImGui.Spacing(); try { Lumina.Excel.Sheets.Quest? quest = _dataManager.GetExcelSheet()?.GetRowOrDefault((uint)(questId.Value + 65536)); if (!quest.HasValue) { DrawErrorState("Quest Not Found in Game Data", "Unable to load quest information from Lumina."); return; } List 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 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 num5 = list.Max(); int num6 = num5 + 1; Questionable.Model.Quest quest2; bool flag = _questRegistry.TryGetQuest(questElementId, out quest2); HashSet hashSet = new HashSet(); Dictionary dictionary = new Dictionary(); 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 num7 = hashSet.Count + (flag2 ? 1 : 0); int num8 = num6 + 1; float num9 = (flag ? ((float)num7 / (float)num8 * 100f) : 0f); Vector4 coverageColor = ((num9 >= 100f) ? new Vector4(0.5f, 1f, 0.6f, 1f) : ((num9 >= 50f) ? new Vector4(1f, 0.9f, 0.5f, 1f) : ((num9 < 1f) ? new Vector4(0.6f, 0.5f, 0.8f, 0.7f) : new Vector4(1f, 0.5f, 0.5f, 1f)))); DrawSummaryCards(num6, num5, flag, num9, coverageColor, num7, num8); ImGui.Spacing(); ImGui.Spacing(); DrawSequenceGrid(num5, 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((x - ImGui.CalcTextSize(title).X) * 0.5f); ImGui.TextColored(new Vector4(1f, 0.5f, 0.5f, 1f), title); ImGui.Spacing(); ImGui.SetCursorPosX((x - ImGui.CalcTextSize(message).X) * 0.5f); ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.8f, 1f), message); } private static void DrawSummaryCards(int totalSequences, int maxSeq, bool hasQuestPath, float coverage, Vector4 coverageColor, int implementedCount, int expectedCount) { using ImRaii.IEndObject endObject = ImRaii.Table("SummaryCards", 2, ImGuiTableFlags.None); if (!endObject) { 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); Vector4 col = new Vector4(0.9f, 0.9f, 0.98f, 1f); ImU8String text = new ImU8String(6, 0); text.AppendLiteral("Count:"); ImGui.TextColored(in col, text); ImGui.SameLine(); col = new Vector4(0.7f, 0.9f, 1f, 1f); text = new ImU8String(0, 1); text.AppendFormatted(totalSequences); ImGui.TextColored(in col, text); ImGui.Spacing(); col = new Vector4(0.9f, 0.9f, 0.98f, 1f); text = new ImU8String(6, 0); text.AppendLiteral("Range:"); ImGui.TextColored(in col, text); ImGui.SameLine(); col = new Vector4(0.7f, 0.9f, 1f, 1f); text = new ImU8String(9, 1); text.AppendLiteral("0 → "); text.AppendFormatted(maxSeq); text.AppendLiteral(", 255"); ImGui.TextColored(in col, text); 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(new Vector4(0.9f, 0.9f, 0.98f, 1f), "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(new Vector4(0.7f, 0.7f, 0.8f, 1f), "/"); ImGui.SameLine(); Vector4 col2 = new Vector4(0.9f, 0.9f, 0.98f, 1f); text = new ImU8String(0, 1); text.AppendFormatted(expectedCount); ImGui.TextColored(in col2, text); ImGui.SameLine(); ref Vector4 col3 = ref coverageColor; text = new ImU8String(3, 1); text.AppendLiteral("("); text.AppendFormatted(coverage, "F0"); text.AppendLiteral("%)"); ImGui.TextColored(in col3, text); 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), ""); } } ImGui.GetWindowDrawList().AddRect(cursorScreenPos, cursorScreenPos + new Vector2(x, 16f), ImGui.ColorConvertFloat4ToU32(new Vector4(0.6f, 0.5f, 0.8f, 0.3f)), 2f); ImGui.Unindent(10f); } else { ImGui.Spacing(); ImGui.Indent(10f); ImGui.PushFont(UiBuilder.IconFont); ImGui.TextColored(new Vector4(0.6f, 0.5f, 0.8f, 0.8f), FontAwesomeIcon.Ban.ToIconString()); ImGui.PopFont(); ImGui.SameLine(); ImGui.TextColored(new Vector4(0.6f, 0.5f, 0.8f, 0.8f), "Not Implemented"); ImGui.Spacing(); ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.8f, 1f), "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(new Vector4(0.12f, 0.1f, 0.16f, 0.7f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.1f, 0.08f, 0.14f, 0.7f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.1f, 0.08f, 0.14f, 0.7f)), ImGui.ColorConvertFloat4ToU32(new Vector4(0.12f, 0.1f, 0.16f, 0.7f))); windowDrawList.AddRect(cursorScreenPos, cursorScreenPos + new Vector2(x, height), ImGui.ColorConvertFloat4ToU32(new Vector4(0.6f, 0.5f, 0.8f, 0.2f)), 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(new Vector4(0.98f, 0.98f, 1f, 1f), 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 implementedSequences, Dictionary 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))) { using (ImRaii.PushColor(ImGuiCol.Border, new Vector4(0.6f, 0.5f, 0.8f, 0.2f))) { using ImRaii.IEndObject endObject = ImRaii.Child("SequenceGrid", new Vector2(-1f, y), border: true, ImGuiWindowFlags.None); if (!ImRaii.IEndObject.op_True(endObject)) { return; } using (ImRaii.PushColor(ImGuiCol.TableBorderStrong, new Vector4(0.6f, 0.5f, 0.8f, 0.2f))) { using (ImRaii.PushColor(ImGuiCol.TableBorderLight, new Vector4(0.6f, 0.5f, 0.8f, 0.15f))) { using ImRaii.IEndObject endObject2 = ImRaii.Table("SequenceGridTable", val2, ImGuiTableFlags.Borders | ImGuiTableFlags.SizingStretchSame); if (!ImRaii.IEndObject.op_True(endObject2)) { 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 implementedSequences, Dictionary 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, new Vector4(0.98f, 0.98f, 1f, 1f))) { strId = new ImU8String(9, 1); strId.AppendLiteral("Sequence "); strId.AppendFormatted(sequenceId); ImGui.Text(strId); } 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(); Vector4 col = new Vector4(0.9f, 0.9f, 0.98f, 1f); strId = new ImU8String(6, 0); strId.AppendLiteral("Steps:"); ImGui.TextColored(in col, strId); ImGui.SameLine(); col = new Vector4(0.7f, 0.9f, 1f, 1f); strId = new ImU8String(0, 1); strId.AppendFormatted(value.Item1); ImGui.TextColored(in col, strId); if (!string.IsNullOrEmpty(value.Item2)) { ImGui.Separator(); ImGui.PushTextWrapPos(250f); ImGui.TextColored(new Vector4(0.7f, 0.7f, 0.8f, 1f), 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(new Vector4(0.7f, 0.7f, 0.8f, 1f), "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)); } }