forked from liza/ARDiscard
Refactoring, allow unique/untradeable items that can be purchased after completing quests to be discarded
This commit is contained in:
parent
5817f8c976
commit
ce37130390
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<Version>3.8</Version>
|
||||
<Version>4.0</Version>
|
||||
<LangVersion>11.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
|
@ -1,14 +1,11 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ARDiscard.GameData;
|
||||
using ARDiscard.GameData.Agents;
|
||||
using ARDiscard.Windows;
|
||||
using Dalamud.ContextMenu;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Game.Text.SeStringHandling.Payloads;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
|
||||
namespace ARDiscard;
|
||||
|
||||
@ -52,18 +49,7 @@ internal sealed class ContextMenuIntegration : IDisposable
|
||||
if (_configuration.ContextMenu.OnlyWhenConfigIsOpen && !_configWindow.IsOpen)
|
||||
return;
|
||||
|
||||
if (args.ParentAddonName == "ArmouryBoard")
|
||||
{
|
||||
var agent = AgentModule.Instance()->GetAgentByInternalId(AgentId.ArmouryBoard);
|
||||
if (agent == null || !agent->IsAgentActive())
|
||||
return;
|
||||
|
||||
// don't add it in the main/off hand weapon tabs, as we don't use these for discarding
|
||||
var agentArmouryBoard = (AgentArmouryBoard*)agent;
|
||||
if (agentArmouryBoard->CurrentTab is 0 or 6)
|
||||
return;
|
||||
}
|
||||
else if (!(args.ParentAddonName is "Inventory" or "InventoryExpansion" or "InventoryLarge"))
|
||||
if (!(args.ParentAddonName is "Inventory" or "InventoryExpansion" or "InventoryLarge" or "ArmouryBoard"))
|
||||
return;
|
||||
|
||||
if (!_configWindow.CanItemBeConfigured(args.ItemId))
|
||||
@ -71,7 +57,8 @@ internal sealed class ContextMenuIntegration : IDisposable
|
||||
|
||||
if (_configuration.DiscardingItems.Contains(args.ItemId))
|
||||
args.AddCustomItem(_removeItem);
|
||||
else if (!InternalConfiguration.BlacklistedItems.Contains(args.ItemId))
|
||||
else if (_itemCache.TryGetItem(args.ItemId, out ItemCache.CachedItemInfo? cachedItemInfo) &&
|
||||
cachedItemInfo.CanBeDiscarded())
|
||||
args.AddCustomItem(_addItem);
|
||||
}
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using FFXIVClientStructs.Attributes;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
|
||||
namespace ARDiscard.GameData.Agents;
|
||||
|
||||
[Agent(AgentId.ArmouryBoard)]
|
||||
[StructLayout(LayoutKind.Explicit, Size = 0x2E)]
|
||||
public struct AgentArmouryBoard
|
||||
{
|
||||
[FieldOffset(0x2C)] public byte CurrentTab;
|
||||
}
|
@ -42,6 +42,9 @@ internal static class InternalConfiguration
|
||||
9390, // Antique Breeches
|
||||
9391, // Antique Sollerets
|
||||
|
||||
6223, // Mended Imperial Pot Helm
|
||||
6224, // Mended Imperial Short Robe
|
||||
|
||||
#region Fate drops used in tribal quests
|
||||
|
||||
7001, // Flamefang Choker (Amalj'aa)
|
||||
|
@ -35,6 +35,8 @@ internal sealed class InventoryUtils
|
||||
InventoryType.ArmoryRings
|
||||
};
|
||||
|
||||
private static readonly IReadOnlyList<uint> NoGearsetItems = new List<uint>();
|
||||
|
||||
private readonly Configuration _configuration;
|
||||
private readonly ItemCache _itemCache;
|
||||
private readonly IPluginLog _pluginLog;
|
||||
@ -53,7 +55,7 @@ internal sealed class InventoryUtils
|
||||
|
||||
InventoryManager* inventoryManager = InventoryManager.Instance();
|
||||
foreach (InventoryType inventoryType in DefaultInventoryTypes)
|
||||
toDiscard.AddRange(GetItemsToDiscard(inventoryManager, inventoryType, itemCounts, false, null));
|
||||
toDiscard.AddRange(GetItemsToDiscard(inventoryManager, inventoryType, itemCounts, NoGearsetItems));
|
||||
|
||||
if (_configuration.Armoury.DiscardFromArmouryChest)
|
||||
{
|
||||
@ -62,14 +64,14 @@ internal sealed class InventoryUtils
|
||||
if (_configuration.Armoury.CheckLeftSideGear)
|
||||
{
|
||||
foreach (InventoryType inventoryType in LeftSideGearInventoryTypes)
|
||||
toDiscard.AddRange(GetItemsToDiscard(inventoryManager, inventoryType, itemCounts, true,
|
||||
toDiscard.AddRange(GetItemsToDiscard(inventoryManager, inventoryType, itemCounts,
|
||||
gearsetItems));
|
||||
}
|
||||
|
||||
if (_configuration.Armoury.CheckRightSideGear)
|
||||
{
|
||||
foreach (InventoryType inventoryType in RightSideGearInventoryTypes)
|
||||
toDiscard.AddRange(GetItemsToDiscard(inventoryManager, inventoryType, itemCounts, true,
|
||||
toDiscard.AddRange(GetItemsToDiscard(inventoryManager, inventoryType, itemCounts,
|
||||
gearsetItems));
|
||||
}
|
||||
}
|
||||
@ -88,7 +90,7 @@ internal sealed class InventoryUtils
|
||||
}
|
||||
|
||||
private unsafe IReadOnlyList<ItemWrapper> GetItemsToDiscard(InventoryManager* inventoryManager,
|
||||
InventoryType inventoryType, Dictionary<uint, uint> itemCounts, bool doGearChecks,
|
||||
InventoryType inventoryType, Dictionary<uint, uint> itemCounts,
|
||||
IReadOnlyList<uint>? gearsetItems)
|
||||
{
|
||||
List<ItemWrapper> toDiscard = new List<ItemWrapper>();
|
||||
@ -107,18 +109,16 @@ internal sealed class InventoryUtils
|
||||
if (InternalConfiguration.BlacklistedItems.Contains(item->ItemID))
|
||||
continue;
|
||||
|
||||
if (doGearChecks)
|
||||
{
|
||||
if (gearsetItems == null || gearsetItems.Contains(item->ItemID))
|
||||
continue;
|
||||
if (!_itemCache.TryGetItem(item->ItemID, out ItemCache.CachedItemInfo? itemInfo) || !itemInfo.CanBeDiscarded())
|
||||
continue; // no info, who knows what that item is
|
||||
|
||||
ItemCache.CachedItemInfo? itemInfo = _itemCache.GetItem(item->ItemID);
|
||||
if (itemInfo == null)
|
||||
continue; // no info, who knows what that item is
|
||||
// skip gear if we're unable to load gearsets or it is used in a gearset
|
||||
if (itemInfo.EquipSlotCategory > 0 && (gearsetItems == null || gearsetItems.Contains(item->ItemID)))
|
||||
continue;
|
||||
|
||||
if (itemInfo.ILvl >= _configuration.Armoury.MaximumGearItemLevel)
|
||||
continue;
|
||||
}
|
||||
if (itemInfo is { EquipSlotCategory: > 0, CanBeBoughtFromCalamitySalvager: false } &&
|
||||
itemInfo.ILvl >= _configuration.Armoury.MaximumGearItemLevel)
|
||||
continue;
|
||||
|
||||
//PluginLog.Verbose($"{i} → {item->ItemID}");
|
||||
if (_configuration.DiscardingItems.Contains(item->ItemID))
|
||||
|
@ -1,5 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace ARDiscard.GameData;
|
||||
@ -28,12 +31,45 @@ internal sealed class ItemCache
|
||||
Level = item.LevelEquip,
|
||||
UiCategory = item.ItemUICategory.Row,
|
||||
UiCategoryName = item.ItemUICategory.Value!.Name.ToString(),
|
||||
EquipSlotCategory = item.EquipSlotCategory.Row,
|
||||
};
|
||||
}
|
||||
|
||||
foreach (var shopItem in dataManager.GetExcelSheet<GilShopItem>()!)
|
||||
{
|
||||
// exclude base ARR relics, not strictly necessary since we don't allow discarding weapons anyway
|
||||
if (shopItem.Item.Value!.Rarity == 4)
|
||||
continue;
|
||||
|
||||
// the item can be discarded already
|
||||
if (!_items.TryGetValue(shopItem.Item.Row, out CachedItemInfo? cachedItemInfo) ||
|
||||
cachedItemInfo.CanBeDiscarded())
|
||||
continue;
|
||||
|
||||
if (shopItem.AchievementRequired.Row != 0)
|
||||
continue;
|
||||
|
||||
// has a quest required to unlock from the shop
|
||||
if (!shopItem.QuestRequired.Any(CanDiscardItemsFromQuest))
|
||||
continue;
|
||||
|
||||
cachedItemInfo.CanBeBoughtFromCalamitySalvager = true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanDiscardItemsFromQuest(LazyRow<Quest> quest)
|
||||
{
|
||||
return quest.Row > 0 &&
|
||||
quest.Value?.JournalGenre.Value?.JournalCategory.Value?.JournalSection
|
||||
.Row is 0 or 1 or 6; // pre-EW MSQ, EW MSQ or Job/Class quest
|
||||
}
|
||||
|
||||
public IEnumerable<CachedItemInfo> AllItems => _items.Values;
|
||||
|
||||
|
||||
public bool TryGetItem(uint itemId, [NotNullWhen(true)] out CachedItemInfo? item)
|
||||
=> _items.TryGetValue(itemId, out item);
|
||||
|
||||
public CachedItemInfo? GetItem(uint itemId)
|
||||
{
|
||||
if (_items.TryGetValue(itemId, out var item))
|
||||
@ -71,7 +107,28 @@ internal sealed class ItemCache
|
||||
/// </summary>
|
||||
public required bool IsIndisposable { get; init; }
|
||||
|
||||
public bool CanBeBoughtFromCalamitySalvager { get; set; }
|
||||
|
||||
public required uint UiCategory { get; init; }
|
||||
public required string UiCategoryName { get; init; }
|
||||
public required uint EquipSlotCategory { get; init; }
|
||||
|
||||
public bool CanBeDiscarded()
|
||||
{
|
||||
if (InternalConfiguration.BlacklistedItems.Contains(ItemId))
|
||||
return false;
|
||||
|
||||
if (UiCategory is UiCategories.Currency or UiCategories.Crystals or UiCategories.Unobtainable)
|
||||
return false;
|
||||
|
||||
if (EquipSlotCategory is 1 or 2 or 13 or 14)
|
||||
return false;
|
||||
|
||||
if (InternalConfiguration.WhitelistedItems.Contains(ItemId))
|
||||
return true;
|
||||
|
||||
return CanBeBoughtFromCalamitySalvager ||
|
||||
this is { IsUnique: false, IsUntradable: false, IsIndisposable: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -380,11 +380,7 @@ internal sealed class ConfigWindow : LImGui.LWindow
|
||||
if (_allItems == null)
|
||||
{
|
||||
_allItems = _itemCache.AllItems
|
||||
.Where(x => !InternalConfiguration.BlacklistedItems.Contains(x.ItemId))
|
||||
.Where(x => InternalConfiguration.WhitelistedItems.Contains(x.ItemId) ||
|
||||
x is { IsUnique: false, IsUntradable: false, IsIndisposable: false })
|
||||
.Where(x => x.UiCategory != UiCategories.Currency && x.UiCategory != UiCategories.Crystals &&
|
||||
x.UiCategory != UiCategories.Unobtainable)
|
||||
.Where(x => x.CanBeDiscarded())
|
||||
.Select(x => (x.ItemId, x.Name.ToString()))
|
||||
.ToList();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user