Compare commits

..

No commits in common. "master" and "v2.0" have entirely different histories.
master ... v2.0

4 changed files with 47 additions and 129 deletions

View File

@ -62,7 +62,7 @@ internal sealed class CharacterSwitch : IDisposable
{ {
UIInputData* uiInputData = UIInputData.Instance(); UIInputData* uiInputData = UIInputData.Instance();
MouseButtonFlags mouseButtonFlags = MouseButtonFlags mouseButtonFlags =
uiInputData != null ? uiInputData->CursorInputs.MouseButtonHeldThrottledFlags : MouseButtonFlags.LBUTTON; uiInputData != null ? uiInputData->CursorInputs.MouseButtonReleasedFlags : MouseButtonFlags.LBUTTON;
var target = FindCharacter(mouseButtonFlags.HasFlag(MouseButtonFlags.RBUTTON) ? -1 : 1); var target = FindCharacter(mouseButtonFlags.HasFlag(MouseButtonFlags.RBUTTON) ? -1 : 1);
SwitchCharacter(target); SwitchCharacter(target);
} }

View File

@ -3,11 +3,13 @@ using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Dalamud.Game.Addon.Events;
using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.Addon.Lifecycle.AddonArgTypes; using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
using Dalamud.Game.Command; using Dalamud.Game.Command;
using Dalamud.Game.Text.SeStringHandling; using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Interface.Colors; using Dalamud.Interface.Colors;
using Dalamud.Interface.Style;
using Dalamud.Interface.Utility.Raii; using Dalamud.Interface.Utility.Raii;
using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing;
using Dalamud.Plugin; using Dalamud.Plugin;
@ -26,13 +28,6 @@ internal sealed class GlamourSetter : Window, IDisposable
private const uint ItemMgp = 29; private const uint ItemMgp = 29;
private const uint ItemTrophyCrystals = 36656; private const uint ItemTrophyCrystals = 36656;
private static readonly (uint ItemId, string Name)[] AlliedSocietyCurrencies =
[
(21074, "Vanu Whitebone"),
(21079, "Black Copper Gil"),
(21081, "Kojin Sango"),
];
private static readonly ImmutableHashSet<uint> MgpMakaiSets = new HashSet<uint> private static readonly ImmutableHashSet<uint> MgpMakaiSets = new HashSet<uint>
{ {
// makai gear // makai gear
@ -89,8 +84,6 @@ internal sealed class GlamourSetter : Window, IDisposable
private readonly IAddonLifecycle _addonLifecycle; private readonly IAddonLifecycle _addonLifecycle;
private readonly Configuration _configuration; private readonly Configuration _configuration;
private readonly ReadOnlyCollection<GlamourSet> _glamourSets; private readonly ReadOnlyCollection<GlamourSet> _glamourSets;
private readonly Dictionary<uint, int> _ownedCurrencies = [];
private Configuration.CharacterData? _characterData; private Configuration.CharacterData? _characterData;
public GlamourSetter(IDalamudPluginInterface pluginInterface, IDataManager dataManager, IClientState clientState, public GlamourSetter(IDalamudPluginInterface pluginInterface, IDataManager dataManager, IClientState clientState,
@ -105,34 +98,28 @@ internal sealed class GlamourSetter : Window, IDisposable
_addonLifecycle = addonLifecycle; _addonLifecycle = addonLifecycle;
_configuration = configuration; _configuration = configuration;
SizeConstraints = new WindowSizeConstraints
{
MinimumSize = new(300, 400)
};
var armoireItems = dataManager.GetExcelSheet<Cabinet>() var armoireItems = dataManager.GetExcelSheet<Cabinet>()
.Where(x => x.RowId > 0) .Where(x => x.RowId > 0)
.Select(x => x.Item.RowId) .Select(x => x.Item.RowId)
.ToHashSet(); .ToHashSet();
var specialShopItems = BuildSpecialShopItems(dataManager); var specialShopItems = dataManager.GetExcelSheet<SpecialShop>()
_glamourSets = BuildGlamourSets(dataManager, armoireItems, specialShopItems); .Where(x => x.RowId > 0 && !string.IsNullOrEmpty(x.Name.ToString()))
.SelectMany(x => x.Item.SelectMany(y =>
y.ReceiveItems.Select(z => new SpecialShopItem
{
ItemId = z.Item.RowId,
CostItemId = y.ItemCosts[0].ItemCost.Value.RowId,
CostType = y.ItemCosts[0].ItemCost.Value.ItemUICategory.RowId,
CostName = y.ItemCosts[0].ItemCost.Value.Name.ToString(),
CostQuantity = y.ItemCosts[0].CurrencyCost,
})
.Where(z => z.ItemId > 0 && (z.CostItemId < 100 || z.CostType == 100))))
.GroupBy(x => x.ItemId)
.ToDictionary(x => x.Key, x => x.FirstOrDefault());
_commandManager.AddHandler("/glamoursets", new CommandInfo(ProcessCommand)
{
HelpMessage = "Shows the glamour set tracker"
});
_addonLifecycle.RegisterListener(AddonEvent.PostRefresh, "MiragePrismPrismBox", UpdateFromGlamourDresser);
_clientState.Logout += Reset;
if (_clientState.IsLoggedIn)
Update();
}
private static ReadOnlyCollection<GlamourSet> BuildGlamourSets(IDataManager dataManager, HashSet<uint> armoireItems,
Dictionary<uint, SpecialShopItem> specialShopItems)
{
ExcelSheet<Item> itemSheet = dataManager.GetExcelSheet<Item>(); ExcelSheet<Item> itemSheet = dataManager.GetExcelSheet<Item>();
return dataManager.GetExcelSheet<MirageStoreSetItem>() _glamourSets = dataManager.GetExcelSheet<MirageStoreSetItem>()
.Where(x => x.RowId > 0) .Where(x => x.RowId > 0)
.Select(x => .Select(x =>
{ {
@ -167,7 +154,20 @@ internal sealed class GlamourSetter : Window, IDisposable
ItemId = x.RowId, ItemId = x.RowId,
Name = itemSheet.GetRow(x.RowId).Name.ToString(), Name = itemSheet.GetRow(x.RowId).Name.ToString(),
Items = items, Items = items,
SetType = DetermineSetType(x, items), SetType =
x.RowId == MostRecentPvpSet
? ESetType.PvP
: UnobtainableSets.Contains(x.RowId)
? ESetType.Unobtainable
: EternalBondingSets.Contains(x.RowId) || UndyedRathalosSets.Contains(x.RowId) || MgpMakaiSets.Contains(x.RowId)
? ESetType.Special
: items.FirstOrDefault()?.ShopItem?.CostItemId switch
{
ItemWolfMarks or ItemTrophyCrystals => ESetType.PvP,
ItemMgp => ESetType.MGP,
> 100 => ESetType.AlliedSociety,
_ => ESetType.Default,
},
}; };
}) })
.Where(x => x.Items.Count > 0 && x.Items.Any(y => !armoireItems.Contains(y.ItemId))) .Where(x => x.Items.Count > 0 && x.Items.Any(y => !armoireItems.Contains(y.ItemId)))
@ -175,49 +175,16 @@ internal sealed class GlamourSetter : Window, IDisposable
.ThenBy(x => x.ItemId) .ThenBy(x => x.ItemId)
.ToList() .ToList()
.AsReadOnly(); .AsReadOnly();
}
private static ESetType DetermineSetType(MirageStoreSetItem item, ReadOnlyCollection<GlamourItem> items) _commandManager.AddHandler("/glamoursets", new CommandInfo(ProcessCommand)
{
if (item.RowId == MostRecentPvpSet)
return ESetType.PvP;
if (UnobtainableSets.Contains(item.RowId))
return ESetType.Unobtainable;
if (EternalBondingSets.Contains(item.RowId) ||
UndyedRathalosSets.Contains(item.RowId) ||
MgpMakaiSets.Contains(item.RowId))
return ESetType.Special;
uint? costItemId = items.FirstOrDefault()?.ShopItem?.CostItemId;
if (AlliedSocietyCurrencies.Any(x => x.ItemId == costItemId))
return ESetType.AlliedSociety;
return costItemId switch
{ {
ItemWolfMarks or ItemTrophyCrystals => ESetType.PvP, HelpMessage = "Shows the glamour set tracker"
ItemMgp => ESetType.MGP, });
_ => ESetType.Default, _addonLifecycle.RegisterListener(AddonEvent.PostRefresh, "MiragePrismPrismBox", UpdateFromGlamourDresser);
}; _clientState.Logout += Reset;
}
private static Dictionary<uint, SpecialShopItem> BuildSpecialShopItems(IDataManager dataManager) if (_clientState.IsLoggedIn)
{ Update();
return dataManager.GetExcelSheet<SpecialShop>()
.Where(x => x.RowId > 0 && !string.IsNullOrEmpty(x.Name.ToString()))
.SelectMany(x => x.Item.SelectMany(y =>
y.ReceiveItems.Select(z => new SpecialShopItem
{
ItemId = z.Item.RowId,
CostItemId = y.ItemCosts[0].ItemCost.Value.RowId,
CostType = y.ItemCosts[0].ItemCost.Value.ItemUICategory.RowId,
CostName = y.ItemCosts[0].ItemCost.Value.Name.ToString(),
CostQuantity = y.ItemCosts[0].CurrencyCost,
})
.Where(z => z.ItemId > 0 && (z.CostItemId < 100 || z.CostType == 100))))
.GroupBy(x => x.ItemId)
.ToDictionary(x => x.Key, x => x.First());
} }
private void ProcessCommand(string command, string arguments) private void ProcessCommand(string command, string arguments)
@ -260,21 +227,6 @@ internal sealed class GlamourSetter : Window, IDisposable
return; return;
} }
unsafe
{
InventoryManager* inventoryManager = InventoryManager.Instance();
if (inventoryManager != null)
{
_ownedCurrencies[ItemMgp] = inventoryManager->GetItemCountInContainer(ItemMgp, InventoryType.Currency);
_ownedCurrencies[ItemWolfMarks] = (int)inventoryManager->GetWolfMarks();
_ownedCurrencies[ItemTrophyCrystals] = inventoryManager->GetInventoryItemCount(ItemTrophyCrystals);
foreach (var (itemId, _) in AlliedSocietyCurrencies)
_ownedCurrencies[itemId] = inventoryManager->GetInventoryItemCount(itemId);
}
else
_ownedCurrencies.Clear();
}
var ownedSets = _glamourSets.Where(x => _characterData.GlamourDresserItems.Contains(x.ItemId)).ToList(); var ownedSets = _glamourSets.Where(x => _characterData.GlamourDresserItems.Contains(x.ItemId)).ToList();
ImGui.Text( ImGui.Text(
$"Complete Sets: {ownedSets.Count} / {_glamourSets.Count(x => x.SetType != ESetType.Unobtainable || ownedSets.Contains(x))}"); $"Complete Sets: {ownedSets.Count} / {_glamourSets.Count(x => x.SetType != ESetType.Unobtainable || ownedSets.Contains(x))}");
@ -315,9 +267,7 @@ internal sealed class GlamourSetter : Window, IDisposable
var ownedItems = GetOwnedItems(); var ownedItems = GetOwnedItems();
DrawMissingItemHeader(glamourSets, setType, ownedSets, ownedItems); DrawMissingItemHeader(glamourSets, setType, ownedSets, ownedItems);
DrawSetRange(glamourSets, ownedSets, ownedItems);
using (ImRaii.Child("Sets"))
DrawSetRange(glamourSets, ownedSets, ownedItems);
} }
private void DrawSpecialtyTab(List<GlamourSet> ownedSets) private void DrawSpecialtyTab(List<GlamourSet> ownedSets)
@ -340,7 +290,7 @@ internal sealed class GlamourSetter : Window, IDisposable
DrawSetRange(glamourSets.Where(x => UndyedRathalosSets.Contains(x.ItemId)).ToList(), ownedSets, ownedItems); DrawSetRange(glamourSets.Where(x => UndyedRathalosSets.Contains(x.ItemId)).ToList(), ownedSets, ownedItems);
} }
private void DrawMissingItemHeader(List<GlamourSet> glamourSets, ESetType setType, List<GlamourSet> ownedSets, private static void DrawMissingItemHeader(List<GlamourSet> glamourSets, ESetType setType, List<GlamourSet> ownedSets,
HashSet<uint> ownedItems) HashSet<uint> ownedItems)
{ {
var missingItems = glamourSets var missingItems = glamourSets
@ -350,24 +300,15 @@ internal sealed class GlamourSetter : Window, IDisposable
if (setType == ESetType.PvP) if (setType == ESetType.PvP)
{ {
ImGui.Text( ImGui.Text(
$"Wolf Marks: {_ownedCurrencies.GetValueOrDefault(ItemWolfMarks):N0} / {missingItems.Where(x => x is { ShopItem.CostItemId: ItemWolfMarks }).Sum(x => x.ShopItem!.CostQuantity):N0}"); $"Wolf Marks: {missingItems.Where(x => x is { ShopItem.CostItemId: ItemWolfMarks }).Sum(x => x.ShopItem!.CostQuantity):N0}");
ImGui.Text( ImGui.Text(
$"Trophy Crystals: {_ownedCurrencies.GetValueOrDefault(ItemTrophyCrystals):N0} / {missingItems.Where(x => x is { ShopItem.CostItemId: ItemTrophyCrystals }).Sum(x => x.ShopItem!.CostQuantity):N0}"); $"Trophy Crystals: {missingItems.Where(x => x is { ShopItem.CostItemId: ItemTrophyCrystals }).Sum(x => x.ShopItem!.CostQuantity):N0}");
ImGui.Separator(); ImGui.Separator();
} }
else if (setType is ESetType.MGP or ESetType.Special) else if (setType is ESetType.MGP or ESetType.Special)
{ {
ImGui.Text( ImGui.Text(
$"MGP: {_ownedCurrencies.GetValueOrDefault(ItemMgp):N0} / {missingItems.Where(x => x is { ShopItem.CostItemId: ItemMgp }).Sum(x => x.ShopItem!.CostQuantity):N0}"); $"MGP: {missingItems.Where(x => x is { ShopItem.CostItemId: ItemMgp }).Sum(x => x.ShopItem!.CostQuantity):N0}");
ImGui.Separator();
}
else if (setType == ESetType.AlliedSociety)
{
foreach (var (itemId, name) in AlliedSocietyCurrencies)
{
ImGui.Text(
$"{name}: {_ownedCurrencies.GetValueOrDefault(itemId):N0} / {missingItems.Where(x => x is { ShopItem: { } shopItem } && shopItem.CostItemId == itemId).Sum(x => x.ShopItem!.CostQuantity):N0}");
}
ImGui.Separator(); ImGui.Separator();
} }
} }
@ -384,13 +325,12 @@ internal sealed class GlamourSetter : Window, IDisposable
int ownedCount = glamourSet.Items.Count(x => ownedItems.Contains(x.ItemId)); int ownedCount = glamourSet.Items.Count(x => ownedItems.Contains(x.ItemId));
if (ownedCount == glamourSet.Items.Count) if (ownedCount == glamourSet.Items.Count)
ImGui.TextColored(ImGuiColors.ParsedBlue, $"{glamourSet.Name} (Can be completed)"); ImGui.TextColored(ImGuiColors.ParsedBlue, $"{glamourSet.Name} (Can be completed)");
else if (CanAffordAllMissingGearPieces(glamourSet, ownedItems))
ImGui.TextColored(ImGuiColors.DalamudViolet, $"{glamourSet.Name} (Can afford)");
else if (ownedCount > 0) else if (ownedCount > 0)
ImGui.TextColored(ImGuiColors.DalamudYellow, glamourSet.Name); ImGui.TextColored(ImGuiColors.DalamudYellow, glamourSet.Name);
else else
ImGui.Text(glamourSet.Name); ImGui.Text(glamourSet.Name);
using (ImRaii.PushIndent()) using (ImRaii.PushIndent())
{ {
foreach (var item in glamourSet.Items) foreach (var item in glamourSet.Items)
@ -431,9 +371,6 @@ internal sealed class GlamourSetter : Window, IDisposable
foreach (var inventoryType in _inventoryTypes) foreach (var inventoryType in _inventoryTypes)
{ {
var inventoryContainer = inventoryManager->GetInventoryContainer(inventoryType); var inventoryContainer = inventoryManager->GetInventoryContainer(inventoryType);
if (inventoryContainer == null)
continue;
for (int i = 0; i < inventoryContainer->Size; ++i) for (int i = 0; i < inventoryContainer->Size; ++i)
{ {
InventoryItem* item = inventoryContainer->GetInventorySlot(i); InventoryItem* item = inventoryContainer->GetInventorySlot(i);
@ -447,25 +384,6 @@ internal sealed class GlamourSetter : Window, IDisposable
return ownedItems; return ownedItems;
} }
private bool CanAffordAllMissingGearPieces(GlamourSet glamourSet, HashSet<uint> ownedItems)
{
uint costItemId = 0;
uint costQuantity = 0;
foreach (var item in glamourSet.Items)
{
if (ownedItems.Contains(item.ItemId))
continue;
if (item.ShopItem == null)
return false;
costItemId = item.ShopItem.CostItemId;
costQuantity += item.ShopItem.CostQuantity;
}
return costQuantity <= _ownedCurrencies.GetValueOrDefault(costItemId);
}
private unsafe void UpdateFromGlamourDresser(AddonEvent type, AddonArgs args) private unsafe void UpdateFromGlamourDresser(AddonEvent type, AddonArgs args)
{ {
if (_characterData == null) if (_characterData == null)

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project> <Project>
<Target Name="PackagePluginDebug" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'"> <Target Name="PackagePlugin" AfterTargets="Build" Condition="'$(Configuration)' == 'Debug'">
<DalamudPackager <DalamudPackager
ProjectDir="$(ProjectDir)" ProjectDir="$(ProjectDir)"
OutputPath="$(OutputPath)" OutputPath="$(OutputPath)"

View File

@ -1,6 +1,6 @@
<Project Sdk="Dalamud.NET.Sdk/11.0.0"> <Project Sdk="Dalamud.NET.Sdk/11.0.0">
<PropertyGroup> <PropertyGroup>
<Version>2.3</Version> <Version>2.0</Version>
<OutputPath>dist</OutputPath> <OutputPath>dist</OutputPath>
</PropertyGroup> </PropertyGroup>