mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -192,8 +192,6 @@ namespace Glamourer.Customization
|
|||
if (set.Faces.Count > 0)
|
||||
set.SetAvailable(CustomizationId.Face);
|
||||
|
||||
|
||||
|
||||
var count = race.ToRace() == Race.Hrothgar ? set.HairStyles.Count : set.Faces.Count;
|
||||
var featureDict = new List<IReadOnlyList<Customization>>(count);
|
||||
for (var i = 0; i < count; ++i)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ImGuiScene;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Customization
|
||||
|
|
@ -37,7 +39,7 @@ namespace Glamourer.Customization
|
|||
public Race Race
|
||||
=> Clan.ToRace();
|
||||
|
||||
private int _settingAvailable = DefaultAvailable;
|
||||
private int _settingAvailable;
|
||||
|
||||
internal void SetAvailable(CustomizationId id)
|
||||
=> _settingAvailable |= 1 << (int) id;
|
||||
|
|
@ -71,7 +73,52 @@ namespace Glamourer.Customization
|
|||
public IReadOnlyDictionary<CustomizationId, string> OptionName { get; internal set; } = null!;
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue