mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Fix a bunch of shit and update.
This commit is contained in:
parent
2d5e88745f
commit
fbb41636df
9 changed files with 708 additions and 86 deletions
|
|
@ -106,7 +106,7 @@ namespace Glamourer.Customization
|
||||||
{
|
{
|
||||||
var row = _customizeSheet.GetRow(value);
|
var row = _customizeSheet.GetRow(value);
|
||||||
return row == null
|
return row == null
|
||||||
? new Customization(id, (byte) index, value, 0)
|
? new Customization(id, (byte) (index + 1), value, 0)
|
||||||
: new Customization(id, row.FeatureID, row.Icon, (ushort) row.RowId);
|
: new Customization(id, row.FeatureID, row.Icon, (ushort) row.RowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,8 +192,6 @@ namespace Glamourer.Customization
|
||||||
if (set.Faces.Count > 0)
|
if (set.Faces.Count > 0)
|
||||||
set.SetAvailable(CustomizationId.Face);
|
set.SetAvailable(CustomizationId.Face);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var count = race.ToRace() == Race.Hrothgar ? set.HairStyles.Count : set.Faces.Count;
|
var count = race.ToRace() == Race.Hrothgar ? set.HairStyles.Count : set.Faces.Count;
|
||||||
var featureDict = new List<IReadOnlyList<Customization>>(count);
|
var featureDict = new List<IReadOnlyList<Customization>>(count);
|
||||||
for (var i = 0; i < count; ++i)
|
for (var i = 0; i < count; ++i)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using ImGuiScene;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Glamourer.Customization
|
namespace Glamourer.Customization
|
||||||
|
|
@ -37,7 +39,7 @@ namespace Glamourer.Customization
|
||||||
public Race Race
|
public Race Race
|
||||||
=> Clan.ToRace();
|
=> Clan.ToRace();
|
||||||
|
|
||||||
private int _settingAvailable = DefaultAvailable;
|
private int _settingAvailable;
|
||||||
|
|
||||||
internal void SetAvailable(CustomizationId id)
|
internal void SetAvailable(CustomizationId id)
|
||||||
=> _settingAvailable |= 1 << (int) id;
|
=> _settingAvailable |= 1 << (int) id;
|
||||||
|
|
@ -71,7 +73,52 @@ namespace Glamourer.Customization
|
||||||
public IReadOnlyDictionary<CustomizationId, string> OptionName { get; internal set; } = null!;
|
public IReadOnlyDictionary<CustomizationId, string> OptionName { get; internal set; } = null!;
|
||||||
|
|
||||||
public Customization FacialFeature(int faceIdx, int idx)
|
public Customization FacialFeature(int faceIdx, int idx)
|
||||||
=> FeaturesTattoos[faceIdx][idx];
|
=> FeaturesTattoos[faceIdx - 1][idx];
|
||||||
|
|
||||||
|
public int DataByValue(CustomizationId id, byte value, out Customization? custom)
|
||||||
|
{
|
||||||
|
var type = id.ToType();
|
||||||
|
custom = null;
|
||||||
|
if (type == CharaMakeParams.MenuType.Percentage || type == CharaMakeParams.MenuType.ListSelector)
|
||||||
|
{
|
||||||
|
if (value < Count(id))
|
||||||
|
{
|
||||||
|
custom = new Customization(id, value, 0, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Get(IEnumerable<Customization> list, ref Customization? output)
|
||||||
|
{
|
||||||
|
var (val, idx) = list.Cast<Customization?>().Select((c, i) => (c, i)).FirstOrDefault(c => c.c!.Value.Value == value);
|
||||||
|
if (val == null)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
output = val;
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return id switch
|
||||||
|
{
|
||||||
|
CustomizationId.SkinColor => Get(SkinColors, ref custom),
|
||||||
|
CustomizationId.EyeColorL => Get(EyeColors, ref custom),
|
||||||
|
CustomizationId.EyeColorR => Get(EyeColors, ref custom),
|
||||||
|
CustomizationId.HairColor => Get(HairColors, ref custom),
|
||||||
|
CustomizationId.HighlightColor => Get(HighlightColors, ref custom),
|
||||||
|
CustomizationId.TattooColor => Get(TattooColors, ref custom),
|
||||||
|
CustomizationId.LipColor => Get(LipColorsDark.Concat(LipColorsLight), ref custom),
|
||||||
|
CustomizationId.FacePaintColor => Get(FacePaintColorsDark.Concat(FacePaintColorsLight), ref custom),
|
||||||
|
|
||||||
|
CustomizationId.Face => Get(Faces, ref custom),
|
||||||
|
CustomizationId.Hairstyle => Get(HairStyles, ref custom),
|
||||||
|
CustomizationId.TailEarShape => Get(TailEarShapes, ref custom),
|
||||||
|
CustomizationId.FacePaint => Get(FacePaints, ref custom),
|
||||||
|
CustomizationId.FacialFeaturesTattoos => Get(FeaturesTattoos[0], ref custom),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(id), id, null),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public Customization Data(CustomizationId id, int idx)
|
public Customization Data(CustomizationId id, int idx)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
247
Glamourer.GameData/Customization/CustomizationStruct.cs
Normal file
247
Glamourer.GameData/Customization/CustomizationStruct.cs
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
|
namespace Glamourer.Customization
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public unsafe struct CustomizationStruct
|
||||||
|
{
|
||||||
|
public CustomizationStruct(IntPtr ptr)
|
||||||
|
=> _ptr = (byte*) ptr;
|
||||||
|
|
||||||
|
private readonly byte* _ptr;
|
||||||
|
|
||||||
|
public byte this[CustomizationId id]
|
||||||
|
{
|
||||||
|
get => id switch
|
||||||
|
{
|
||||||
|
// Needs to handle the Highlander Race in enum.
|
||||||
|
CustomizationId.Race => (byte) (_ptr[(int) CustomizationId.Race] > 1 ? _ptr[(int) CustomizationId.Race] + 1 : 1),
|
||||||
|
// Needs to handle Gender.Unknown = 0.
|
||||||
|
CustomizationId.Gender => (byte) (_ptr[(int) id] + 1),
|
||||||
|
// Just a flag.
|
||||||
|
CustomizationId.HighlightsOnFlag => (byte) ((_ptr[(int) id] & 128) == 128 ? 1 : 0),
|
||||||
|
// Eye also includes iris flag at bit 128.
|
||||||
|
CustomizationId.EyeShape => (byte) (_ptr[(int) CustomizationId.EyeShape] & 127),
|
||||||
|
// Mouth also includes Lipstick flag at bit 128.
|
||||||
|
CustomizationId.Mouth => (byte) (_ptr[(int) CustomizationId.Mouth] & 127),
|
||||||
|
// FacePaint also includes Reverse bit at 128.
|
||||||
|
CustomizationId.FacePaint => (byte) (_ptr[(int) CustomizationId.FacePaint] & 127),
|
||||||
|
_ => _ptr[(int) id],
|
||||||
|
};
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_ptr[(int) id] = id switch
|
||||||
|
{
|
||||||
|
CustomizationId.Race => (byte) (value > (byte) Race.Midlander ? value - 1 : value),
|
||||||
|
CustomizationId.Gender => (byte) (value - 1),
|
||||||
|
CustomizationId.HighlightsOnFlag => (byte) (value != 0 ? 128 : 0),
|
||||||
|
CustomizationId.EyeShape => (byte) ((_ptr[(int) CustomizationId.EyeShape] & 128) | (value & 127)),
|
||||||
|
CustomizationId.Mouth => (byte) ((_ptr[(int) CustomizationId.Mouth] & 128) | (value & 127)),
|
||||||
|
CustomizationId.FacePaint => (byte) ((_ptr[(int) CustomizationId.FacePaint] & 128) | (value & 127)),
|
||||||
|
_ => value,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Race != Race.Hrothgar)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Handle Hrothgar Face being dependent on hairstyle, 2 faces per hairstyle.
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case CustomizationId.Hairstyle:
|
||||||
|
_ptr[(int) CustomizationId.Face] = (byte) ((value + 1) / 2);
|
||||||
|
break;
|
||||||
|
case CustomizationId.Face:
|
||||||
|
_ptr[(int) CustomizationId.Hairstyle] = (byte) (value * 2 - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Race Race
|
||||||
|
{
|
||||||
|
get => (Race) this[CustomizationId.Race];
|
||||||
|
set => this[CustomizationId.Race] = (byte) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Gender Gender
|
||||||
|
{
|
||||||
|
get => (Gender) this[CustomizationId.Gender];
|
||||||
|
set => this[CustomizationId.Gender] = (byte) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte BodyType
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.BodyType];
|
||||||
|
set => this[CustomizationId.BodyType] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Height
|
||||||
|
{
|
||||||
|
get => _ptr[(int) CustomizationId.Height];
|
||||||
|
set => _ptr[(int) CustomizationId.Height] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubRace Clan
|
||||||
|
{
|
||||||
|
get => (SubRace) this[CustomizationId.Clan];
|
||||||
|
set => this[CustomizationId.Clan] = (byte) value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Face
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.Face];
|
||||||
|
set => this[CustomizationId.Face] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Hairstyle
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.Hairstyle];
|
||||||
|
set => this[CustomizationId.Hairstyle] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HighlightsOn
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.HighlightsOnFlag] == 1;
|
||||||
|
set => this[CustomizationId.HighlightsOnFlag] = (byte) (value ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte SkinColor
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.SkinColor];
|
||||||
|
set => this[CustomizationId.SkinColor] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte EyeColorRight
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.EyeColorR];
|
||||||
|
set => this[CustomizationId.EyeColorR] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte HairColor
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.HairColor];
|
||||||
|
set => this[CustomizationId.HairColor] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte HighlightsColor
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.HighlightColor];
|
||||||
|
set => this[CustomizationId.HighlightColor] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool FacialFeature(int idx)
|
||||||
|
=> (this[CustomizationId.FacialFeaturesTattoos] & (1 << idx)) != 0;
|
||||||
|
|
||||||
|
public void FacialFeature(int idx, bool set)
|
||||||
|
{
|
||||||
|
if (set)
|
||||||
|
this[CustomizationId.FacialFeaturesTattoos] |= (byte) (1 << idx);
|
||||||
|
else
|
||||||
|
this[CustomizationId.FacialFeaturesTattoos] &= (byte) ~(1 << idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte FacialFeatures
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.FacialFeaturesTattoos];
|
||||||
|
set => this[CustomizationId.FacialFeaturesTattoos] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte TattooColor
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.TattooColor];
|
||||||
|
set => this[CustomizationId.TattooColor] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Eyebrow
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.Eyebrows];
|
||||||
|
set => this[CustomizationId.Eyebrows] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte EyeColorLeft
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.EyeColorL];
|
||||||
|
set => this[CustomizationId.EyeColorL] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Eye
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.EyeShape];
|
||||||
|
set => this[CustomizationId.EyeShape] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SmallIris
|
||||||
|
{
|
||||||
|
get => (_ptr[(int) CustomizationId.EyeShape] & 128) == 128;
|
||||||
|
set => _ptr[(int) CustomizationId.EyeShape] = (byte) (this[CustomizationId.EyeShape] | (value ? 128u : 0u));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Nose
|
||||||
|
{
|
||||||
|
get => _ptr[(int) CustomizationId.Nose];
|
||||||
|
set => _ptr[(int) CustomizationId.Nose] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Jaw
|
||||||
|
{
|
||||||
|
get => _ptr[(int) CustomizationId.Jaw];
|
||||||
|
set => _ptr[(int) CustomizationId.Jaw] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Mouth
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.Mouth];
|
||||||
|
set => this[CustomizationId.Mouth] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LipstickSet
|
||||||
|
{
|
||||||
|
get => (_ptr[(int) CustomizationId.Mouth] & 128) == 128;
|
||||||
|
set => _ptr[(int) CustomizationId.Mouth] = (byte) (this[CustomizationId.Mouth] | (value ? 128u : 0u));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte LipColor
|
||||||
|
{
|
||||||
|
get => _ptr[(int) CustomizationId.LipColor];
|
||||||
|
set => _ptr[(int) CustomizationId.LipColor] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte MuscleMass
|
||||||
|
{
|
||||||
|
get => _ptr[(int) CustomizationId.MuscleToneOrTailEarLength];
|
||||||
|
set => _ptr[(int) CustomizationId.MuscleToneOrTailEarLength] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte TailShape
|
||||||
|
{
|
||||||
|
get => _ptr[(int) CustomizationId.TailEarShape];
|
||||||
|
set => _ptr[(int) CustomizationId.TailEarShape] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte BustSize
|
||||||
|
{
|
||||||
|
get => _ptr[(int) CustomizationId.BustSize];
|
||||||
|
set => _ptr[(int) CustomizationId.BustSize] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte FacePaint
|
||||||
|
{
|
||||||
|
get => this[CustomizationId.FacePaint];
|
||||||
|
set => this[CustomizationId.FacePaint] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool FacePaintReversed
|
||||||
|
{
|
||||||
|
get => (_ptr[(int) CustomizationId.FacePaint] & 128) == 128;
|
||||||
|
set => _ptr[(int) CustomizationId.FacePaint] = (byte) (this[CustomizationId.FacePaint] | (value ? 128u : 0u));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte FacePaintColor
|
||||||
|
{
|
||||||
|
get => _ptr[(int) CustomizationId.FacePaintColor];
|
||||||
|
set => _ptr[(int) CustomizationId.FacePaintColor] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Glamourer.zip
BIN
Glamourer.zip
Binary file not shown.
|
|
@ -4,8 +4,8 @@
|
||||||
<LangVersion>preview</LangVersion>
|
<LangVersion>preview</LangVersion>
|
||||||
<RootNamespace>Glamourer</RootNamespace>
|
<RootNamespace>Glamourer</RootNamespace>
|
||||||
<AssemblyName>Glamourer</AssemblyName>
|
<AssemblyName>Glamourer</AssemblyName>
|
||||||
<FileVersion>1.0.0.0</FileVersion>
|
<FileVersion>0.0.1.1</FileVersion>
|
||||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
<AssemblyVersion>0.0.1.1</AssemblyVersion>
|
||||||
<Company>SoftOtter</Company>
|
<Company>SoftOtter</Company>
|
||||||
<Product>Glamourer</Product>
|
<Product>Glamourer</Product>
|
||||||
<Copyright>Copyright © 2020</Copyright>
|
<Copyright>Copyright © 2020</Copyright>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"Name": "Glamourer",
|
"Name": "Glamourer",
|
||||||
"Description": "Adds functionality to change appearance of actors. Requires Penumbra to be installed and activated to work.",
|
"Description": "Adds functionality to change appearance of actors. Requires Penumbra to be installed and activated to work.",
|
||||||
"InternalName": "Glamourer",
|
"InternalName": "Glamourer",
|
||||||
"AssemblyVersion": "0.0.1.0",
|
"AssemblyVersion": "0.0.1.1",
|
||||||
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
|
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"DalamudApiLevel": 3,
|
"DalamudApiLevel": 3,
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ namespace Glamourer.Gui
|
||||||
private string _currentFilterLower = string.Empty;
|
private string _currentFilterLower = string.Empty;
|
||||||
private bool _focus;
|
private bool _focus;
|
||||||
private readonly float _size;
|
private readonly float _size;
|
||||||
|
private readonly float _previewSize;
|
||||||
private readonly IReadOnlyList<T> _items;
|
private readonly IReadOnlyList<T> _items;
|
||||||
private readonly IReadOnlyList<string> _itemNamesLower;
|
private readonly IReadOnlyList<string> _itemNamesLower;
|
||||||
private readonly Func<T, string> _itemToName;
|
private readonly Func<T, string> _itemToName;
|
||||||
|
|
@ -31,7 +32,7 @@ namespace Glamourer.Gui
|
||||||
public ImGuiComboFlags Flags { get; set; } = ImGuiComboFlags.None;
|
public ImGuiComboFlags Flags { get; set; } = ImGuiComboFlags.None;
|
||||||
public int ItemsAtOnce { get; set; } = 12;
|
public int ItemsAtOnce { get; set; } = 12;
|
||||||
|
|
||||||
public ComboWithFilter(string label, float size, IReadOnlyList<T> items, Func<T, string> itemToName)
|
public ComboWithFilter(string label, float size, float previewSize, IReadOnlyList<T> items, Func<T, string> itemToName)
|
||||||
{
|
{
|
||||||
_label = label;
|
_label = label;
|
||||||
_filterLabel = $"##_{label}_filter";
|
_filterLabel = $"##_{label}_filter";
|
||||||
|
|
@ -39,6 +40,7 @@ namespace Glamourer.Gui
|
||||||
_itemToName = itemToName;
|
_itemToName = itemToName;
|
||||||
_items = items;
|
_items = items;
|
||||||
_size = size;
|
_size = size;
|
||||||
|
_previewSize = previewSize;
|
||||||
|
|
||||||
_itemNamesLower = _items.Select(i => _itemToName(i).ToLowerInvariant()).ToList();
|
_itemNamesLower = _items.Select(i => _itemToName(i).ToLowerInvariant()).ToList();
|
||||||
}
|
}
|
||||||
|
|
@ -52,6 +54,7 @@ namespace Glamourer.Gui
|
||||||
_items = other._items;
|
_items = other._items;
|
||||||
_itemNamesLower = other._itemNamesLower;
|
_itemNamesLower = other._itemNamesLower;
|
||||||
_size = other._size;
|
_size = other._size;
|
||||||
|
_previewSize = other._previewSize;
|
||||||
PrePreview = other.PrePreview;
|
PrePreview = other.PrePreview;
|
||||||
PostPreview = other.PostPreview;
|
PostPreview = other.PostPreview;
|
||||||
CreateSelectable = other.CreateSelectable;
|
CreateSelectable = other.CreateSelectable;
|
||||||
|
|
@ -130,7 +133,7 @@ namespace Glamourer.Gui
|
||||||
public bool Draw(string currentName, out T? value)
|
public bool Draw(string currentName, out T? value)
|
||||||
{
|
{
|
||||||
value = default;
|
value = default;
|
||||||
ImGui.SetNextItemWidth(_size);
|
ImGui.SetNextItemWidth(_previewSize);
|
||||||
PrePreview?.Invoke();
|
PrePreview?.Invoke();
|
||||||
if (!ImGui.BeginCombo(_label, currentName, Flags))
|
if (!ImGui.BeginCombo(_label, currentName, Flags))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Dalamud.Data.LuminaExtensions;
|
|
||||||
using Dalamud.Game.ClientState.Actors;
|
using Dalamud.Game.ClientState.Actors;
|
||||||
using Dalamud.Game.ClientState.Actors.Types;
|
using Dalamud.Game.ClientState.Actors.Types;
|
||||||
|
using Dalamud.Plugin;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Penumbra.Api;
|
using Penumbra.Api;
|
||||||
|
|
@ -12,17 +12,17 @@ using Penumbra.GameData;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.PlayerWatch;
|
using Penumbra.PlayerWatch;
|
||||||
using SDL2;
|
|
||||||
|
|
||||||
namespace Glamourer.Gui
|
namespace Glamourer.Gui
|
||||||
{
|
{
|
||||||
internal class Interface : IDisposable
|
internal partial class Interface : IDisposable
|
||||||
{
|
{
|
||||||
public const int GPoseActorId = 201;
|
public const int GPoseActorId = 201;
|
||||||
private const string PluginName = "Glamourer";
|
private const string PluginName = "Glamourer";
|
||||||
private readonly string _glamourerHeader;
|
private readonly string _glamourerHeader;
|
||||||
|
|
||||||
private const int ColorButtonWidth = 140;
|
private const float ColorButtonWidth = 22.5f;
|
||||||
|
private const float ColorComboWidth = 140f;
|
||||||
|
|
||||||
private readonly IReadOnlyDictionary<byte, Stain> _stains;
|
private readonly IReadOnlyDictionary<byte, Stain> _stains;
|
||||||
private readonly IReadOnlyDictionary<EquipSlot, List<Item>> _equip;
|
private readonly IReadOnlyDictionary<EquipSlot, List<Item>> _equip;
|
||||||
|
|
@ -35,7 +35,11 @@ namespace Glamourer.Gui
|
||||||
|
|
||||||
private Actor? _player;
|
private Actor? _player;
|
||||||
|
|
||||||
private static readonly Vector2 FeatureIconSize = new(80, 80);
|
private static readonly Vector2 FeatureIconSizeIntern =
|
||||||
|
Vector2.One * ImGui.GetTextLineHeightWithSpacing() * 2 / ImGui.GetIO().FontGlobalScale;
|
||||||
|
|
||||||
|
public static Vector2 FeatureIconSize
|
||||||
|
=> FeatureIconSizeIntern * ImGui.GetIO().FontGlobalScale;
|
||||||
|
|
||||||
|
|
||||||
public Interface()
|
public Interface()
|
||||||
|
|
@ -52,7 +56,7 @@ namespace Glamourer.Gui
|
||||||
_actors = GlamourerPlugin.PluginInterface.ClientState.Actors;
|
_actors = GlamourerPlugin.PluginInterface.ClientState.Actors;
|
||||||
_playerWatcher = PlayerWatchFactory.Create(GlamourerPlugin.PluginInterface);
|
_playerWatcher = PlayerWatchFactory.Create(GlamourerPlugin.PluginInterface);
|
||||||
|
|
||||||
var stainCombo = new ComboWithFilter<Stain>("##StainCombo", ColorButtonWidth, _stains.Values.ToArray(),
|
var stainCombo = new ComboWithFilter<Stain>("##StainCombo", ColorComboWidth, ColorButtonWidth, _stains.Values.ToArray(),
|
||||||
s => s.Name.ToString())
|
s => s.Name.ToString())
|
||||||
{
|
{
|
||||||
Flags = ImGuiComboFlags.NoArrowButton | ImGuiComboFlags.HeightLarge,
|
Flags = ImGuiComboFlags.NoArrowButton | ImGuiComboFlags.HeightLarge,
|
||||||
|
|
@ -67,7 +71,7 @@ namespace Glamourer.Gui
|
||||||
{
|
{
|
||||||
var push = PushColor(s);
|
var push = PushColor(s);
|
||||||
var ret = ImGui.Button($"{s.Name}##Stain{(byte) s.RowIndex}",
|
var ret = ImGui.Button($"{s.Name}##Stain{(byte) s.RowIndex}",
|
||||||
Vector2.UnitX * (ColorButtonWidth - ImGui.GetStyle().ScrollbarSize));
|
Vector2.UnitX * (ColorComboWidth - ImGui.GetStyle().ScrollbarSize));
|
||||||
ImGui.PopStyleColor(push);
|
ImGui.PopStyleColor(push);
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
|
|
@ -75,7 +79,7 @@ namespace Glamourer.Gui
|
||||||
};
|
};
|
||||||
|
|
||||||
_combos = _equip.ToDictionary(kvp => kvp.Key,
|
_combos = _equip.ToDictionary(kvp => kvp.Key,
|
||||||
kvp => (new ComboWithFilter<Item>($"{kvp.Key}##Equip", 300, kvp.Value, i => i.Name) { Flags = ImGuiComboFlags.HeightLarge }
|
kvp => (new ComboWithFilter<Item>($"{kvp.Key}##Equip", 300, 300, kvp.Value, i => i.Name) { Flags = ImGuiComboFlags.HeightLarge }
|
||||||
, new ComboWithFilter<Stain>($"##{kvp.Key}Stain", stainCombo))
|
, new ComboWithFilter<Stain>($"##{kvp.Key}Stain", stainCombo))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +119,7 @@ namespace Glamourer.Gui
|
||||||
stainCombo.PostPreview = () => ImGui.PopStyleColor(previewPush);
|
stainCombo.PostPreview = () => ImGui.PopStyleColor(previewPush);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stainCombo.Draw(name, out var newStain) && _player != null)
|
if (stainCombo.Draw(string.Empty, out var newStain) && _player != null)
|
||||||
{
|
{
|
||||||
newStain.Write(_player.Address, slot);
|
newStain.Write(_player.Address, slot);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -176,101 +180,424 @@ namespace Glamourer.Gui
|
||||||
|
|
||||||
private SubRace _currentSubRace = SubRace.Midlander;
|
private SubRace _currentSubRace = SubRace.Midlander;
|
||||||
private Gender _currentGender = Gender.Male;
|
private Gender _currentGender = Gender.Male;
|
||||||
private CustomizationId _currentCustomization = CustomizationId.Hairstyle;
|
|
||||||
|
|
||||||
private static readonly string[]
|
private static readonly string[]
|
||||||
SubRaceNames = ((SubRace[]) Enum.GetValues(typeof(SubRace))).Skip(1).Select(s => s.ToName()).ToArray();
|
SubRaceNames = ((SubRace[]) Enum.GetValues(typeof(SubRace))).Skip(1).Select(s => s.ToName()).ToArray();
|
||||||
|
|
||||||
|
private static bool DrawColorPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value)
|
||||||
private void DrawStuff()
|
|
||||||
{
|
{
|
||||||
if (ImGui.BeginCombo("SubRace", _currentSubRace.ToString()))
|
value = default;
|
||||||
|
if (!ImGui.BeginPopup(label, ImGuiWindowFlags.AlwaysAutoResize))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var ret = false;
|
||||||
|
var count = set.Count(id);
|
||||||
|
using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||||
|
.PushStyle(ImGuiStyleVar.FrameRounding, 0);
|
||||||
|
for (var i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
var custom = set.Data(id, i);
|
||||||
|
if (ImGui.ColorButton($"{i}", ImGui.ColorConvertU32ToFloat4(custom.Color)))
|
||||||
|
{
|
||||||
|
value = custom;
|
||||||
|
ret = true;
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % 8 != 7)
|
||||||
|
ImGui.SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void FixUpAttributes(CustomizationStruct customization)
|
||||||
|
{
|
||||||
|
var set = GlamourerPlugin.Customization.GetList(customization.Clan, customization.Gender);
|
||||||
|
foreach (CustomizationId id in Enum.GetValues(typeof(CustomizationId)))
|
||||||
|
{
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
case CustomizationId.Race: break;
|
||||||
|
case CustomizationId.Clan: break;
|
||||||
|
case CustomizationId.BodyType: break;
|
||||||
|
case CustomizationId.Gender: break;
|
||||||
|
case CustomizationId.FacialFeaturesTattoos: break;
|
||||||
|
case CustomizationId.Face:
|
||||||
|
if (customization.Race != Race.Hrothgar)
|
||||||
|
goto default;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
var count = set.Count(id);
|
||||||
|
if (customization[id] >= count)
|
||||||
|
customization[id] = set.Data(id, 0).Value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ChangeRace(CustomizationStruct customization, SubRace clan)
|
||||||
|
{
|
||||||
|
if (clan == customization.Clan)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var race = clan.ToRace();
|
||||||
|
customization.Race = race;
|
||||||
|
customization.Clan = clan;
|
||||||
|
|
||||||
|
customization.Gender = race switch
|
||||||
|
{
|
||||||
|
Race.Hrothgar => Gender.Male,
|
||||||
|
Race.Viera => Gender.Female,
|
||||||
|
_ => customization.Gender,
|
||||||
|
};
|
||||||
|
|
||||||
|
FixUpAttributes(customization);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ChangeGender(CustomizationStruct customization, Gender gender)
|
||||||
|
{
|
||||||
|
if (gender == customization.Gender)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
customization.Gender = gender;
|
||||||
|
FixUpAttributes(customization);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool DrawColorPicker(string label, string tooltip, CustomizationStruct customization, CustomizationId id,
|
||||||
|
CustomizationSet set)
|
||||||
|
{
|
||||||
|
var ret = false;
|
||||||
|
var count = set.Count(id);
|
||||||
|
|
||||||
|
var current = set.DataByValue(id, customization[id], out var custom);
|
||||||
|
if (current < 0)
|
||||||
|
{
|
||||||
|
PluginLog.Warning($"Read invalid customization value {customization[id]} for {id}.");
|
||||||
|
current = 0;
|
||||||
|
custom = set.Data(id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var popupName = $"Color Picker##{id}";
|
||||||
|
if (ImGui.ColorButton($"{current}##color_{id}", ImGui.ColorConvertU32ToFloat4(custom!.Value.Color)))
|
||||||
|
ImGui.OpenPopup(popupName);
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetNextItemWidth(50 + 2 * 22.5f * ImGui.GetIO().FontGlobalScale);
|
||||||
|
if (ImGui.InputInt($"##text_{id}", ref current, 1) && current != customization[id] && current >= 0 && current < count)
|
||||||
|
{
|
||||||
|
customization[id] = set.Data(id, current).Value;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip($"Input Range: [0, {count - 1}]");
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(label);
|
||||||
|
if (tooltip.Any() && ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip(tooltip);
|
||||||
|
|
||||||
|
if (!DrawColorPickerPopup(popupName, set, id, out var newCustom))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
customization[id] = newCustom.Value;
|
||||||
|
ret = true;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool DrawListSelector(string label, string tooltip, CustomizationStruct customization, CustomizationId id,
|
||||||
|
CustomizationSet set)
|
||||||
|
{
|
||||||
|
var ret = false;
|
||||||
|
int current = customization[id];
|
||||||
|
var count = set.Count(id);
|
||||||
|
|
||||||
|
ImGui.SetNextItemWidth(150 * ImGui.GetIO().FontGlobalScale);
|
||||||
|
if (ImGui.BeginCombo($"##combo_{id}", $"{id} #{current + 1}"))
|
||||||
|
{
|
||||||
|
for (var i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
if (ImGui.Selectable($"{id} #{i + 1}##combo", i == current) && i != current)
|
||||||
|
{
|
||||||
|
customization[id] = (byte) i;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetNextItemWidth(50 + 2 * 22.5f * ImGui.GetIO().FontGlobalScale);
|
||||||
|
if (ImGui.InputInt($"##text_{id}", ref current, 1) && current != customization[id] && current >= 0 && current < count)
|
||||||
|
{
|
||||||
|
customization[id] = set.Data(id, current).Value;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(label);
|
||||||
|
if (tooltip.Any() && ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip(tooltip);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Vector4 NoColor = new(1f, 1f, 1f, 1f);
|
||||||
|
private static readonly Vector4 RedColor = new(0.6f, 0.3f, 0.3f, 1f);
|
||||||
|
|
||||||
|
private static bool DrawMultiSelector(CustomizationStruct customization, CustomizationSet set)
|
||||||
|
{
|
||||||
|
var ret = false;
|
||||||
|
var count = set.Count(CustomizationId.FacialFeaturesTattoos);
|
||||||
|
using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing / 2);
|
||||||
|
for (var i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
var enabled = customization.FacialFeature(i);
|
||||||
|
var feature = set.FacialFeature(set.Race == Race.Hrothgar ? customization.Hairstyle : customization.Face, i);
|
||||||
|
var icon = GlamourerPlugin.Customization.GetIcon(feature.IconId);
|
||||||
|
if (ImGui.ImageButton(icon.ImGuiHandle, FeatureIconSize, Vector2.Zero, Vector2.One, (int) ImGui.GetStyle().FramePadding.X,
|
||||||
|
Vector4.Zero,
|
||||||
|
enabled ? NoColor : RedColor))
|
||||||
|
{
|
||||||
|
ret = true;
|
||||||
|
customization.FacialFeature(i, !enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
using var tt = ImGuiRaii.NewTooltip();
|
||||||
|
ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
raii.PopStyles();
|
||||||
|
raii.Group();
|
||||||
|
int value = customization[CustomizationId.FacialFeaturesTattoos];
|
||||||
|
ImGui.SetNextItemWidth(50 + 2 * 22.5f * ImGui.GetIO().FontGlobalScale);
|
||||||
|
if (ImGui.InputInt($"##{CustomizationId.FacialFeaturesTattoos}", ref value, 1)
|
||||||
|
&& value != customization[CustomizationId.FacialFeaturesTattoos]
|
||||||
|
&& value > 0
|
||||||
|
&& value < 256)
|
||||||
|
{
|
||||||
|
customization[CustomizationId.FacialFeaturesTattoos] = (byte) value;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Text("Facial Features & Tattoos");
|
||||||
|
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool DrawIconPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value)
|
||||||
|
{
|
||||||
|
value = default;
|
||||||
|
if (!ImGui.BeginPopup(label, ImGuiWindowFlags.AlwaysAutoResize))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var ret = false;
|
||||||
|
var count = set.Count(id);
|
||||||
|
using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||||
|
.PushStyle(ImGuiStyleVar.FrameRounding, 0);
|
||||||
|
for (var i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
var custom = set.Data(id, i);
|
||||||
|
var icon = GlamourerPlugin.Customization.GetIcon(custom.IconId);
|
||||||
|
if (ImGui.ImageButton(icon.ImGuiHandle, FeatureIconSize))
|
||||||
|
{
|
||||||
|
value = custom;
|
||||||
|
ret = true;
|
||||||
|
ImGui.CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
using var tt = ImGuiRaii.NewTooltip();
|
||||||
|
ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % 8 != 7)
|
||||||
|
ImGui.SameLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool DrawIconSelector(string label, string tooltip, CustomizationStruct customization, CustomizationId id,
|
||||||
|
CustomizationSet set)
|
||||||
|
{
|
||||||
|
var ret = false;
|
||||||
|
var count = set.Count(id);
|
||||||
|
|
||||||
|
var current = set.DataByValue(id, customization[id], out var custom);
|
||||||
|
if (current < 0)
|
||||||
|
{
|
||||||
|
PluginLog.Warning($"Read invalid customization value {customization[id]} for {id}.");
|
||||||
|
current = 0;
|
||||||
|
custom = set.Data(id, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var popupName = $"Style Picker##{id}";
|
||||||
|
var icon = GlamourerPlugin.Customization.GetIcon(custom!.Value.IconId);
|
||||||
|
if (ImGui.ImageButton(icon.ImGuiHandle, FeatureIconSize))
|
||||||
|
ImGui.OpenPopup(popupName);
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
{
|
||||||
|
using var tt = ImGuiRaii.NewTooltip();
|
||||||
|
ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
using var group = ImGuiRaii.NewGroup();
|
||||||
|
ImGui.SetNextItemWidth(50 + 2 * 22.5f * ImGui.GetIO().FontGlobalScale);
|
||||||
|
var oldIdx = current;
|
||||||
|
if (ImGui.InputInt($"##text_{id}", ref current, 1) && current != oldIdx && current >= 0 && current < count)
|
||||||
|
{
|
||||||
|
customization[id] = set.Data(id, current).Value;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip($"Input Range: [0, {count - 1}]");
|
||||||
|
|
||||||
|
if (DrawIconPickerPopup(popupName, set, id, out var newCustom))
|
||||||
|
{
|
||||||
|
customization[id] = newCustom.Value;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Text(label);
|
||||||
|
if (tooltip.Any() && ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip(tooltip);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static bool DrawPercentageSelector(string label, string tooltip, CustomizationStruct customization, CustomizationId id,
|
||||||
|
CustomizationSet set)
|
||||||
|
{
|
||||||
|
var ret = false;
|
||||||
|
int value = customization[id];
|
||||||
|
var count = set.Count(id);
|
||||||
|
ImGui.SetNextItemWidth(150 * ImGui.GetIO().FontGlobalScale);
|
||||||
|
if (ImGui.SliderInt($"##slider_{id}", ref value, 0, count - 1, "") && value != customization[id])
|
||||||
|
{
|
||||||
|
customization[id] = (byte) value;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.SetNextItemWidth(50 + 2 * 22.5f * ImGui.GetIO().FontGlobalScale);
|
||||||
|
if (ImGui.InputInt($"##input_{id}", ref value, 1) && value != customization[id] && value >= 0 && value < count)
|
||||||
|
{
|
||||||
|
customization[id] = (byte) value;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip($"Input Range: [0, {count - 1}]");
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.Text(label);
|
||||||
|
if (tooltip.Any() && ImGui.IsItemHovered())
|
||||||
|
ImGui.SetTooltip(tooltip);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool DrawStuff()
|
||||||
|
{
|
||||||
|
var ret = false;
|
||||||
|
var x = new CustomizationStruct(_player!.Address + 0x1898);
|
||||||
|
_currentSubRace = x.Clan;
|
||||||
|
ImGui.SetNextItemWidth(150 * ImGui.GetIO().FontGlobalScale);
|
||||||
|
if (ImGui.BeginCombo("SubRace", SubRaceNames[(int) _currentSubRace - 1]))
|
||||||
{
|
{
|
||||||
for (var i = 0; i < SubRaceNames.Length; ++i)
|
for (var i = 0; i < SubRaceNames.Length; ++i)
|
||||||
{
|
{
|
||||||
if (ImGui.Selectable(SubRaceNames[i], (int) _currentSubRace == i + 1))
|
if (ImGui.Selectable(SubRaceNames[i], (int) _currentSubRace == i + 1))
|
||||||
_currentSubRace = (SubRace) (i + 1);
|
{
|
||||||
|
_currentSubRace = (SubRace) i + 1;
|
||||||
|
ret |= ChangeRace(x, _currentSubRace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndCombo();
|
ImGui.EndCombo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_currentGender = x.Gender;
|
||||||
|
ImGui.SetNextItemWidth(150 * ImGui.GetIO().FontGlobalScale);
|
||||||
if (ImGui.BeginCombo("Gender", _currentGender.ToName()))
|
if (ImGui.BeginCombo("Gender", _currentGender.ToName()))
|
||||||
{
|
{
|
||||||
if (ImGui.Selectable(Gender.Male.ToName(), _currentGender == Gender.Male))
|
if (_currentSubRace.ToRace() != Race.Viera
|
||||||
|
&& ImGui.Selectable(Gender.Male.ToName(), _currentGender == Gender.Male)
|
||||||
|
&& _currentGender != Gender.Male)
|
||||||
|
{
|
||||||
_currentGender = Gender.Male;
|
_currentGender = Gender.Male;
|
||||||
if (ImGui.Selectable(Gender.Female.ToName(), _currentGender == Gender.Female))
|
ret = ChangeGender(x, _currentGender);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_currentSubRace.ToRace() != Race.Hrothgar
|
||||||
|
&& ImGui.Selectable(Gender.Female.ToName(), _currentGender == Gender.Female)
|
||||||
|
&& _currentGender != Gender.Female)
|
||||||
|
{
|
||||||
_currentGender = Gender.Female;
|
_currentGender = Gender.Female;
|
||||||
|
ret = ChangeGender(x, _currentGender);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.EndCombo();
|
ImGui.EndCombo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var set = GlamourerPlugin.Customization.GetList(_currentSubRace, _currentGender);
|
var set = GlamourerPlugin.Customization.GetList(_currentSubRace, _currentGender);
|
||||||
if (ImGui.BeginCombo("Customization", _currentCustomization.ToString()))
|
|
||||||
|
|
||||||
|
foreach (CustomizationId customizationId in Enum.GetValues(typeof(CustomizationId)))
|
||||||
{
|
{
|
||||||
foreach (CustomizationId customizationId in Enum.GetValues(typeof(CustomizationId)))
|
if (!set.IsAvailable(customizationId))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (customizationId.ToType(_currentSubRace.ToRace() == Race.Hrothgar))
|
||||||
{
|
{
|
||||||
if (!set.IsAvailable(customizationId))
|
case CharaMakeParams.MenuType.ColorPicker:
|
||||||
continue;
|
ret |= DrawColorPicker(customizationId.ToString(), "", x,
|
||||||
|
customizationId, set);
|
||||||
if (ImGui.Selectable(customizationId.ToString(), customizationId == _currentCustomization))
|
break;
|
||||||
_currentCustomization = customizationId;
|
case CharaMakeParams.MenuType.ListSelector:
|
||||||
|
ret |= DrawListSelector(customizationId.ToString(), "", x,
|
||||||
|
customizationId, set);
|
||||||
|
break;
|
||||||
|
case CharaMakeParams.MenuType.IconSelector:
|
||||||
|
ret |= DrawIconSelector(customizationId.ToString(), "", x, customizationId, set);
|
||||||
|
break;
|
||||||
|
case CharaMakeParams.MenuType.MultiIconSelector:
|
||||||
|
ret |= DrawMultiSelector(x, set);
|
||||||
|
break;
|
||||||
|
case CharaMakeParams.MenuType.Percentage:
|
||||||
|
ret |= DrawPercentageSelector(customizationId.ToString(), "", x, customizationId, set);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.EndCombo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var count = set.Count(_currentCustomization);
|
return ret;
|
||||||
var tmp = 0;
|
|
||||||
switch (_currentCustomization.ToType(_currentSubRace.ToRace() == Race.Hrothgar))
|
|
||||||
{
|
|
||||||
case CharaMakeParams.MenuType.ColorPicker:
|
|
||||||
{
|
|
||||||
using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
|
||||||
.PushStyle(ImGuiStyleVar.FrameRounding, 0f);
|
|
||||||
for (var i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
var data = set.Data(_currentCustomization, i);
|
|
||||||
ImGui.ColorButton($"{data.Value}", ImGui.ColorConvertU32ToFloat4(data.Color));
|
|
||||||
if (i % 8 != 7)
|
|
||||||
ImGui.SameLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CharaMakeParams.MenuType.Percentage:
|
|
||||||
ImGui.SliderInt("Percentage", ref tmp, 0, 100);
|
|
||||||
break;
|
|
||||||
case CharaMakeParams.MenuType.ListSelector:
|
|
||||||
ImGui.Combo("List", ref tmp, Enumerable.Range(0, count).Select(i => $"{_currentCustomization} #{i}").ToArray(), count);
|
|
||||||
break;
|
|
||||||
case CharaMakeParams.MenuType.IconSelector:
|
|
||||||
case CharaMakeParams.MenuType.MultiIconSelector:
|
|
||||||
{
|
|
||||||
using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
|
||||||
.PushStyle(ImGuiStyleVar.FrameRounding, 0f);
|
|
||||||
for (var i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
var data = set.Data(_currentCustomization, i);
|
|
||||||
var texture = GlamourerPlugin.Customization.GetIcon(data.IconId);
|
|
||||||
ImGui.ImageButton(texture.ImGuiHandle, FeatureIconSize * ImGui.GetIO().FontGlobalScale);
|
|
||||||
if (ImGui.IsItemHovered())
|
|
||||||
{
|
|
||||||
using var tooltip = ImGuiRaii.NewTooltip();
|
|
||||||
ImGui.Image(texture.ImGuiHandle, new Vector2(texture.Width, texture.Height));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i % 4 != 3)
|
|
||||||
ImGui.SameLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Draw()
|
private void Draw()
|
||||||
{
|
{
|
||||||
ImGui.SetNextWindowSizeConstraints(Vector2.One * 600, Vector2.One * 5000);
|
ImGui.SetNextWindowSizeConstraints(Vector2.One * 600, Vector2.One * 5000);
|
||||||
if (!_visible || !ImGui.Begin(_glamourerHeader))
|
if (!_visible || !ImGui.Begin(_glamourerHeader, ref _visible))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
|
@ -311,11 +638,11 @@ namespace Glamourer.Gui
|
||||||
changes |= DrawEquip(EquipSlot.RFinger, equip.RFinger);
|
changes |= DrawEquip(EquipSlot.RFinger, equip.RFinger);
|
||||||
changes |= DrawEquip(EquipSlot.LFinger, equip.LFinger);
|
changes |= DrawEquip(EquipSlot.LFinger, equip.LFinger);
|
||||||
|
|
||||||
|
changes |= DrawStuff();
|
||||||
|
|
||||||
if (changes)
|
if (changes)
|
||||||
UpdateActors(_player);
|
UpdateActors(_player);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawStuff();
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@
|
||||||
"Name": "Glamourer",
|
"Name": "Glamourer",
|
||||||
"Description": "Adds functionality to change appearance of actors. Requires Penumbra to be installed and activated to work.",
|
"Description": "Adds functionality to change appearance of actors. Requires Penumbra to be installed and activated to work.",
|
||||||
"InternalName": "Glamourer",
|
"InternalName": "Glamourer",
|
||||||
"AssemblyVersion": "0.0.1.0",
|
"AssemblyVersion": "0.0.1.1",
|
||||||
"TestingAssemblyVersion": "0.0.1.0",
|
"TestingAssemblyVersion": "0.0.1.1",
|
||||||
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
|
"RepoUrl": "https://github.com/Ottermandias/Glamourer",
|
||||||
"ApplicableVersion": "any",
|
"ApplicableVersion": "any",
|
||||||
"DalamudApiLevel": 3,
|
"DalamudApiLevel": 3,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue