267 lines
8.3 KiB
C#
267 lines
8.3 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Game.Text;
|
|
using Dalamud.Interface;
|
|
using Dalamud.Interface.Utility.Raii;
|
|
using Dalamud.Plugin;
|
|
using Questionable.Controller;
|
|
using Questionable.Data;
|
|
using Questionable.Model;
|
|
using Questionable.Windows.QuestComponents;
|
|
|
|
namespace Questionable.Windows.JournalComponents;
|
|
|
|
internal sealed class QuestRewardComponent
|
|
{
|
|
private enum RowType : byte
|
|
{
|
|
Group,
|
|
Item
|
|
}
|
|
|
|
private readonly record struct FlatRow(RowType Type, int GroupIndex, ItemReward? Item);
|
|
|
|
private sealed record ItemGroup(string Label, EItemRewardType Type, List<ItemReward> Items);
|
|
|
|
private readonly QuestRegistry _questRegistry;
|
|
|
|
private readonly QuestData _questData;
|
|
|
|
private readonly QuestTooltipComponent _questTooltipComponent;
|
|
|
|
private readonly UiUtils _uiUtils;
|
|
|
|
private readonly IDalamudPluginInterface _pluginInterface;
|
|
|
|
private bool _showEventRewards;
|
|
|
|
private string _searchText = string.Empty;
|
|
|
|
private List<ItemGroup> _filteredGroups = new List<ItemGroup>();
|
|
|
|
private List<FlatRow> _flatRows = new List<FlatRow>();
|
|
|
|
private readonly HashSet<string> _expandedGroups = new HashSet<string>();
|
|
|
|
private bool _initialized;
|
|
|
|
private static readonly int CountPadWidth = 9999.ToString(CultureInfo.CurrentCulture).Length;
|
|
|
|
public QuestRewardComponent(QuestRegistry questRegistry, QuestData questData, QuestTooltipComponent questTooltipComponent, UiUtils uiUtils, IDalamudPluginInterface pluginInterface)
|
|
{
|
|
_questRegistry = questRegistry;
|
|
_questData = questData;
|
|
_questTooltipComponent = questTooltipComponent;
|
|
_uiUtils = uiUtils;
|
|
_pluginInterface = pluginInterface;
|
|
}
|
|
|
|
public unsafe void DrawItemRewards()
|
|
{
|
|
if (!_initialized)
|
|
{
|
|
UpdateFilter();
|
|
_initialized = true;
|
|
}
|
|
float x = ImGui.GetStyle().ItemSpacing.X;
|
|
float num = ImGui.GetFrameHeight() + ImGui.CalcTextSize("Show seasonal event rewards").X + 3f * x;
|
|
if (UiThemeUtils.SearchInput("##RewardSearch", ref _searchText, 0f - num, "Search items..."))
|
|
{
|
|
UpdateFilter();
|
|
}
|
|
ImGui.SameLine();
|
|
if (UiThemeUtils.WrappedCheckbox("Show seasonal event rewards", ref _showEventRewards))
|
|
{
|
|
UpdateFilter();
|
|
}
|
|
ImGui.Spacing();
|
|
ImGui.TextColored(in UiThemeUtils.MutedTextColor, "Only untradeable items are listed (e.g. the Wind-up Airship can be sold on the market board).");
|
|
ImGui.Separator();
|
|
if (_flatRows.Count == 0)
|
|
{
|
|
UiThemeUtils.EmptyState(FontAwesomeIcon.Gift, "No items match your search.");
|
|
return;
|
|
}
|
|
float x2;
|
|
using (_pluginInterface.UiBuilder.IconFontFixedWidthHandle.Push())
|
|
{
|
|
x2 = ImGui.CalcTextSize(FontAwesomeIcon.Check.ToIconString()).X;
|
|
}
|
|
float fontGlobalScale = ImGui.GetIO().FontGlobalScale;
|
|
using ImRaii.TableDisposable tableDisposable = UiThemeUtils.BeginThemedTable("ItemRewards", 2, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.ScrollY);
|
|
if (!tableDisposable)
|
|
{
|
|
return;
|
|
}
|
|
ImGui.TableSetupColumn("Name", ImGuiTableColumnFlags.WidthStretch);
|
|
ImGui.TableSetupColumn("Obtained", ImGuiTableColumnFlags.WidthFixed, 120f * fontGlobalScale);
|
|
ImGui.TableHeadersRow();
|
|
float textLineHeightWithSpacing = ImGui.GetTextLineHeightWithSpacing();
|
|
bool flag = false;
|
|
ImGuiListClipper* intPtr = ImGuiNative.ImGuiListClipper();
|
|
ImGuiNative.Begin(intPtr, _flatRows.Count, textLineHeightWithSpacing);
|
|
ImGuiListClipperPtr imGuiListClipperPtr = intPtr;
|
|
try
|
|
{
|
|
while (imGuiListClipperPtr.Step())
|
|
{
|
|
for (int i = imGuiListClipperPtr.DisplayStart; i < imGuiListClipperPtr.DisplayEnd; i++)
|
|
{
|
|
if (DrawFlatRow(_flatRows[i], x2))
|
|
{
|
|
flag = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
imGuiListClipperPtr.Destroy();
|
|
}
|
|
if (flag)
|
|
{
|
|
RebuildFlatRows();
|
|
}
|
|
}
|
|
|
|
private bool DrawFlatRow(FlatRow row, float statusIconSpacing)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableNextColumn();
|
|
if (row.Type == RowType.Group)
|
|
{
|
|
ItemGroup itemGroup = _filteredGroups[row.GroupIndex];
|
|
bool flag = _expandedGroups.Contains(itemGroup.Label);
|
|
UiThemeUtils.DrawTrackerGroupCaret(_pluginInterface.UiBuilder.IconFontFixedWidthHandle, flag);
|
|
ImGui.SameLine();
|
|
bool result = false;
|
|
ImU8String label = new ImU8String(5, 2);
|
|
label.AppendFormatted(itemGroup.Label);
|
|
label.AppendLiteral("##grp");
|
|
label.AppendFormatted(row.GroupIndex);
|
|
if (ImGui.Selectable(label))
|
|
{
|
|
if (flag)
|
|
{
|
|
_expandedGroups.Remove(itemGroup.Label);
|
|
}
|
|
else
|
|
{
|
|
_expandedGroups.Add(itemGroup.Label);
|
|
}
|
|
result = true;
|
|
}
|
|
int num = itemGroup.Items.Count((ItemReward x) => x.IsUnlocked());
|
|
int count = itemGroup.Items.Count;
|
|
ImGui.TableNextColumn();
|
|
UiThemeUtils.DrawTrackerCount(FormatCount(num, count), num == count && count > 0, count == 0);
|
|
return result;
|
|
}
|
|
ItemReward item = row.Item;
|
|
float indentSpacing = ImGui.GetStyle().IndentSpacing;
|
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + indentSpacing);
|
|
bool flag2 = item.IsUnlocked();
|
|
Vector4 color = ((!_questRegistry.IsKnownQuest(item.ElementId)) ? UiThemeUtils.StatusUnobtainable : (flag2 ? UiThemeUtils.StatusComplete : UiThemeUtils.StatusLocked));
|
|
IQuestInfo questInfo;
|
|
bool flag3 = _questData.TryGetQuestInfo(item.ElementId, out questInfo);
|
|
string text = item.Name;
|
|
if (questInfo is QuestInfo { IsSeasonalEvent: not false })
|
|
{
|
|
text = text + " " + SeIconChar.Clock.ToIconString();
|
|
}
|
|
ImGui.TreeNodeEx(text, ImGuiTreeNodeFlags.NoTreePushOnOpen | ImGuiTreeNodeFlags.Leaf | ImGuiTreeNodeFlags.SpanFullWidth);
|
|
bool num2 = ImGui.IsItemHovered();
|
|
ImGui.TableNextColumn();
|
|
float num3 = ImGui.GetColumnWidth() / 2f - statusIconSpacing;
|
|
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + num3);
|
|
FontAwesomeIcon icon = (flag2 ? FontAwesomeIcon.Check : FontAwesomeIcon.Times);
|
|
if ((num2 | _uiUtils.ChecklistItem(string.Empty, color, icon)) && flag3)
|
|
{
|
|
using ImRaii.TooltipDisposable tooltipDisposable = ImRaii.Tooltip();
|
|
if (tooltipDisposable.Alive)
|
|
{
|
|
ImU8String text2 = new ImU8String(15, 1);
|
|
text2.AppendLiteral("Obtained from: ");
|
|
text2.AppendFormatted(questInfo.Name);
|
|
ImGui.Text(text2);
|
|
using (ImRaii.PushIndent())
|
|
{
|
|
_questTooltipComponent.DrawInner(questInfo, showItemRewards: false);
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static string FormatCount(int n, int d)
|
|
{
|
|
if (d != 0)
|
|
{
|
|
return n.ToString(CultureInfo.CurrentCulture).PadLeft(CountPadWidth) + " / " + d.ToString(CultureInfo.CurrentCulture).PadLeft(CountPadWidth);
|
|
}
|
|
return "-".PadLeft(CountPadWidth) + " / " + "-".PadLeft(CountPadWidth);
|
|
}
|
|
|
|
private void RebuildFlatRows()
|
|
{
|
|
List<FlatRow> list = new List<FlatRow>();
|
|
for (int i = 0; i < _filteredGroups.Count; i++)
|
|
{
|
|
ItemGroup itemGroup = _filteredGroups[i];
|
|
list.Add(new FlatRow(RowType.Group, i, null));
|
|
if (!_expandedGroups.Contains(itemGroup.Label))
|
|
{
|
|
continue;
|
|
}
|
|
foreach (ItemReward item in itemGroup.Items)
|
|
{
|
|
if (_questData.TryGetQuestInfo(item.ElementId, out IQuestInfo _))
|
|
{
|
|
list.Add(new FlatRow(RowType.Item, i, item));
|
|
}
|
|
}
|
|
}
|
|
_flatRows = list;
|
|
}
|
|
|
|
private void UpdateFilter()
|
|
{
|
|
List<ItemGroup> list = new List<ItemGroup>();
|
|
AddGroup(list, "Mounts", EItemRewardType.Mount);
|
|
AddGroup(list, "Minions", EItemRewardType.Minion);
|
|
AddGroup(list, "Orchestrion Rolls", EItemRewardType.OrchestrionRoll);
|
|
AddGroup(list, "Triple Triad Cards", EItemRewardType.TripleTriadCard);
|
|
AddGroup(list, "Fashion Accessories", EItemRewardType.FashionAccessory);
|
|
AddGroup(list, "Unlock Links", EItemRewardType.UnlockLink);
|
|
_filteredGroups = list;
|
|
RebuildFlatRows();
|
|
}
|
|
|
|
private void AddGroup(List<ItemGroup> groups, string label, EItemRewardType type)
|
|
{
|
|
List<ItemReward> filteredItems = GetFilteredItems(type);
|
|
if (filteredItems.Count > 0)
|
|
{
|
|
groups.Add(new ItemGroup(label, type, filteredItems));
|
|
}
|
|
}
|
|
|
|
private List<ItemReward> GetFilteredItems(EItemRewardType type)
|
|
{
|
|
return (from x in _questData.RedeemableItems
|
|
where x.Type == type
|
|
where x.IsUntradable
|
|
select x).Where(delegate(ItemReward x)
|
|
{
|
|
if (!_showEventRewards && _questData.TryGetQuestInfo(x.ElementId, out IQuestInfo questInfo) && questInfo is QuestInfo { IsSeasonalEvent: not false })
|
|
{
|
|
return false;
|
|
}
|
|
return (string.IsNullOrEmpty(_searchText) || x.Name.Contains(_searchText, StringComparison.OrdinalIgnoreCase)) ? true : false;
|
|
}).OrderBy<ItemReward, string>((ItemReward x) => x.Name, StringComparer.CurrentCultureIgnoreCase).ToList();
|
|
}
|
|
}
|