Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cd847a4fb7 | |||
| c9d2b9ce94 | |||
| f6d06a652d | |||
| 935a89847f | |||
| 7baa5965e4 | |||
| 667c54bc83 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -367,3 +367,6 @@ FodyWeavers.xsd
|
|||||||
Glamaholic/.github/
|
Glamaholic/.github/
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
|
/.claude
|
||||||
|
/.claude/settings.local.json
|
||||||
|
/nul
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using Dalamud.Game.Command;
|
using Dalamud.Game.Command;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
internal class Commands : IDisposable {
|
internal class Commands : IDisposable {
|
||||||
private Plugin Plugin { get; }
|
private Plugin Plugin { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
[Serializable]
|
[Serializable]
|
||||||
internal class Configuration : IPluginConfiguration {
|
internal class Configuration : IPluginConfiguration {
|
||||||
private const int CURRENT_VERSION = 1;
|
private const int CURRENT_VERSION = 1;
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ using System;
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
internal class DataCache {
|
internal class DataCache {
|
||||||
public static Lazy<ImmutableList<Item>> EquippableItems { get; } =
|
public static Lazy<ImmutableList<Item>> EquippableItems { get; } =
|
||||||
new(() => Service.DataManager.GetExcelSheet<Item>(ClientLanguage.English)!
|
new(() => Service.DataManager.GetExcelSheet<Item>(ClientLanguage.English)!
|
||||||
.Where(row => row.EquipSlotCategory.RowId != 0 &&
|
.Where(row => row.EquipSlotCategory.RowId != 0 &&
|
||||||
row.EquipSlotCategory.Value!.SoulCrystal == 0)
|
row.EquipSlotCategory.Value!.SoulCrystal == 0)
|
||||||
.ToImmutableList());
|
.ToImmutableList());
|
||||||
/*
|
|
||||||
public static Lazy<ImmutableDictionary<string, byte>> StainLookup { get; } =
|
public static Lazy<ImmutableDictionary<string, byte>> StainLookup { get; } =
|
||||||
new (() =>
|
new (() =>
|
||||||
Service.DataManager.GetExcelSheet<Stain>(ClientLanguage.English)!
|
Service.DataManager.GetExcelSheet<Stain>(ClientLanguage.English)!
|
||||||
@@ -20,7 +20,17 @@ namespace Glamaholic {
|
|||||||
.ToImmutableDictionary(static row =>
|
.ToImmutableDictionary(static row =>
|
||||||
row.Name.ExtractText().Trim().ToLower(), static row => (byte) row.RowId));
|
row.Name.ExtractText().Trim().ToLower(), static row => (byte) row.RowId));
|
||||||
|
|
||||||
|
public static Lazy<ImmutableList<(byte Id, string Name, uint Color, bool Gloss)>> AllStains { get; } =
|
||||||
|
new(() => Service.DataManager.GetExcelSheet<Stain>(ClientLanguage.English)!
|
||||||
|
.Where(row => row.RowId != 0 && !row.Name.IsEmpty)
|
||||||
|
.Select(row => ((byte)row.RowId, row.Name.ExtractText(), SeColorToRgba(row.Color), row.IsMetallic))
|
||||||
|
.ToImmutableList());
|
||||||
|
|
||||||
|
// Convert SE's BGR color format to RGBA
|
||||||
|
private static uint SeColorToRgba(uint color)
|
||||||
|
=> ((color & 0xFF) << 16) | ((color >> 16) & 0xFF) | (color & 0xFF00) | 0xFF000000;
|
||||||
|
|
||||||
public static int GetNumStainSlots(uint itemId) =>
|
public static int GetNumStainSlots(uint itemId) =>
|
||||||
Service.DataManager.GetExcelSheet<Item>(ClientLanguage.English)!.GetRowOrDefault(itemId)?.DyeCount ?? 0;*/
|
Service.DataManager.GetExcelSheet<Item>(ClientLanguage.English)!.GetRowOrDefault(itemId)?.DyeCount ?? 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
60
GlamourBrowser/Interop/AT.cs
Normal file
60
GlamourBrowser/Interop/AT.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using Dalamud.Plugin;
|
||||||
|
using Dalamud.Plugin.Ipc;
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using HeightAdjuster.Interop.Glamourer;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace GlamourBrowser.Interop {
|
||||||
|
internal class AT {
|
||||||
|
|
||||||
|
private static bool Initialized { get; set; } = false;
|
||||||
|
private static bool Available { get; set; } = false;
|
||||||
|
private static ICommandManager _commandManager;
|
||||||
|
private static IChatGui _chatGui;
|
||||||
|
|
||||||
|
|
||||||
|
public static void Initialize(ICommandManager commandManager, IDalamudPluginInterface pluginInterface, IChatGui chatGui) {
|
||||||
|
if (Initialized)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_commandManager = commandManager;
|
||||||
|
_chatGui = chatGui;
|
||||||
|
|
||||||
|
Initialized = true;
|
||||||
|
|
||||||
|
RefreshStatus(pluginInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RefreshStatus(IDalamudPluginInterface pluginInterface) {
|
||||||
|
var prev = Available;
|
||||||
|
|
||||||
|
Available = false;
|
||||||
|
|
||||||
|
foreach (var plugin in pluginInterface.InstalledPlugins) {
|
||||||
|
if (plugin.InternalName == "InventoryTools") {
|
||||||
|
Available = plugin.IsLoaded;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prev == Available)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void OpenMoreInformationSub(string itemId) {
|
||||||
|
if (IsAvailable()) {
|
||||||
|
_commandManager.ProcessCommand("/moreinfo " + itemId);
|
||||||
|
} else {
|
||||||
|
_chatGui.PrintError("Allagan Tools was not detected, please install it to get more information about this item.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static bool IsAvailable() {
|
||||||
|
return Available;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ using HeightAdjuster.Interop.Glamourer;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Glamaholic.Interop {
|
namespace GlamourBrowser.Interop {
|
||||||
internal class Glamourer {
|
internal class Glamourer {
|
||||||
private static SetItem _SetItem { get; set; } = null!;
|
private static SetItem _SetItem { get; set; } = null!;
|
||||||
private static GetState _GetState { get; set; } = null!;
|
private static GetState _GetState { get; set; } = null!;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using Dalamud.Plugin;
|
|||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
public class Plugin : IDalamudPlugin {
|
public class Plugin : IDalamudPlugin {
|
||||||
internal static string Name => "GlamourBrowser";
|
internal static string Name => "GlamourBrowser";
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@ namespace Glamaholic {
|
|||||||
this.Commands = new Commands(this);
|
this.Commands = new Commands(this);
|
||||||
|
|
||||||
Interop.Glamourer.Initialize(Service.Interface);
|
Interop.Glamourer.Initialize(Service.Interface);
|
||||||
|
Interop.AT.Initialize(Service.CommandManager, Service.Interface, Service.ChatGui);
|
||||||
Service.Framework.Update += OnFrameworkUpdate;
|
Service.Framework.Update += OnFrameworkUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ namespace Glamaholic {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Interop.Glamourer.RefreshStatus(Service.Interface);
|
Interop.Glamourer.RefreshStatus(Service.Interface);
|
||||||
|
Interop.AT.RefreshStatus(Service.Interface);
|
||||||
|
|
||||||
LastInteropCheckTime = now;
|
LastInteropCheckTime = now;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using Dalamud.Interface.Textures.TextureWraps;
|
using Dalamud.Interface.Textures.TextureWraps;
|
||||||
using Glamaholic.Ui;
|
using GlamourBrowser.Ui;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
internal class PluginUi : IDisposable {
|
internal class PluginUi : IDisposable {
|
||||||
internal Plugin Plugin { get; }
|
internal Plugin Plugin { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using Dalamud.IoC;
|
|||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
|
||||||
namespace Glamaholic {
|
namespace GlamourBrowser {
|
||||||
internal class Service {
|
internal class Service {
|
||||||
[PluginService] internal static IPluginLog Log { get; private set; } = null!;
|
[PluginService] internal static IPluginLog Log { get; private set; } = null!;
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using System.Collections.Immutable;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
|
||||||
namespace Glamaholic.Ui {
|
namespace GlamourBrowser.Ui {
|
||||||
internal class MainInterface {
|
internal class MainInterface {
|
||||||
internal const int IconSize = 48;
|
internal const int IconSize = 48;
|
||||||
private const int ItemsPerRow = 5;
|
private const int ItemsPerRow = 5;
|
||||||
@@ -18,8 +18,8 @@ namespace Glamaholic.Ui {
|
|||||||
|
|
||||||
private enum ItemCategory {
|
private enum ItemCategory {
|
||||||
Head,
|
Head,
|
||||||
Gloves,
|
|
||||||
Body,
|
Body,
|
||||||
|
Gloves,
|
||||||
Legs,
|
Legs,
|
||||||
Feet,
|
Feet,
|
||||||
}
|
}
|
||||||
@@ -29,12 +29,15 @@ namespace Glamaholic.Ui {
|
|||||||
private Dictionary<ItemCategory, Item?> SelectedItems { get; set; } = new();
|
private Dictionary<ItemCategory, Item?> SelectedItems { get; set; } = new();
|
||||||
private Dictionary<ItemCategory, List<Item>> FilteredItemsCache { get; set; } = new();
|
private Dictionary<ItemCategory, List<Item>> FilteredItemsCache { get; set; } = new();
|
||||||
private Dictionary<ItemCategory, float> ScrollPositions { get; set; } = new();
|
private Dictionary<ItemCategory, float> ScrollPositions { get; set; } = new();
|
||||||
|
private Dictionary<ItemCategory, byte> SelectedStain1 { get; set; } = new();
|
||||||
|
private Dictionary<ItemCategory, byte> SelectedStain2 { get; set; } = new();
|
||||||
|
|
||||||
private bool _visible;
|
private bool _visible;
|
||||||
private string _itemFilter = string.Empty;
|
private string _itemFilter = string.Empty;
|
||||||
private ItemCategory _currentCategory = ItemCategory.Head;
|
private ItemCategory _currentCategory = ItemCategory.Head;
|
||||||
private ItemCategory _previousCategory = ItemCategory.Head;
|
private ItemCategory _previousCategory = ItemCategory.Head;
|
||||||
private string _lastFilterUsed = string.Empty;
|
private string _lastFilterUsed = string.Empty;
|
||||||
|
private string _dyeFilter = string.Empty;
|
||||||
|
|
||||||
internal MainInterface(PluginUi ui) {
|
internal MainInterface(PluginUi ui) {
|
||||||
this.Ui = ui;
|
this.Ui = ui;
|
||||||
@@ -44,10 +47,23 @@ namespace Glamaholic.Ui {
|
|||||||
|
|
||||||
private void InitializeSelectedItems() {
|
private void InitializeSelectedItems() {
|
||||||
SelectedItems[ItemCategory.Head] = null;
|
SelectedItems[ItemCategory.Head] = null;
|
||||||
SelectedItems[ItemCategory.Gloves] = null;
|
|
||||||
SelectedItems[ItemCategory.Body] = null;
|
SelectedItems[ItemCategory.Body] = null;
|
||||||
|
SelectedItems[ItemCategory.Gloves] = null;
|
||||||
SelectedItems[ItemCategory.Legs] = null;
|
SelectedItems[ItemCategory.Legs] = null;
|
||||||
SelectedItems[ItemCategory.Feet] = null;
|
SelectedItems[ItemCategory.Feet] = null;
|
||||||
|
|
||||||
|
// Initialize dye selections (0 = no dye)
|
||||||
|
SelectedStain1[ItemCategory.Head] = 0;
|
||||||
|
SelectedStain1[ItemCategory.Body] = 0;
|
||||||
|
SelectedStain1[ItemCategory.Gloves] = 0;
|
||||||
|
SelectedStain1[ItemCategory.Legs] = 0;
|
||||||
|
SelectedStain1[ItemCategory.Feet] = 0;
|
||||||
|
|
||||||
|
SelectedStain2[ItemCategory.Head] = 0;
|
||||||
|
SelectedStain2[ItemCategory.Body] = 0;
|
||||||
|
SelectedStain2[ItemCategory.Gloves] = 0;
|
||||||
|
SelectedStain2[ItemCategory.Legs] = 0;
|
||||||
|
SelectedStain2[ItemCategory.Feet] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadItemsByCategory() {
|
private void LoadItemsByCategory() {
|
||||||
@@ -64,17 +80,6 @@ namespace Glamaholic.Ui {
|
|||||||
.OrderBy(item => item.RowId)
|
.OrderBy(item => item.RowId)
|
||||||
.ToImmutableList();
|
.ToImmutableList();
|
||||||
|
|
||||||
ItemsByCategory[ItemCategory.Gloves] = equippableItems
|
|
||||||
.Where(item => {
|
|
||||||
if (!item.EquipSlotCategory.IsValid) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var equipSlot = item.EquipSlotCategory.Value;
|
|
||||||
return equipSlot.Gloves > 0;
|
|
||||||
})
|
|
||||||
.OrderBy(item => item.RowId)
|
|
||||||
.ToImmutableList();
|
|
||||||
|
|
||||||
ItemsByCategory[ItemCategory.Body] = equippableItems
|
ItemsByCategory[ItemCategory.Body] = equippableItems
|
||||||
.Where(item => {
|
.Where(item => {
|
||||||
if (!item.EquipSlotCategory.IsValid) {
|
if (!item.EquipSlotCategory.IsValid) {
|
||||||
@@ -86,6 +91,17 @@ namespace Glamaholic.Ui {
|
|||||||
.OrderBy(item => item.RowId)
|
.OrderBy(item => item.RowId)
|
||||||
.ToImmutableList();
|
.ToImmutableList();
|
||||||
|
|
||||||
|
ItemsByCategory[ItemCategory.Gloves] = equippableItems
|
||||||
|
.Where(item => {
|
||||||
|
if (!item.EquipSlotCategory.IsValid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var equipSlot = item.EquipSlotCategory.Value;
|
||||||
|
return equipSlot.Gloves > 0;
|
||||||
|
})
|
||||||
|
.OrderBy(item => item.RowId)
|
||||||
|
.ToImmutableList();
|
||||||
|
|
||||||
ItemsByCategory[ItemCategory.Legs] = equippableItems
|
ItemsByCategory[ItemCategory.Legs] = equippableItems
|
||||||
.Where(item => {
|
.Where(item => {
|
||||||
if (!item.EquipSlotCategory.IsValid) {
|
if (!item.EquipSlotCategory.IsValid) {
|
||||||
@@ -204,8 +220,8 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void DrawSelectedGearDisplay() {
|
private unsafe void DrawSelectedGearDisplay() {
|
||||||
var categories = new[] { ItemCategory.Head, ItemCategory.Gloves, ItemCategory.Body, ItemCategory.Legs, ItemCategory.Feet };
|
var categories = new[] { ItemCategory.Head, ItemCategory.Body, ItemCategory.Gloves, ItemCategory.Legs, ItemCategory.Feet };
|
||||||
var categoryLabels = new[] { "Hat", "Gloves", "Top", "Bottom", "Shoes" };
|
var categoryLabels = new[] { "Hat", "Top", "Gloves", "Bottom", "Shoes" };
|
||||||
|
|
||||||
for (int i = 0; i < categories.Length; i++) {
|
for (int i = 0; i < categories.Length; i++) {
|
||||||
var category = categories[i];
|
var category = categories[i];
|
||||||
@@ -213,11 +229,24 @@ namespace Glamaholic.Ui {
|
|||||||
var selectedItem = SelectedItems[category];
|
var selectedItem = SelectedItems[category];
|
||||||
|
|
||||||
ImGui.TextUnformatted(label);
|
ImGui.TextUnformatted(label);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(2, 2));
|
||||||
|
if (ImGui.Button($"?##info-{label}", new Vector2(20, 20))) {
|
||||||
|
if (selectedItem.HasValue) {
|
||||||
|
Interop.AT.OpenMoreInformationSub(selectedItem.Value.RowId.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui.PopStyleVar();
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered()) {
|
||||||
|
ImGui.SetTooltip("Click to see item location");
|
||||||
|
}
|
||||||
|
|
||||||
var drawCursor = ImGui.GetCursorScreenPos();
|
var drawCursor = ImGui.GetCursorScreenPos();
|
||||||
var slotSize = SelectedGearIconSize + SelectedGearPaddingSize;
|
var slotSize = SelectedGearIconSize + SelectedGearPaddingSize;
|
||||||
var borderColour = *ImGui.GetStyleColorVec4(ImGuiCol.Border);
|
var borderColour = *ImGui.GetStyleColorVec4(ImGuiCol.Border);
|
||||||
|
|
||||||
ImGui.GetWindowDrawList().AddRect(
|
ImGui.GetWindowDrawList().AddRect(
|
||||||
drawCursor,
|
drawCursor,
|
||||||
drawCursor + new Vector2(slotSize),
|
drawCursor + new Vector2(slotSize),
|
||||||
@@ -241,6 +270,24 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui.TextUnformatted(selectedItem.Value.Name.ExtractText());
|
ImGui.TextUnformatted(selectedItem.Value.Name.ExtractText());
|
||||||
|
|
||||||
|
// Draw dye controls - always show both slots
|
||||||
|
ImGui.PushItemWidth(-1);
|
||||||
|
|
||||||
|
// Primary dye
|
||||||
|
if (DrawDyeCombo($"##dye1-{label}", SelectedStain1, category, true)) {
|
||||||
|
// Apply the dye change immediately
|
||||||
|
this.ApplyItemToCharacter(selectedItem.Value, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Secondary dye
|
||||||
|
if (DrawDyeCombo($"##dye2-{label}", SelectedStain2, category, false)) {
|
||||||
|
// Apply the dye change immediately
|
||||||
|
this.ApplyItemToCharacter(selectedItem.Value, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopItemWidth();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ImGui.SetCursorPos(cursorAfter);
|
ImGui.SetCursorPos(cursorAfter);
|
||||||
ImGui.TextUnformatted("(empty)");
|
ImGui.TextUnformatted("(empty)");
|
||||||
@@ -261,6 +308,137 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe bool DrawDyeCombo(string id, Dictionary<ItemCategory, byte> stainDict, ItemCategory category, bool isPrimary) {
|
||||||
|
var allStains = DataCache.AllStains.Value;
|
||||||
|
var currentStain = stainDict[category];
|
||||||
|
|
||||||
|
// Find the current stain info
|
||||||
|
string previewName = "None";
|
||||||
|
uint previewColor = 0;
|
||||||
|
bool previewGloss = false;
|
||||||
|
if (currentStain != 0) {
|
||||||
|
var stain = allStains.FirstOrDefault(s => s.Id == currentStain);
|
||||||
|
if (stain != default) {
|
||||||
|
previewName = stain.Name;
|
||||||
|
previewColor = stain.Color;
|
||||||
|
previewGloss = stain.Gloss;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate contrast color for text
|
||||||
|
var textColor = GetContrastColor(previewColor);
|
||||||
|
|
||||||
|
bool changed = false;
|
||||||
|
|
||||||
|
// Draw preview button with color
|
||||||
|
if (previewColor != 0) {
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.FrameBg, previewColor);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Text, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.BeginCombo(id, previewName, ImGuiComboFlags.HeightLarge)) {
|
||||||
|
if (previewColor != 0) {
|
||||||
|
ImGui.PopStyleColor(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search filter
|
||||||
|
ImGui.SetNextItemWidth(-1);
|
||||||
|
ImGui.InputTextWithHint("##dyefilter", "Search dyes...", ref _dyeFilter, 256);
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
// Filter dyes based on search
|
||||||
|
IEnumerable<(byte Id, string Name, uint Color, bool Gloss)> filteredStains = string.IsNullOrEmpty(_dyeFilter)
|
||||||
|
? allStains
|
||||||
|
: allStains.Where(s => s.Name.Contains(_dyeFilter, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
// None option
|
||||||
|
var noneColor = ImGui.ColorConvertFloat4ToU32(new Vector4(0.2f, 0.2f, 0.2f, 1.0f));
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Button, noneColor);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, noneColor + 0x202020);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonActive, noneColor + 0x404040);
|
||||||
|
if (ImGui.Button("None", new Vector2(-1, 0))) {
|
||||||
|
stainDict[category] = 0;
|
||||||
|
changed = true;
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui.PopStyleColor(3);
|
||||||
|
|
||||||
|
// All filtered dyes
|
||||||
|
foreach (var stain in filteredStains) {
|
||||||
|
var stainTextColor = GetContrastColor(stain.Color);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Button, stain.Color);
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, AdjustBrightness(stain.Color, 1.1f));
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.ButtonActive, AdjustBrightness(stain.Color, 0.9f));
|
||||||
|
ImGui.PushStyleColor(ImGuiCol.Text, stainTextColor);
|
||||||
|
|
||||||
|
if (ImGui.Button($"{stain.Name}##{stain.Id}", new Vector2(-1, 0))) {
|
||||||
|
stainDict[category] = stain.Id;
|
||||||
|
changed = true;
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw gloss overlay
|
||||||
|
if (stain.Gloss) {
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
var min = ImGui.GetItemRectMin();
|
||||||
|
var max = ImGui.GetItemRectMax();
|
||||||
|
drawList.AddRectFilledMultiColor(min, max,
|
||||||
|
0x50FFFFFF, 0x50000000, 0x50FFFFFF, 0x50000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selection indicator
|
||||||
|
if (currentStain == stain.Id) {
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
var min = ImGui.GetItemRectMin();
|
||||||
|
var max = ImGui.GetItemRectMax();
|
||||||
|
drawList.AddRect(min, max, 0xFF2020D0, 0, ImDrawFlags.None, 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.PopStyleColor(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
} else {
|
||||||
|
if (previewColor != 0) {
|
||||||
|
ImGui.PopStyleColor(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw gloss overlay on preview
|
||||||
|
if (previewGloss) {
|
||||||
|
var drawList = ImGui.GetWindowDrawList();
|
||||||
|
var min = ImGui.GetItemRectMin();
|
||||||
|
var max = ImGui.GetItemRectMax();
|
||||||
|
drawList.AddRectFilledMultiColor(min, max,
|
||||||
|
0x50FFFFFF, 0x50000000, 0x50FFFFFF, 0x50000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right-click to clear
|
||||||
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && currentStain != 0) {
|
||||||
|
stainDict[category] = 0;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint GetContrastColor(uint rgba) {
|
||||||
|
float r = ((rgba >> 0) & 0xFF) / 255.0f;
|
||||||
|
float g = ((rgba >> 8) & 0xFF) / 255.0f;
|
||||||
|
float b = ((rgba >> 16) & 0xFF) / 255.0f;
|
||||||
|
float luminance = 0.299f * r + 0.587f * g + 0.114f * b;
|
||||||
|
return luminance > 0.5f ? 0xFF000000 : 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static uint AdjustBrightness(uint rgba, float factor) {
|
||||||
|
byte r = (byte)Math.Min(255, ((rgba >> 0) & 0xFF) * factor);
|
||||||
|
byte g = (byte)Math.Min(255, ((rgba >> 8) & 0xFF) * factor);
|
||||||
|
byte b = (byte)Math.Min(255, ((rgba >> 16) & 0xFF) * factor);
|
||||||
|
byte a = (byte)((rgba >> 24) & 0xFF);
|
||||||
|
return (uint)(r | (g << 8) | (b << 16) | (a << 24));
|
||||||
|
}
|
||||||
|
|
||||||
private void ApplySelectedGearToCharacter() {
|
private void ApplySelectedGearToCharacter() {
|
||||||
if (Service.ObjectTable.LocalPlayer == null) {
|
if (Service.ObjectTable.LocalPlayer == null) {
|
||||||
Service.ChatGui.PrintError("[Glamour Browser] No character found.");
|
Service.ChatGui.PrintError("[Glamour Browser] No character found.");
|
||||||
@@ -278,16 +456,18 @@ namespace Glamaholic.Ui {
|
|||||||
var slotMappings = new Dictionary<ItemCategory, Glamourer.Api.Enums.ApiEquipSlot>
|
var slotMappings = new Dictionary<ItemCategory, Glamourer.Api.Enums.ApiEquipSlot>
|
||||||
{
|
{
|
||||||
{ ItemCategory.Head, Glamourer.Api.Enums.ApiEquipSlot.Head },
|
{ ItemCategory.Head, Glamourer.Api.Enums.ApiEquipSlot.Head },
|
||||||
{ ItemCategory.Gloves, Glamourer.Api.Enums.ApiEquipSlot.Hands },
|
|
||||||
{ ItemCategory.Body, Glamourer.Api.Enums.ApiEquipSlot.Body },
|
{ ItemCategory.Body, Glamourer.Api.Enums.ApiEquipSlot.Body },
|
||||||
|
{ ItemCategory.Gloves, Glamourer.Api.Enums.ApiEquipSlot.Hands },
|
||||||
{ ItemCategory.Legs, Glamourer.Api.Enums.ApiEquipSlot.Legs },
|
{ ItemCategory.Legs, Glamourer.Api.Enums.ApiEquipSlot.Legs },
|
||||||
{ ItemCategory.Feet, Glamourer.Api.Enums.ApiEquipSlot.Feet },
|
{ ItemCategory.Feet, Glamourer.Api.Enums.ApiEquipSlot.Feet },
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var (category, glamourerSlot) in slotMappings) {
|
foreach (var (category, glamourerSlot) in slotMappings) {
|
||||||
if (SelectedItems[category].HasValue) {
|
if (SelectedItems[category] is { } item) {
|
||||||
var item = SelectedItems[category].Value;
|
var stain1 = SelectedStain1[category];
|
||||||
Interop.Glamourer.SetItem(playerIndex, glamourerSlot, item.RowId, []);
|
var stain2 = SelectedStain2[category];
|
||||||
|
var stains = new byte[] { stain1, stain2 };
|
||||||
|
Interop.Glamourer.SetItem(playerIndex, glamourerSlot, item.RowId, stains);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,10 +479,10 @@ namespace Glamaholic.Ui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void DrawTabs() {
|
private void DrawTabs() {
|
||||||
if (ImGui.BeginTabBar("item-category-tabs")) {
|
if (ImGui.BeginTabBar("item-category-tabs2")) {
|
||||||
DrawTabButton("Hat", ItemCategory.Head);
|
DrawTabButton("Hat", ItemCategory.Head);
|
||||||
DrawTabButton("Gloves", ItemCategory.Gloves);
|
|
||||||
DrawTabButton("Top", ItemCategory.Body);
|
DrawTabButton("Top", ItemCategory.Body);
|
||||||
|
DrawTabButton("Gloves", ItemCategory.Gloves);
|
||||||
DrawTabButton("Bottom", ItemCategory.Legs);
|
DrawTabButton("Bottom", ItemCategory.Legs);
|
||||||
DrawTabButton("Shoes", ItemCategory.Feet);
|
DrawTabButton("Shoes", ItemCategory.Feet);
|
||||||
|
|
||||||
@@ -434,14 +614,17 @@ namespace Glamaholic.Ui {
|
|||||||
var slotMapping = new Dictionary<ItemCategory, Glamourer.Api.Enums.ApiEquipSlot>
|
var slotMapping = new Dictionary<ItemCategory, Glamourer.Api.Enums.ApiEquipSlot>
|
||||||
{
|
{
|
||||||
{ ItemCategory.Head, Glamourer.Api.Enums.ApiEquipSlot.Head },
|
{ ItemCategory.Head, Glamourer.Api.Enums.ApiEquipSlot.Head },
|
||||||
{ ItemCategory.Gloves, Glamourer.Api.Enums.ApiEquipSlot.Hands },
|
|
||||||
{ ItemCategory.Body, Glamourer.Api.Enums.ApiEquipSlot.Body },
|
{ ItemCategory.Body, Glamourer.Api.Enums.ApiEquipSlot.Body },
|
||||||
|
{ ItemCategory.Gloves, Glamourer.Api.Enums.ApiEquipSlot.Hands },
|
||||||
{ ItemCategory.Legs, Glamourer.Api.Enums.ApiEquipSlot.Legs },
|
{ ItemCategory.Legs, Glamourer.Api.Enums.ApiEquipSlot.Legs },
|
||||||
{ ItemCategory.Feet, Glamourer.Api.Enums.ApiEquipSlot.Feet },
|
{ ItemCategory.Feet, Glamourer.Api.Enums.ApiEquipSlot.Feet },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (slotMapping.TryGetValue(category, out var glamourerSlot)) {
|
if (slotMapping.TryGetValue(category, out var glamourerSlot)) {
|
||||||
Interop.Glamourer.SetItem(playerIndex, glamourerSlot, item.RowId, []);
|
var stain1 = SelectedStain1[category];
|
||||||
|
var stain2 = SelectedStain2[category];
|
||||||
|
var stains = new byte[] { stain1, stain2 };
|
||||||
|
Interop.Glamourer.SetItem(playerIndex, glamourerSlot, item.RowId, stains);
|
||||||
}
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Service.Log.Error(ex, "Failed to apply item to character");
|
Service.Log.Error(ex, "Failed to apply item to character");
|
||||||
|
|||||||
Reference in New Issue
Block a user