mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-15 21:24:18 +01:00
Current state.
This commit is contained in:
parent
7a602d6ec5
commit
81059411e5
42 changed files with 913 additions and 320 deletions
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4aaece34289d64363bc32aaa8fe52c8e7d3dce32
|
Subproject commit ca003395306791b9e595683c47824b4718385311
|
||||||
|
|
@ -35,6 +35,7 @@ public class ApiHelpers(ObjectManager objects, StateManager stateManager, ActorM
|
||||||
state = null;
|
state = null;
|
||||||
return GlamourerApiEc.ActorNotFound;
|
return GlamourerApiEc.ActorNotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
stateManager.TryGetValue(identifier, out state);
|
stateManager.TryGetValue(identifier, out state);
|
||||||
return GlamourerApiEc.Success;
|
return GlamourerApiEc.Success;
|
||||||
}
|
}
|
||||||
|
|
@ -54,12 +55,10 @@ public class ApiHelpers(ObjectManager objects, StateManager stateManager, ActorM
|
||||||
internal static DesignBase.FlagRestrictionResetter Restrict(DesignBase design, ApplyFlag flags)
|
internal static DesignBase.FlagRestrictionResetter Restrict(DesignBase design, ApplyFlag flags)
|
||||||
=> (flags & (ApplyFlag.Equipment | ApplyFlag.Customization)) switch
|
=> (flags & (ApplyFlag.Equipment | ApplyFlag.Customization)) switch
|
||||||
{
|
{
|
||||||
ApplyFlag.Equipment => design.TemporarilyRestrictApplication(EquipFlagExtensions.All, 0, CrestExtensions.All, 0),
|
ApplyFlag.Equipment => design.TemporarilyRestrictApplication(ApplicationCollection.Equipment),
|
||||||
ApplyFlag.Customization => design.TemporarilyRestrictApplication(0, CustomizeFlagExtensions.All, 0,
|
ApplyFlag.Customization => design.TemporarilyRestrictApplication(ApplicationCollection.Customizations),
|
||||||
CustomizeParameterExtensions.All),
|
ApplyFlag.Equipment | ApplyFlag.Customization => design.TemporarilyRestrictApplication(ApplicationCollection.All),
|
||||||
ApplyFlag.Equipment | ApplyFlag.Customization => design.TemporarilyRestrictApplication(EquipFlagExtensions.All,
|
_ => design.TemporarilyRestrictApplication(ApplicationCollection.None),
|
||||||
CustomizeFlagExtensions.All, CrestExtensions.All, CustomizeParameterExtensions.All),
|
|
||||||
_ => design.TemporarilyRestrictApplication(0, 0, 0, 0),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,7 @@ public static class ApplicationTypeExtensions
|
||||||
(ApplicationType.Weapons, "Apply all weapon changes that are enabled in this design and that are valid with the current weapon worn."),
|
(ApplicationType.Weapons, "Apply all weapon changes that are enabled in this design and that are valid with the current weapon worn."),
|
||||||
];
|
];
|
||||||
|
|
||||||
public static (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, MetaFlag Meta) ApplyWhat(
|
public static ApplicationCollection Collection(this ApplicationType type)
|
||||||
this ApplicationType type, IDesignStandIn designStandIn)
|
|
||||||
{
|
{
|
||||||
var equipFlags = (type.HasFlag(ApplicationType.Weapons) ? WeaponFlags : 0)
|
var equipFlags = (type.HasFlag(ApplicationType.Weapons) ? WeaponFlags : 0)
|
||||||
| (type.HasFlag(ApplicationType.Armor) ? ArmorFlags : 0)
|
| (type.HasFlag(ApplicationType.Armor) ? ArmorFlags : 0)
|
||||||
|
|
@ -37,18 +36,18 @@ public static class ApplicationTypeExtensions
|
||||||
| (type.HasFlag(ApplicationType.GearCustomization) ? StainFlags : 0);
|
| (type.HasFlag(ApplicationType.GearCustomization) ? StainFlags : 0);
|
||||||
var customizeFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeFlagExtensions.All : 0;
|
var customizeFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeFlagExtensions.All : 0;
|
||||||
var parameterFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeParameterExtensions.All : 0;
|
var parameterFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeParameterExtensions.All : 0;
|
||||||
var crestFlag = type.HasFlag(ApplicationType.GearCustomization) ? CrestExtensions.AllRelevant : 0;
|
var crestFlags = type.HasFlag(ApplicationType.GearCustomization) ? CrestExtensions.AllRelevant : 0;
|
||||||
var metaFlag = (type.HasFlag(ApplicationType.Armor) ? MetaFlag.HatState | MetaFlag.VisorState : 0)
|
var metaFlags = (type.HasFlag(ApplicationType.Armor) ? MetaFlag.HatState | MetaFlag.VisorState : 0)
|
||||||
| (type.HasFlag(ApplicationType.Weapons) ? MetaFlag.WeaponState : 0)
|
| (type.HasFlag(ApplicationType.Weapons) ? MetaFlag.WeaponState : 0)
|
||||||
| (type.HasFlag(ApplicationType.Customizations) ? MetaFlag.Wetness : 0);
|
| (type.HasFlag(ApplicationType.Customizations) ? MetaFlag.Wetness : 0);
|
||||||
|
var bonusFlags = type.HasFlag(ApplicationType.Armor) ? BonusExtensions.All : 0;
|
||||||
|
|
||||||
if (designStandIn is not DesignBase design)
|
return new ApplicationCollection(equipFlags, bonusFlags, customizeFlags, crestFlags, parameterFlags, metaFlags);
|
||||||
return (equipFlags, customizeFlags, crestFlag, parameterFlags, metaFlag);
|
|
||||||
|
|
||||||
return (equipFlags & design!.ApplyEquip, customizeFlags & design.ApplyCustomize, crestFlag & design.ApplyCrest,
|
|
||||||
parameterFlags & design.ApplyParameters, metaFlag & design.ApplyMeta);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ApplicationCollection ApplyWhat(this ApplicationType type, IDesignStandIn designStandIn)
|
||||||
|
=> designStandIn is not DesignBase design ? type.Collection() : type.Collection().Restrict(design.Application);
|
||||||
|
|
||||||
public const EquipFlag WeaponFlags = EquipFlag.Mainhand | EquipFlag.Offhand;
|
public const EquipFlag WeaponFlags = EquipFlag.Mainhand | EquipFlag.Offhand;
|
||||||
public const EquipFlag ArmorFlags = EquipFlag.Head | EquipFlag.Body | EquipFlag.Hands | EquipFlag.Legs | EquipFlag.Feet;
|
public const EquipFlag ArmorFlags = EquipFlag.Head | EquipFlag.Body | EquipFlag.Hands | EquipFlag.Legs | EquipFlag.Feet;
|
||||||
public const EquipFlag AccessoryFlags = EquipFlag.Ears | EquipFlag.Neck | EquipFlag.Wrist | EquipFlag.RFinger | EquipFlag.LFinger;
|
public const EquipFlag AccessoryFlags = EquipFlag.Ears | EquipFlag.Neck | EquipFlag.Wrist | EquipFlag.RFinger | EquipFlag.LFinger;
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,6 @@ public class AutoDesign
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, MetaFlag Meta) ApplyWhat()
|
public ApplicationCollection ApplyWhat()
|
||||||
=> Type.ApplyWhat(Design);
|
=> Type.ApplyWhat(Design);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
61
Glamourer/Designs/ApplicationCollection.cs
Normal file
61
Glamourer/Designs/ApplicationCollection.cs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
using Glamourer.GameData;
|
||||||
|
using ImGuiNET;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
|
public record struct ApplicationCollection(
|
||||||
|
EquipFlag Equip,
|
||||||
|
BonusItemFlag BonusItem,
|
||||||
|
CustomizeFlag Customize,
|
||||||
|
CrestFlag Crest,
|
||||||
|
CustomizeParameterFlag Parameters,
|
||||||
|
MetaFlag Meta)
|
||||||
|
{
|
||||||
|
public static readonly ApplicationCollection All = new(EquipFlagExtensions.All, BonusExtensions.All,
|
||||||
|
CustomizeFlagExtensions.AllRelevant, CrestExtensions.AllRelevant, CustomizeParameterExtensions.All, MetaExtensions.All);
|
||||||
|
|
||||||
|
public static readonly ApplicationCollection None = new(0, 0, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
public static readonly ApplicationCollection Equipment = new(EquipFlagExtensions.All, BonusExtensions.All,
|
||||||
|
0, CrestExtensions.AllRelevant, 0, MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState);
|
||||||
|
|
||||||
|
public static readonly ApplicationCollection Customizations = new(0, 0, CustomizeFlagExtensions.AllRelevant, 0,
|
||||||
|
CustomizeParameterExtensions.All, MetaFlag.Wetness);
|
||||||
|
|
||||||
|
public static readonly ApplicationCollection Default = new(EquipFlagExtensions.All, BonusExtensions.All,
|
||||||
|
CustomizeFlagExtensions.AllRelevant, CrestExtensions.AllRelevant, 0, MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState);
|
||||||
|
|
||||||
|
public static ApplicationCollection FromKeys()
|
||||||
|
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
||||||
|
{
|
||||||
|
(false, false) => All,
|
||||||
|
(true, true) => All,
|
||||||
|
(true, false) => Equipment,
|
||||||
|
(false, true) => Customizations,
|
||||||
|
};
|
||||||
|
|
||||||
|
public void RemoveEquip()
|
||||||
|
{
|
||||||
|
Equip = 0;
|
||||||
|
BonusItem = 0;
|
||||||
|
Crest = 0;
|
||||||
|
Meta &= ~(MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveCustomize()
|
||||||
|
{
|
||||||
|
Customize = 0;
|
||||||
|
Parameters = 0;
|
||||||
|
Meta &= MetaFlag.Wetness;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplicationCollection Restrict(ApplicationCollection old)
|
||||||
|
=> new(old.Equip & Equip, old.BonusItem & BonusItem, old.Customize & Customize, old.Crest & Crest,
|
||||||
|
old.Parameters & Parameters, old.Meta & Meta);
|
||||||
|
|
||||||
|
public ApplicationCollection CloneSecure()
|
||||||
|
=> new(Equip & EquipFlagExtensions.All, BonusItem & BonusExtensions.All,
|
||||||
|
(Customize & CustomizeFlagExtensions.AllRelevant) | CustomizeFlag.BodyType, Crest & CrestExtensions.AllRelevant,
|
||||||
|
Parameters & CustomizeParameterExtensions.All, Meta & MetaExtensions.All);
|
||||||
|
}
|
||||||
|
|
@ -5,16 +5,9 @@ using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
public readonly struct ApplicationRules(
|
public readonly struct ApplicationRules(ApplicationCollection application, bool materials)
|
||||||
EquipFlag equip,
|
|
||||||
CustomizeFlag customize,
|
|
||||||
CrestFlag crest,
|
|
||||||
CustomizeParameterFlag parameters,
|
|
||||||
MetaFlag meta,
|
|
||||||
bool materials)
|
|
||||||
{
|
{
|
||||||
public static readonly ApplicationRules All = new(EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant,
|
public static readonly ApplicationRules All = new(ApplicationCollection.All, true);
|
||||||
CrestExtensions.AllRelevant, CustomizeParameterExtensions.All, MetaExtensions.All, true);
|
|
||||||
|
|
||||||
public static ApplicationRules FromModifiers(ActorState state)
|
public static ApplicationRules FromModifiers(ActorState state)
|
||||||
=> FromModifiers(state, ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift);
|
=> FromModifiers(state, ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift);
|
||||||
|
|
@ -23,54 +16,43 @@ public readonly struct ApplicationRules(
|
||||||
=> NpcFromModifiers(ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift);
|
=> NpcFromModifiers(ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift);
|
||||||
|
|
||||||
public static ApplicationRules AllButParameters(ActorState state)
|
public static ApplicationRules AllButParameters(ActorState state)
|
||||||
=> new(All.Equip, All.Customize, All.Crest, ComputeParameters(state.ModelData, state.BaseData, All.Parameters), All.Meta, true);
|
=> new(ApplicationCollection.All with { Parameters = ComputeParameters(state.ModelData, state.BaseData, All.Parameters) }, true);
|
||||||
|
|
||||||
public static ApplicationRules AllWithConfig(Configuration config)
|
public static ApplicationRules AllWithConfig(Configuration config)
|
||||||
=> new(All.Equip, All.Customize, All.Crest, config.UseAdvancedParameters ? All.Parameters : 0, All.Meta, config.UseAdvancedDyes);
|
=> new(ApplicationCollection.All with { Parameters = config.UseAdvancedParameters ? All.Parameters : 0 }, config.UseAdvancedDyes);
|
||||||
|
|
||||||
public static ApplicationRules NpcFromModifiers(bool ctrl, bool shift)
|
public static ApplicationRules NpcFromModifiers(bool ctrl, bool shift)
|
||||||
=> new(ctrl || !shift ? EquipFlagExtensions.All : 0,
|
{
|
||||||
!ctrl || shift ? CustomizeFlagExtensions.AllRelevant : 0,
|
var equip = ctrl || !shift ? EquipFlagExtensions.All : 0;
|
||||||
0,
|
var customize = !ctrl || shift ? CustomizeFlagExtensions.AllRelevant : 0;
|
||||||
0,
|
var visor = equip != 0 ? MetaFlag.VisorState : 0;
|
||||||
ctrl || !shift ? MetaFlag.VisorState : 0, false);
|
return new ApplicationRules(new ApplicationCollection(equip, 0, customize, 0, 0, visor), false);
|
||||||
|
}
|
||||||
|
|
||||||
public static ApplicationRules FromModifiers(ActorState state, bool ctrl, bool shift)
|
public static ApplicationRules FromModifiers(ActorState state, bool ctrl, bool shift)
|
||||||
{
|
{
|
||||||
var equip = ctrl || !shift ? EquipFlagExtensions.All : 0;
|
var equip = ctrl || !shift ? EquipFlagExtensions.All : 0;
|
||||||
var customize = !ctrl || shift ? CustomizeFlagExtensions.AllRelevant : 0;
|
var customize = !ctrl || shift ? CustomizeFlagExtensions.AllRelevant : 0;
|
||||||
|
var bonus = equip == 0 ? 0 : BonusExtensions.All;
|
||||||
var crest = equip == 0 ? 0 : CrestExtensions.AllRelevant;
|
var crest = equip == 0 ? 0 : CrestExtensions.AllRelevant;
|
||||||
var parameters = customize == 0 ? 0 : CustomizeParameterExtensions.All;
|
var parameters = customize == 0 ? 0 : CustomizeParameterExtensions.All;
|
||||||
var meta = state.ModelData.IsWet() ? MetaFlag.Wetness : 0;
|
var meta = state.ModelData.IsWet() ? MetaFlag.Wetness : 0;
|
||||||
if (equip != 0)
|
if (equip != 0)
|
||||||
meta |= MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState;
|
meta |= MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState;
|
||||||
|
|
||||||
return new ApplicationRules(equip, customize, crest, ComputeParameters(state.ModelData, state.BaseData, parameters), meta, equip != 0);
|
var collection = new ApplicationCollection(equip, bonus, customize, crest,
|
||||||
|
ComputeParameters(state.ModelData, state.BaseData, parameters), meta);
|
||||||
|
return new ApplicationRules(collection, equip != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Apply(DesignBase design)
|
public void Apply(DesignBase design)
|
||||||
{
|
=> design.Application = application;
|
||||||
design.ApplyEquip = Equip;
|
|
||||||
design.ApplyCustomize = Customize;
|
|
||||||
design.ApplyCrest = Crest;
|
|
||||||
design.ApplyParameters = Parameters;
|
|
||||||
design.ApplyMeta = Meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EquipFlag Equip
|
public EquipFlag Equip
|
||||||
=> equip & EquipFlagExtensions.All;
|
=> application.Equip & EquipFlagExtensions.All;
|
||||||
|
|
||||||
public CustomizeFlag Customize
|
|
||||||
=> customize & CustomizeFlagExtensions.AllRelevant;
|
|
||||||
|
|
||||||
public CrestFlag Crest
|
|
||||||
=> crest & CrestExtensions.AllRelevant;
|
|
||||||
|
|
||||||
public CustomizeParameterFlag Parameters
|
public CustomizeParameterFlag Parameters
|
||||||
=> parameters & CustomizeParameterExtensions.All;
|
=> application.Parameters & CustomizeParameterExtensions.All;
|
||||||
|
|
||||||
public MetaFlag Meta
|
|
||||||
=> meta & MetaExtensions.All;
|
|
||||||
|
|
||||||
public bool Materials
|
public bool Materials
|
||||||
=> materials;
|
=> materials;
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,8 @@ public class DesignBase
|
||||||
{
|
{
|
||||||
_designData = designData;
|
_designData = designData;
|
||||||
ApplyCustomize = customizeFlags & CustomizeFlagExtensions.AllRelevant;
|
ApplyCustomize = customizeFlags & CustomizeFlagExtensions.AllRelevant;
|
||||||
ApplyEquip = equipFlags & EquipFlagExtensions.All;
|
Application.Equip = equipFlags & EquipFlagExtensions.All;
|
||||||
ApplyMeta = 0;
|
Application.Meta = 0;
|
||||||
CustomizeSet = SetCustomizationSet(customize);
|
CustomizeSet = SetCustomizationSet(customize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,11 +54,7 @@ public class DesignBase
|
||||||
_designData = clone._designData;
|
_designData = clone._designData;
|
||||||
_materials = clone._materials.Clone();
|
_materials = clone._materials.Clone();
|
||||||
CustomizeSet = clone.CustomizeSet;
|
CustomizeSet = clone.CustomizeSet;
|
||||||
ApplyCustomize = clone.ApplyCustomizeRaw;
|
Application = clone.Application.CloneSecure();
|
||||||
ApplyEquip = clone.ApplyEquip & EquipFlagExtensions.All;
|
|
||||||
ApplyParameters = clone.ApplyParameters & CustomizeParameterExtensions.All;
|
|
||||||
ApplyCrest = clone.ApplyCrest & CrestExtensions.All;
|
|
||||||
ApplyMeta = clone.ApplyMeta & MetaExtensions.All;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Ensure that the customization set is updated when the design data changes. </summary>
|
/// <summary> Ensure that the customization set is updated when the design data changes. </summary>
|
||||||
|
|
@ -70,26 +66,19 @@ public class DesignBase
|
||||||
|
|
||||||
#region Application Data
|
#region Application Data
|
||||||
|
|
||||||
private CustomizeFlag _applyCustomize = CustomizeFlagExtensions.AllRelevant;
|
|
||||||
public CustomizeSet CustomizeSet { get; private set; }
|
public CustomizeSet CustomizeSet { get; private set; }
|
||||||
|
|
||||||
public CustomizeParameterFlag ApplyParameters { get; internal set; }
|
public ApplicationCollection Application = ApplicationCollection.Default;
|
||||||
|
|
||||||
internal CustomizeFlag ApplyCustomize
|
internal CustomizeFlag ApplyCustomize
|
||||||
{
|
{
|
||||||
get => _applyCustomize.FixApplication(CustomizeSet);
|
get => Application.Customize.FixApplication(CustomizeSet);
|
||||||
set => _applyCustomize = (value & CustomizeFlagExtensions.AllRelevant) | CustomizeFlag.BodyType;
|
set => Application.Customize = (value & CustomizeFlagExtensions.AllRelevant) | CustomizeFlag.BodyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal CustomizeFlag ApplyCustomizeExcludingBodyType
|
internal CustomizeFlag ApplyCustomizeExcludingBodyType
|
||||||
=> _applyCustomize.FixApplication(CustomizeSet) & ~CustomizeFlag.BodyType;
|
=> Application.Customize.FixApplication(CustomizeSet) & ~CustomizeFlag.BodyType;
|
||||||
|
|
||||||
internal CustomizeFlag ApplyCustomizeRaw
|
|
||||||
=> _applyCustomize;
|
|
||||||
|
|
||||||
internal EquipFlag ApplyEquip = EquipFlagExtensions.All;
|
|
||||||
internal CrestFlag ApplyCrest = CrestExtensions.AllRelevant;
|
|
||||||
internal MetaFlag ApplyMeta = MetaFlag.HatState | MetaFlag.VisorState | MetaFlag.WeaponState;
|
|
||||||
private bool _writeProtected;
|
private bool _writeProtected;
|
||||||
|
|
||||||
public bool SetCustomize(CustomizeService customizeService, CustomizeArray customize)
|
public bool SetCustomize(CustomizeService customizeService, CustomizeArray customize)
|
||||||
|
|
@ -103,18 +92,18 @@ public class DesignBase
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DoApplyMeta(MetaIndex index)
|
public bool DoApplyMeta(MetaIndex index)
|
||||||
=> ApplyMeta.HasFlag(index.ToFlag());
|
=> Application.Meta.HasFlag(index.ToFlag());
|
||||||
|
|
||||||
public bool WriteProtected()
|
public bool WriteProtected()
|
||||||
=> _writeProtected;
|
=> _writeProtected;
|
||||||
|
|
||||||
public bool SetApplyMeta(MetaIndex index, bool value)
|
public bool SetApplyMeta(MetaIndex index, bool value)
|
||||||
{
|
{
|
||||||
var newFlag = value ? ApplyMeta | index.ToFlag() : ApplyMeta & ~index.ToFlag();
|
var newFlag = value ? Application.Meta | index.ToFlag() : Application.Meta & ~index.ToFlag();
|
||||||
if (newFlag == ApplyMeta)
|
if (newFlag == Application.Meta)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ApplyMeta = newFlag;
|
Application.Meta = newFlag;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,103 +117,100 @@ public class DesignBase
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool DoApplyEquip(EquipSlot slot)
|
public bool DoApplyEquip(EquipSlot slot)
|
||||||
=> ApplyEquip.HasFlag(slot.ToFlag());
|
=> Application.Equip.HasFlag(slot.ToFlag());
|
||||||
|
|
||||||
public bool DoApplyStain(EquipSlot slot)
|
public bool DoApplyStain(EquipSlot slot)
|
||||||
=> ApplyEquip.HasFlag(slot.ToStainFlag());
|
=> Application.Equip.HasFlag(slot.ToStainFlag());
|
||||||
|
|
||||||
public bool DoApplyCustomize(CustomizeIndex idx)
|
public bool DoApplyCustomize(CustomizeIndex idx)
|
||||||
=> ApplyCustomize.HasFlag(idx.ToFlag());
|
=> Application.Customize.HasFlag(idx.ToFlag());
|
||||||
|
|
||||||
public bool DoApplyCrest(CrestFlag slot)
|
public bool DoApplyCrest(CrestFlag slot)
|
||||||
=> ApplyCrest.HasFlag(slot);
|
=> Application.Crest.HasFlag(slot);
|
||||||
|
|
||||||
public bool DoApplyParameter(CustomizeParameterFlag flag)
|
public bool DoApplyParameter(CustomizeParameterFlag flag)
|
||||||
=> ApplyParameters.HasFlag(flag);
|
=> Application.Parameters.HasFlag(flag);
|
||||||
|
|
||||||
|
public bool DoApplyBonusItem(BonusItemFlag slot)
|
||||||
|
=> Application.BonusItem.HasFlag(slot);
|
||||||
|
|
||||||
internal bool SetApplyEquip(EquipSlot slot, bool value)
|
internal bool SetApplyEquip(EquipSlot slot, bool value)
|
||||||
{
|
{
|
||||||
var newValue = value ? ApplyEquip | slot.ToFlag() : ApplyEquip & ~slot.ToFlag();
|
var newValue = value ? Application.Equip | slot.ToFlag() : Application.Equip & ~slot.ToFlag();
|
||||||
if (newValue == ApplyEquip)
|
if (newValue == Application.Equip)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ApplyEquip = newValue;
|
Application.Equip = newValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool SetApplyBonusItem(BonusItemFlag slot, bool value)
|
||||||
|
{
|
||||||
|
var newValue = value ? Application.BonusItem | slot : Application.BonusItem & ~slot;
|
||||||
|
if (newValue == Application.BonusItem)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Application.BonusItem = newValue;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool SetApplyStain(EquipSlot slot, bool value)
|
internal bool SetApplyStain(EquipSlot slot, bool value)
|
||||||
{
|
{
|
||||||
var newValue = value ? ApplyEquip | slot.ToStainFlag() : ApplyEquip & ~slot.ToStainFlag();
|
var newValue = value ? Application.Equip | slot.ToStainFlag() : Application.Equip & ~slot.ToStainFlag();
|
||||||
if (newValue == ApplyEquip)
|
if (newValue == Application.Equip)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ApplyEquip = newValue;
|
Application.Equip = newValue;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool SetApplyCustomize(CustomizeIndex idx, bool value)
|
internal bool SetApplyCustomize(CustomizeIndex idx, bool value)
|
||||||
{
|
{
|
||||||
var newValue = value ? _applyCustomize | idx.ToFlag() : _applyCustomize & ~idx.ToFlag();
|
var newValue = value ? Application.Customize | idx.ToFlag() : Application.Customize & ~idx.ToFlag();
|
||||||
if (newValue == _applyCustomize)
|
if (newValue == Application.Customize)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_applyCustomize = newValue;
|
Application.Customize = newValue;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool SetApplyCrest(CrestFlag slot, bool value)
|
internal bool SetApplyCrest(CrestFlag slot, bool value)
|
||||||
{
|
{
|
||||||
var newValue = value ? ApplyCrest | slot : ApplyCrest & ~slot;
|
var newValue = value ? Application.Crest | slot : Application.Crest & ~slot;
|
||||||
if (newValue == ApplyCrest)
|
if (newValue == Application.Crest)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ApplyCrest = newValue;
|
Application.Crest = newValue;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool SetApplyParameter(CustomizeParameterFlag flag, bool value)
|
internal bool SetApplyParameter(CustomizeParameterFlag flag, bool value)
|
||||||
{
|
{
|
||||||
var newValue = value ? ApplyParameters | flag : ApplyParameters & ~flag;
|
var newValue = value ? Application.Parameters | flag : Application.Parameters & ~flag;
|
||||||
if (newValue == ApplyParameters)
|
if (newValue == Application.Parameters)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ApplyParameters = newValue;
|
Application.Parameters = newValue;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal FlagRestrictionResetter TemporarilyRestrictApplication(EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags,
|
internal FlagRestrictionResetter TemporarilyRestrictApplication(ApplicationCollection restrictions)
|
||||||
CustomizeParameterFlag parameterFlags)
|
=> new(this, restrictions);
|
||||||
=> new(this, equipFlags, customizeFlags, crestFlags, parameterFlags);
|
|
||||||
|
|
||||||
internal readonly struct FlagRestrictionResetter : IDisposable
|
internal readonly struct FlagRestrictionResetter : IDisposable
|
||||||
{
|
{
|
||||||
private readonly DesignBase _design;
|
private readonly DesignBase _design;
|
||||||
private readonly EquipFlag _oldEquipFlags;
|
private readonly ApplicationCollection _oldFlags;
|
||||||
private readonly CustomizeFlag _oldCustomizeFlags;
|
|
||||||
private readonly CrestFlag _oldCrestFlags;
|
|
||||||
private readonly CustomizeParameterFlag _oldParameterFlags;
|
|
||||||
|
|
||||||
public FlagRestrictionResetter(DesignBase d, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags,
|
public FlagRestrictionResetter(DesignBase d, ApplicationCollection restrictions)
|
||||||
CustomizeParameterFlag parameterFlags)
|
|
||||||
{
|
{
|
||||||
_design = d;
|
_design = d;
|
||||||
_oldEquipFlags = d.ApplyEquip;
|
_oldFlags = d.Application;
|
||||||
_oldCustomizeFlags = d.ApplyCustomizeRaw;
|
_design.Application = restrictions.Restrict(_oldFlags);
|
||||||
_oldCrestFlags = d.ApplyCrest;
|
|
||||||
_oldParameterFlags = d.ApplyParameters;
|
|
||||||
d.ApplyEquip &= equipFlags;
|
|
||||||
d.ApplyCustomize &= customizeFlags;
|
|
||||||
d.ApplyCrest &= crestFlags;
|
|
||||||
d.ApplyParameters &= parameterFlags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
=> _design.Application = _oldFlags;
|
||||||
_design.ApplyEquip = _oldEquipFlags;
|
|
||||||
_design.ApplyCustomize = _oldCustomizeFlags;
|
|
||||||
_design.ApplyCrest = _oldCrestFlags;
|
|
||||||
_design.ApplyParameters = _oldParameterFlags;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CustomizeSet SetCustomizationSet(CustomizeService customize)
|
private CustomizeSet SetCustomizationSet(CustomizeService customize)
|
||||||
|
|
@ -285,6 +271,22 @@ public class DesignBase
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected JObject SerializeBonusItems()
|
||||||
|
{
|
||||||
|
var ret = new JObject();
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var item = _designData.BonusItem(slot);
|
||||||
|
ret[slot.ToString()] = new JObject()
|
||||||
|
{
|
||||||
|
["BonusId"] = item.ModelId.Id,
|
||||||
|
["Apply"] = DoApplyBonusItem(slot),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
protected JObject SerializeCustomize()
|
protected JObject SerializeCustomize()
|
||||||
{
|
{
|
||||||
var ret = new JObject()
|
var ret = new JObject()
|
||||||
|
|
@ -299,7 +301,7 @@ public class DesignBase
|
||||||
ret[idx.ToString()] = new JObject()
|
ret[idx.ToString()] = new JObject()
|
||||||
{
|
{
|
||||||
["Value"] = customize[idx].Value,
|
["Value"] = customize[idx].Value,
|
||||||
["Apply"] = ApplyCustomizeRaw.HasFlag(idx.ToFlag()),
|
["Apply"] = Application.Customize.HasFlag(idx.ToFlag()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -382,7 +384,7 @@ public class DesignBase
|
||||||
{
|
{
|
||||||
var k = uint.Parse(key.Name, NumberStyles.HexNumber);
|
var k = uint.Parse(key.Name, NumberStyles.HexNumber);
|
||||||
var v = value.ToObject<MaterialValueDesign>();
|
var v = value.ToObject<MaterialValueDesign>();
|
||||||
if (!MaterialValueIndex.FromKey(k, out var idx))
|
if (!MaterialValueIndex.FromKey(k, out _))
|
||||||
{
|
{
|
||||||
Glamourer.Messager.NotificationMessage($"Invalid material value key {k} for design {name}, skipped.",
|
Glamourer.Messager.NotificationMessage($"Invalid material value key {k} for design {name}, skipped.",
|
||||||
NotificationType.Warning);
|
NotificationType.Warning);
|
||||||
|
|
@ -429,7 +431,7 @@ public class DesignBase
|
||||||
{
|
{
|
||||||
if (parameters == null)
|
if (parameters == null)
|
||||||
{
|
{
|
||||||
design.ApplyParameters = 0;
|
design.Application.Parameters = 0;
|
||||||
design.GetDesignDataRef().Parameters = default;
|
design.GetDesignDataRef().Parameters = default;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -490,7 +492,7 @@ public class DesignBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
design.ApplyParameters &= ~flag;
|
design.Application.Parameters &= ~flag;
|
||||||
design.GetDesignDataRef().Parameters[flag] = CustomizeParameterValue.Zero;
|
design.GetDesignDataRef().Parameters[flag] = CustomizeParameterValue.Zero;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -669,11 +671,12 @@ public class DesignBase
|
||||||
{
|
{
|
||||||
_designData = DesignBase64Migration.MigrateBase64(items, humans, base64, out var equipFlags, out var customizeFlags,
|
_designData = DesignBase64Migration.MigrateBase64(items, humans, base64, out var equipFlags, out var customizeFlags,
|
||||||
out var writeProtected, out var applyMeta);
|
out var writeProtected, out var applyMeta);
|
||||||
ApplyEquip = equipFlags;
|
Application.Equip = equipFlags;
|
||||||
ApplyCustomize = customizeFlags;
|
ApplyCustomize = customizeFlags;
|
||||||
ApplyParameters = 0;
|
Application.Parameters = 0;
|
||||||
ApplyCrest = 0;
|
Application.Crest = 0;
|
||||||
ApplyMeta = applyMeta;
|
Application.Meta = applyMeta;
|
||||||
|
Application.BonusItem = 0;
|
||||||
SetWriteProtected(writeProtected);
|
SetWriteProtected(writeProtected);
|
||||||
CustomizeSet = SetCustomizationSet(customize);
|
CustomizeSet = SetCustomizationSet(customize);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ public class DesignColors : ISavable, IReadOnlyDictionary<string, uint>
|
||||||
public static uint AutoColor(DesignBase design)
|
public static uint AutoColor(DesignBase design)
|
||||||
{
|
{
|
||||||
var customize = design.ApplyCustomizeExcludingBodyType == 0;
|
var customize = design.ApplyCustomizeExcludingBodyType == 0;
|
||||||
var equip = design.ApplyEquip == 0;
|
var equip = design.Application.Equip == 0;
|
||||||
return (customize, equip) switch
|
return (customize, equip) switch
|
||||||
{
|
{
|
||||||
(true, true) => ColorId.StateDesign.Value(),
|
(true, true) => ColorId.StateDesign.Value(),
|
||||||
|
|
|
||||||
|
|
@ -72,16 +72,11 @@ public class DesignConverter(
|
||||||
? Design.LoadDesign(_customize, _items, _linkLoader, jObject)
|
? Design.LoadDesign(_customize, _items, _linkLoader, jObject)
|
||||||
: DesignBase.LoadDesignBase(_customize, _items, jObject);
|
: DesignBase.LoadDesignBase(_customize, _items, jObject);
|
||||||
|
|
||||||
ret.SetApplyMeta(MetaIndex.Wetness, customize);
|
|
||||||
if (!customize)
|
if (!customize)
|
||||||
ret.ApplyCustomize = 0;
|
ret.Application.RemoveCustomize();
|
||||||
|
|
||||||
if (!equip)
|
if (!equip)
|
||||||
{
|
ret.Application.RemoveEquip();
|
||||||
ret.ApplyEquip = 0;
|
|
||||||
ret.ApplyCrest = 0;
|
|
||||||
ret.ApplyMeta &= ~(MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -155,16 +150,11 @@ public class DesignConverter(
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.SetApplyMeta(MetaIndex.Wetness, customize);
|
|
||||||
if (!customize)
|
if (!customize)
|
||||||
ret.ApplyCustomize = 0;
|
ret.Application.RemoveCustomize();
|
||||||
|
|
||||||
if (!equip)
|
if (!equip)
|
||||||
{
|
ret.Application.RemoveEquip();
|
||||||
ret.ApplyEquip = 0;
|
|
||||||
ret.ApplyCrest = 0;
|
|
||||||
ret.ApplyMeta &= ~(MetaFlag.HatState | MetaFlag.WeaponState | MetaFlag.VisorState);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,10 @@ namespace Glamourer.Designs;
|
||||||
|
|
||||||
public unsafe struct DesignData
|
public unsafe struct DesignData
|
||||||
{
|
{
|
||||||
public const int EquipmentByteSize = 10 * CharacterArmor.Size;
|
public const int NumEquipment = 10;
|
||||||
|
public const int EquipmentByteSize = NumEquipment * CharacterArmor.Size;
|
||||||
|
public const int NumBonusItems = 1;
|
||||||
|
public const int NumWeapons = 2;
|
||||||
|
|
||||||
private string _nameHead = string.Empty;
|
private string _nameHead = string.Empty;
|
||||||
private string _nameBody = string.Empty;
|
private string _nameBody = string.Empty;
|
||||||
|
|
@ -23,10 +26,14 @@ public unsafe struct DesignData
|
||||||
private string _nameLFinger = string.Empty;
|
private string _nameLFinger = string.Empty;
|
||||||
private string _nameMainhand = string.Empty;
|
private string _nameMainhand = string.Empty;
|
||||||
private string _nameOffhand = string.Empty;
|
private string _nameOffhand = string.Empty;
|
||||||
private string _nameFaceWear = string.Empty;
|
private string _nameGlasses = string.Empty;
|
||||||
private fixed uint _itemIds[12];
|
|
||||||
private fixed uint _iconIds[12];
|
private fixed uint _itemIds[NumEquipment + NumWeapons];
|
||||||
private fixed byte _equipmentBytes[EquipmentByteSize + 16];
|
private fixed uint _iconIds[NumEquipment + NumWeapons + NumBonusItems];
|
||||||
|
private fixed byte _equipmentBytes[EquipmentByteSize + NumWeapons * CharacterWeapon.Size];
|
||||||
|
private fixed ushort _bonusIds[NumBonusItems];
|
||||||
|
private fixed ushort _bonusModelIds[NumBonusItems];
|
||||||
|
private fixed byte _bonusVariants[NumBonusItems];
|
||||||
public CustomizeParameterData Parameters;
|
public CustomizeParameterData Parameters;
|
||||||
public CustomizeArray Customize = CustomizeArray.Default;
|
public CustomizeArray Customize = CustomizeArray.Default;
|
||||||
public uint ModelId;
|
public uint ModelId;
|
||||||
|
|
@ -52,7 +59,7 @@ public unsafe struct DesignData
|
||||||
|| name.IsContained(_nameLFinger)
|
|| name.IsContained(_nameLFinger)
|
||||||
|| name.IsContained(_nameMainhand)
|
|| name.IsContained(_nameMainhand)
|
||||||
|| name.IsContained(_nameOffhand)
|
|| name.IsContained(_nameOffhand)
|
||||||
|| name.IsContained(_nameFaceWear);
|
|| name.IsContained(_nameGlasses);
|
||||||
|
|
||||||
public readonly StainIds Stain(EquipSlot slot)
|
public readonly StainIds Stain(EquipSlot slot)
|
||||||
{
|
{
|
||||||
|
|
@ -101,6 +108,15 @@ public unsafe struct DesignData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly BonusItem BonusItem(BonusItemFlag slot)
|
||||||
|
=> slot switch
|
||||||
|
{
|
||||||
|
// @formatter:off
|
||||||
|
BonusItemFlag.Glasses => new BonusItem(_nameGlasses, _iconIds[12], _bonusIds[0], _bonusModelIds[0], _bonusVariants[0], BonusItemFlag.Glasses),
|
||||||
|
_ => Penumbra.GameData.Structs.BonusItem.Empty(slot),
|
||||||
|
// @formatter:on
|
||||||
|
};
|
||||||
|
|
||||||
public readonly CharacterArmor Armor(EquipSlot slot)
|
public readonly CharacterArmor Armor(EquipSlot slot)
|
||||||
{
|
{
|
||||||
fixed (byte* ptr = _equipmentBytes)
|
fixed (byte* ptr = _equipmentBytes)
|
||||||
|
|
@ -134,7 +150,7 @@ public unsafe struct DesignData
|
||||||
public bool SetItem(EquipSlot slot, EquipItem item)
|
public bool SetItem(EquipSlot slot, EquipItem item)
|
||||||
{
|
{
|
||||||
var index = slot.ToIndex();
|
var index = slot.ToIndex();
|
||||||
if (index > 11)
|
if (index > NumEquipment + NumWeapons)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_itemIds[index] = item.ItemId.Id;
|
_itemIds[index] = item.ItemId.Id;
|
||||||
|
|
@ -173,6 +189,25 @@ public unsafe struct DesignData
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool SetBonusItem(BonusItemFlag slot, BonusItem item)
|
||||||
|
{
|
||||||
|
var index = slot.ToIndex();
|
||||||
|
if (index > NumBonusItems)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_iconIds[NumEquipment + NumWeapons + index] = item.Icon.Id;
|
||||||
|
_bonusIds[index] = item.Id.Id;
|
||||||
|
_bonusModelIds[index] = item.ModelId.Id;
|
||||||
|
_bonusVariants[index] = item.Variant.Id;
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
_nameGlasses = item.Name;
|
||||||
|
return true;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool SetStain(EquipSlot slot, StainIds stains)
|
public bool SetStain(EquipSlot slot, StainIds stains)
|
||||||
=> slot.ToIndex() switch
|
=> slot.ToIndex() switch
|
||||||
{
|
{
|
||||||
|
|
@ -323,7 +358,7 @@ public unsafe struct DesignData
|
||||||
_nameWrists = string.Empty;
|
_nameWrists = string.Empty;
|
||||||
_nameRFinger = string.Empty;
|
_nameRFinger = string.Empty;
|
||||||
_nameLFinger = string.Empty;
|
_nameLFinger = string.Empty;
|
||||||
_nameFaceWear = string.Empty;
|
_nameGlasses = string.Empty;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,6 +165,11 @@ public class DesignEditor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ChangeBonusItem(object data, BonusItemFlag slot, BonusItem item, ApplySettings settings = default)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void ChangeStains(object data, EquipSlot slot, StainIds stains, ApplySettings _ = default)
|
public void ChangeStains(object data, EquipSlot slot, StainIds stains, ApplySettings _ = default)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -347,6 +347,18 @@ public sealed class DesignManager : DesignEditor
|
||||||
DesignChanged.Invoke(DesignChanged.Type.ApplyEquip, design, slot);
|
DesignChanged.Invoke(DesignChanged.Type.ApplyEquip, design, slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change whether to apply a specific equipment piece. </summary>
|
||||||
|
public void ChangeApplyBonusItem(Design design, BonusItemFlag slot, bool value)
|
||||||
|
{
|
||||||
|
if (!design.SetApplyBonusItem(slot, value))
|
||||||
|
return;
|
||||||
|
|
||||||
|
design.LastEdit = DateTimeOffset.UtcNow;
|
||||||
|
SaveService.QueueSave(design);
|
||||||
|
Glamourer.Log.Debug($"Set applying of {slot} bonus item to {value}.");
|
||||||
|
DesignChanged.Invoke(DesignChanged.Type.ApplyBonus, design, slot);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Change whether to apply a specific stain. </summary>
|
/// <summary> Change whether to apply a specific stain. </summary>
|
||||||
public void ChangeApplyStain(Design design, EquipSlot slot, bool value)
|
public void ChangeApplyStain(Design design, EquipSlot slot, bool value)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,9 @@ public interface IDesignEditor
|
||||||
public void ChangeItem(object data, EquipSlot slot, EquipItem item, ApplySettings settings = default)
|
public void ChangeItem(object data, EquipSlot slot, EquipItem item, ApplySettings settings = default)
|
||||||
=> ChangeEquip(data, slot, item, null, settings);
|
=> ChangeEquip(data, slot, item, null, settings);
|
||||||
|
|
||||||
|
/// <summary> Change a bonus item. </summary>
|
||||||
|
public void ChangeBonusItem(object data, BonusItemFlag slot, BonusItem item, ApplySettings settings = default);
|
||||||
|
|
||||||
/// <summary> Change the stain for any equipment piece. </summary>
|
/// <summary> Change the stain for any equipment piece. </summary>
|
||||||
public void ChangeStains(object data, EquipSlot slot, StainIds stains, ApplySettings settings = default)
|
public void ChangeStains(object data, EquipSlot slot, StainIds stains, ApplySettings settings = default)
|
||||||
=> ChangeEquip(data, slot, null, stains, settings);
|
=> ChangeEquip(data, slot, null, stains, settings);
|
||||||
|
|
|
||||||
|
|
@ -42,14 +42,15 @@ public class DesignMerger(
|
||||||
if (!data.IsHuman)
|
if (!data.IsHuman)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var (equipFlags, customizeFlags, crestFlags, parameterFlags, applyMeta) = type.ApplyWhat(design);
|
var collection = type.ApplyWhat(design);
|
||||||
ReduceMeta(data, applyMeta, ret, source);
|
ReduceMeta(data, collection.Meta, ret, source);
|
||||||
ReduceCustomize(data, customizeFlags, ref fixFlags, ret, source, respectOwnership, startBodyType);
|
ReduceCustomize(data, collection.Customize, ref fixFlags, ret, source, respectOwnership, startBodyType);
|
||||||
ReduceEquip(data, equipFlags, ret, source, respectOwnership);
|
ReduceEquip(data, collection.Equip, ret, source, respectOwnership);
|
||||||
ReduceMainhands(data, jobs, equipFlags, ret, source, respectOwnership);
|
ReduceBonusItems(data, collection.BonusItem, ret, source, respectOwnership);
|
||||||
ReduceOffhands(data, jobs, equipFlags, ret, source, respectOwnership);
|
ReduceMainhands(data, jobs, collection.Equip, ret, source, respectOwnership);
|
||||||
ReduceCrests(data, crestFlags, ret, source);
|
ReduceOffhands(data, jobs, collection.Equip, ret, source, respectOwnership);
|
||||||
ReduceParameters(data, parameterFlags, ret, source);
|
ReduceCrests(data, collection.Crest, ret, source);
|
||||||
|
ReduceParameters(data, collection.Parameters, ret, source);
|
||||||
ReduceMods(design as Design, ret, modAssociations);
|
ReduceMods(design as Design, ret, modAssociations);
|
||||||
if (type.HasFlag(ApplicationType.GearCustomization))
|
if (type.HasFlag(ApplicationType.GearCustomization))
|
||||||
ReduceMaterials(design, ret);
|
ReduceMaterials(design, ret);
|
||||||
|
|
@ -83,7 +84,7 @@ public class DesignMerger(
|
||||||
|
|
||||||
private static void ReduceMeta(in DesignData design, MetaFlag applyMeta, MergedDesign ret, StateSource source)
|
private static void ReduceMeta(in DesignData design, MetaFlag applyMeta, MergedDesign ret, StateSource source)
|
||||||
{
|
{
|
||||||
applyMeta &= ~ret.Design.ApplyMeta;
|
applyMeta &= ~ret.Design.Application.Meta;
|
||||||
if (applyMeta == 0)
|
if (applyMeta == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -100,7 +101,7 @@ public class DesignMerger(
|
||||||
|
|
||||||
private static void ReduceCrests(in DesignData design, CrestFlag crestFlags, MergedDesign ret, StateSource source)
|
private static void ReduceCrests(in DesignData design, CrestFlag crestFlags, MergedDesign ret, StateSource source)
|
||||||
{
|
{
|
||||||
crestFlags &= ~ret.Design.ApplyCrest;
|
crestFlags &= ~ret.Design.Application.Crest;
|
||||||
if (crestFlags == 0)
|
if (crestFlags == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -118,7 +119,7 @@ public class DesignMerger(
|
||||||
private static void ReduceParameters(in DesignData design, CustomizeParameterFlag parameterFlags, MergedDesign ret,
|
private static void ReduceParameters(in DesignData design, CustomizeParameterFlag parameterFlags, MergedDesign ret,
|
||||||
StateSource source)
|
StateSource source)
|
||||||
{
|
{
|
||||||
parameterFlags &= ~ret.Design.ApplyParameters;
|
parameterFlags &= ~ret.Design.Application.Parameters;
|
||||||
if (parameterFlags == 0)
|
if (parameterFlags == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -136,7 +137,7 @@ public class DesignMerger(
|
||||||
private void ReduceEquip(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateSource source,
|
private void ReduceEquip(in DesignData design, EquipFlag equipFlags, MergedDesign ret, StateSource source,
|
||||||
bool respectOwnership)
|
bool respectOwnership)
|
||||||
{
|
{
|
||||||
equipFlags &= ~ret.Design.ApplyEquip;
|
equipFlags &= ~ret.Design.Application.Equip;
|
||||||
if (equipFlags == 0)
|
if (equipFlags == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -174,6 +175,22 @@ public class DesignMerger(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReduceBonusItems(in DesignData design, BonusItemFlag bonusItems, MergedDesign ret, StateSource source, bool respectOwnership)
|
||||||
|
{
|
||||||
|
bonusItems &= ~ret.Design.Application.BonusItem;
|
||||||
|
if (bonusItems == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags.Where(b => bonusItems.HasFlag(b)))
|
||||||
|
{
|
||||||
|
var item = design.BonusItem(slot);
|
||||||
|
if (!respectOwnership || true) // TODO: maybe check unlocks
|
||||||
|
ret.Design.GetDesignDataRef().SetBonusItem(slot, item);
|
||||||
|
ret.Design.SetApplyBonusItem(slot, true);
|
||||||
|
ret.Sources[slot] = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ReduceMainhands(in DesignData design, JobFlag allowedJobs, EquipFlag equipFlags, MergedDesign ret, StateSource source,
|
private void ReduceMainhands(in DesignData design, JobFlag allowedJobs, EquipFlag equipFlags, MergedDesign ret, StateSource source,
|
||||||
bool respectOwnership)
|
bool respectOwnership)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,7 @@ public sealed class MergedDesign
|
||||||
public MergedDesign(DesignManager designManager)
|
public MergedDesign(DesignManager designManager)
|
||||||
{
|
{
|
||||||
Design = designManager.CreateTemporary();
|
Design = designManager.CreateTemporary();
|
||||||
Design.ApplyEquip = 0;
|
Design.Application = ApplicationCollection.None;
|
||||||
Design.ApplyCustomize = 0;
|
|
||||||
Design.ApplyCrest = 0;
|
|
||||||
Design.ApplyParameters = 0;
|
|
||||||
Design.ApplyMeta = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MergedDesign(DesignBase design)
|
public MergedDesign(DesignBase design)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ namespace Glamourer.Events;
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class BonusSlotUpdating()
|
public sealed class BonusSlotUpdating()
|
||||||
: EventWrapperRef34<Model, BonusEquipFlag, CharacterArmor, ulong, BonusSlotUpdating.Priority>(nameof(BonusSlotUpdating))
|
: EventWrapperRef34<Model, BonusItemFlag, CharacterArmor, ulong, BonusSlotUpdating.Priority>(nameof(BonusSlotUpdating))
|
||||||
{
|
{
|
||||||
public enum Priority
|
public enum Priority
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,9 @@ public sealed class DesignChanged()
|
||||||
/// <summary> An existing design changed whether a specific equipment piece is applied. Data is the slot of the equipment [EquipSlot]. </summary>
|
/// <summary> An existing design changed whether a specific equipment piece is applied. Data is the slot of the equipment [EquipSlot]. </summary>
|
||||||
ApplyEquip,
|
ApplyEquip,
|
||||||
|
|
||||||
|
/// <summary> An existing design changed whether a specific bonus item is applied. Data is the slot of the item [BonusItemFlag]. </summary>
|
||||||
|
ApplyBonus,
|
||||||
|
|
||||||
/// <summary> An existing design changed whether a specific stain is applied. Data is the slot of the equipment [EquipSlot]. </summary>
|
/// <summary> An existing design changed whether a specific stain is applied. Data is the slot of the equipment [EquipSlot]. </summary>
|
||||||
ApplyStain,
|
ApplyStain,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,8 +179,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
using var _ = design!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||||
using var _ = design!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
|
|
||||||
_stateManager.ApplyDesign(state, design, ApplySettings.ManualWithLinks);
|
_stateManager.ApplyDesign(state, design, ApplySettings.ManualWithLinks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
57
Glamourer/Gui/Equipment/BonusDrawData.cs
Normal file
57
Glamourer/Gui/Equipment/BonusDrawData.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
using Glamourer.Designs;
|
||||||
|
using Glamourer.State;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
namespace Glamourer.Gui.Equipment;
|
||||||
|
|
||||||
|
public struct BonusDrawData(BonusItemFlag slot, in DesignData designData)
|
||||||
|
{
|
||||||
|
private IDesignEditor _editor;
|
||||||
|
private object _object;
|
||||||
|
public readonly BonusItemFlag Slot = slot;
|
||||||
|
public bool Locked;
|
||||||
|
public bool DisplayApplication;
|
||||||
|
public bool AllowRevert;
|
||||||
|
|
||||||
|
public readonly bool IsDesign
|
||||||
|
=> _object is Design;
|
||||||
|
|
||||||
|
public readonly bool IsState
|
||||||
|
=> _object is ActorState;
|
||||||
|
|
||||||
|
public readonly void SetItem(BonusItem item)
|
||||||
|
=> _editor.ChangeBonusItem(_object, Slot, item, ApplySettings.Manual);
|
||||||
|
|
||||||
|
public readonly void SetApplyItem(bool value)
|
||||||
|
{
|
||||||
|
var manager = (DesignManager)_editor;
|
||||||
|
var design = (Design)_object;
|
||||||
|
manager.ChangeApplyBonusItem(design, Slot, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BonusItem CurrentItem = designData.BonusItem(slot);
|
||||||
|
public BonusItem GameItem = default;
|
||||||
|
public bool CurrentApply;
|
||||||
|
|
||||||
|
public static BonusDrawData FromDesign(DesignManager manager, Design design, BonusItemFlag slot)
|
||||||
|
=> new(slot, design.DesignData)
|
||||||
|
{
|
||||||
|
_editor = manager,
|
||||||
|
_object = design,
|
||||||
|
CurrentApply = design.DoApplyBonusItem(slot),
|
||||||
|
Locked = design.WriteProtected(),
|
||||||
|
DisplayApplication = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static BonusDrawData FromState(StateManager manager, ActorState state, BonusItemFlag slot)
|
||||||
|
=> new(slot, state.ModelData)
|
||||||
|
{
|
||||||
|
_editor = manager,
|
||||||
|
_object = state,
|
||||||
|
Locked = state.IsLocked,
|
||||||
|
DisplayApplication = false,
|
||||||
|
GameItem = state.BaseData.BonusItem(slot),
|
||||||
|
AllowRevert = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
123
Glamourer/Gui/Equipment/BonusItemCombo.cs
Normal file
123
Glamourer/Gui/Equipment/BonusItemCombo.cs
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
using Dalamud.Plugin.Services;
|
||||||
|
using Glamourer.Services;
|
||||||
|
using Glamourer.Unlocks;
|
||||||
|
using ImGuiNET;
|
||||||
|
using Lumina.Excel.GeneratedSheets;
|
||||||
|
using OtterGui;
|
||||||
|
using OtterGui.Classes;
|
||||||
|
using OtterGui.Log;
|
||||||
|
using OtterGui.Raii;
|
||||||
|
using OtterGui.Widgets;
|
||||||
|
using Penumbra.GameData.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
namespace Glamourer.Gui.Equipment;
|
||||||
|
|
||||||
|
public sealed class BonusItemCombo : FilterComboCache<BonusItem>
|
||||||
|
{
|
||||||
|
private readonly FavoriteManager _favorites;
|
||||||
|
public readonly string Label;
|
||||||
|
private BonusItemId _currentItem;
|
||||||
|
private float _innerWidth;
|
||||||
|
|
||||||
|
public PrimaryId CustomSetId { get; private set; }
|
||||||
|
public Variant CustomVariant { get; private set; }
|
||||||
|
|
||||||
|
public BonusItemCombo(IDataManager gameData, ItemManager items, BonusItemFlag slot, Logger log, FavoriteManager favorites)
|
||||||
|
: base(() => GetItems(favorites, items, slot), MouseWheelType.Control, log)
|
||||||
|
{
|
||||||
|
_favorites = favorites;
|
||||||
|
Label = GetLabel(gameData, slot);
|
||||||
|
_currentItem = 0;
|
||||||
|
SearchByParts = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DrawList(float width, float itemHeight)
|
||||||
|
{
|
||||||
|
base.DrawList(width, itemHeight);
|
||||||
|
if (NewSelection != null && Items.Count > NewSelection.Value)
|
||||||
|
CurrentSelection = Items[NewSelection.Value];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int UpdateCurrentSelected(int currentSelected)
|
||||||
|
{
|
||||||
|
if (CurrentSelection.Id == _currentItem)
|
||||||
|
return currentSelected;
|
||||||
|
|
||||||
|
CurrentSelectionIdx = Items.IndexOf(i => i.Id == _currentItem);
|
||||||
|
CurrentSelection = CurrentSelectionIdx >= 0 ? Items[CurrentSelectionIdx] : default;
|
||||||
|
return base.UpdateCurrentSelected(CurrentSelectionIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Draw(string previewName, BonusItemId previewIdx, float width, float innerWidth)
|
||||||
|
{
|
||||||
|
_innerWidth = innerWidth;
|
||||||
|
_currentItem = previewIdx;
|
||||||
|
CustomVariant = 0;
|
||||||
|
return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override float GetFilterWidth()
|
||||||
|
=> _innerWidth - 2 * ImGui.GetStyle().FramePadding.X;
|
||||||
|
|
||||||
|
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||||
|
{
|
||||||
|
var obj = Items[globalIdx];
|
||||||
|
var name = ToString(obj);
|
||||||
|
if (UiHelpers.DrawFavoriteStar(_favorites, obj) && CurrentSelectionIdx == globalIdx)
|
||||||
|
{
|
||||||
|
CurrentSelectionIdx = -1;
|
||||||
|
_currentItem = obj.Id;
|
||||||
|
CurrentSelection = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
var ret = ImGui.Selectable(name, selected);
|
||||||
|
ImGui.SameLine();
|
||||||
|
using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF808080);
|
||||||
|
ImGuiUtil.RightAlign($"({obj.ModelId.Id}-{obj.Variant.Id})");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||||
|
=> base.IsVisible(globalIndex, filter) || filter.IsContained(Items[globalIndex].ModelId.Id.ToString());
|
||||||
|
|
||||||
|
protected override string ToString(BonusItem obj)
|
||||||
|
=> obj.Name;
|
||||||
|
|
||||||
|
private static string GetLabel(IDataManager gameData, BonusItemFlag slot)
|
||||||
|
{
|
||||||
|
var sheet = gameData.GetExcelSheet<Addon>()!;
|
||||||
|
|
||||||
|
return slot switch
|
||||||
|
{
|
||||||
|
BonusItemFlag.Glasses => sheet.GetRow(16050)?.Text.ToString() ?? "Facewear",
|
||||||
|
BonusItemFlag.UnkSlot => sheet.GetRow(16051)?.Text.ToString() ?? "Facewear",
|
||||||
|
|
||||||
|
_ => string.Empty,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<BonusItem> GetItems(FavoriteManager favorites, ItemManager items, BonusItemFlag slot)
|
||||||
|
{
|
||||||
|
var nothing = BonusItem.Empty(slot);
|
||||||
|
if (slot is not BonusItemFlag.Glasses)
|
||||||
|
return [nothing];
|
||||||
|
|
||||||
|
return items.DictBonusItems.Values.OrderByDescending(favorites.Contains).ThenBy(i => i.Id.Id).Prepend(nothing).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnClosePopup()
|
||||||
|
{
|
||||||
|
// If holding control while the popup closes, try to parse the input as a full pair of set id and variant, and set a custom item for that.
|
||||||
|
if (!ImGui.GetIO().KeyCtrl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var split = Filter.Text.Split('-', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||||
|
if (split.Length != 2 || !ushort.TryParse(split[0], out var setId) || !byte.TryParse(split[1], out var variant))
|
||||||
|
return;
|
||||||
|
|
||||||
|
CustomSetId = setId;
|
||||||
|
CustomVariant = variant;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,6 +24,7 @@ public class EquipmentDrawer
|
||||||
private readonly GlamourerColorCombo _stainCombo;
|
private readonly GlamourerColorCombo _stainCombo;
|
||||||
private readonly DictStain _stainData;
|
private readonly DictStain _stainData;
|
||||||
private readonly ItemCombo[] _itemCombo;
|
private readonly ItemCombo[] _itemCombo;
|
||||||
|
private readonly BonusItemCombo[] _bonusItemCombo;
|
||||||
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
||||||
private readonly CodeService _codes;
|
private readonly CodeService _codes;
|
||||||
private readonly TextureService _textures;
|
private readonly TextureService _textures;
|
||||||
|
|
@ -46,6 +47,7 @@ public class EquipmentDrawer
|
||||||
_stainData = items.Stains;
|
_stainData = items.Stains;
|
||||||
_stainCombo = new GlamourerColorCombo(DefaultWidth - 20, _stainData, favorites);
|
_stainCombo = new GlamourerColorCombo(DefaultWidth - 20, _stainData, favorites);
|
||||||
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, Glamourer.Log, favorites)).ToArray();
|
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, Glamourer.Log, favorites)).ToArray();
|
||||||
|
_bonusItemCombo = BonusExtensions.AllFlags.Select(f => new BonusItemCombo(gameData, items, f, Glamourer.Log, favorites)).ToArray();
|
||||||
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
|
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
|
||||||
foreach (var type in Enum.GetValues<FullEquipType>())
|
foreach (var type in Enum.GetValues<FullEquipType>())
|
||||||
{
|
{
|
||||||
|
|
@ -100,6 +102,21 @@ public class EquipmentDrawer
|
||||||
DrawEquipNormal(equipDrawData);
|
DrawEquipNormal(equipDrawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DrawBonusItem(BonusDrawData bonusDrawData)
|
||||||
|
{
|
||||||
|
if (_config.HideApplyCheckmarks)
|
||||||
|
bonusDrawData.DisplayApplication = false;
|
||||||
|
|
||||||
|
using var id = ImRaii.PushId(100 + (int)bonusDrawData.Slot);
|
||||||
|
var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y };
|
||||||
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
|
||||||
|
|
||||||
|
if (_config.SmallEquip)
|
||||||
|
DrawBonusItemSmall(bonusDrawData);
|
||||||
|
else
|
||||||
|
DrawBonusItemNormal(bonusDrawData);
|
||||||
|
}
|
||||||
|
|
||||||
public void DrawWeapons(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
public void DrawWeapons(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
||||||
{
|
{
|
||||||
if (mainhand.CurrentItem.PrimaryId.Id == 0)
|
if (mainhand.CurrentItem.PrimaryId.Id == 0)
|
||||||
|
|
@ -302,6 +319,25 @@ public class EquipmentDrawer
|
||||||
ImGui.TextUnformatted(label);
|
ImGui.TextUnformatted(label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawBonusItemSmall(in BonusDrawData bonusDrawData)
|
||||||
|
{
|
||||||
|
ImGui.Dummy(new Vector2(StainId.NumStains * ImUtf8.FrameHeight + (StainId.NumStains - 1) * ImUtf8.ItemSpacing.X, ImUtf8.FrameHeight));
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawBonusItem(bonusDrawData, out var label, true, false, false);
|
||||||
|
if (bonusDrawData.DisplayApplication)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawApply(bonusDrawData);
|
||||||
|
}
|
||||||
|
else if (bonusDrawData.IsState)
|
||||||
|
{
|
||||||
|
_advancedDyes.DrawButton(bonusDrawData.Slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextUnformatted(label);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawWeaponsSmall(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
private void DrawWeaponsSmall(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
||||||
{
|
{
|
||||||
DrawStain(mainhand, true);
|
DrawStain(mainhand, true);
|
||||||
|
|
@ -382,6 +418,27 @@ public class EquipmentDrawer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawBonusItemNormal(in BonusDrawData bonusDrawData)
|
||||||
|
{
|
||||||
|
ImGui.Dummy(_iconSize with { Y = ImUtf8.FrameHeight });
|
||||||
|
var right = ImGui.IsItemClicked(ImGuiMouseButton.Right);
|
||||||
|
var left = ImGui.IsItemClicked(ImGuiMouseButton.Left);
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawBonusItem(bonusDrawData, out var label, false, right, left);
|
||||||
|
if (bonusDrawData.DisplayApplication)
|
||||||
|
{
|
||||||
|
ImGui.SameLine();
|
||||||
|
DrawApply(bonusDrawData);
|
||||||
|
}
|
||||||
|
else if (bonusDrawData.IsState)
|
||||||
|
{
|
||||||
|
_advancedDyes.DrawButton(bonusDrawData.Slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
ImGui.TextUnformatted(label);
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawWeaponsNormal(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
private void DrawWeaponsNormal(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons)
|
||||||
{
|
{
|
||||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing,
|
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing,
|
||||||
|
|
@ -491,6 +548,25 @@ public class EquipmentDrawer
|
||||||
data.SetItem(item);
|
data.SetItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawBonusItem(in BonusDrawData data, out string label, bool small, bool clear, bool open)
|
||||||
|
{
|
||||||
|
var combo = _bonusItemCombo[data.Slot.ToIndex()];
|
||||||
|
label = combo.Label;
|
||||||
|
if (!data.Locked && open)
|
||||||
|
UiHelpers.OpenCombo($"##{combo.Label}");
|
||||||
|
|
||||||
|
using var disabled = ImRaii.Disabled(data.Locked);
|
||||||
|
var change = combo.Draw(data.CurrentItem.Name, data.CurrentItem.Id, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength,
|
||||||
|
_requiredComboWidth);
|
||||||
|
if (change)
|
||||||
|
data.SetItem(combo.CurrentSelection);
|
||||||
|
else if (combo.CustomVariant.Id > 0)
|
||||||
|
data.SetItem(_items.Identify(data.Slot, combo.CustomSetId, combo.CustomVariant));
|
||||||
|
|
||||||
|
if (ResetOrClear(data.Locked, clear, data.AllowRevert, true, data.CurrentItem, data.GameItem, BonusItem.Empty(data.Slot), out var item))
|
||||||
|
data.SetItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
private static bool ResetOrClear<T>(bool locked, bool clicked, bool allowRevert, bool allowClear,
|
private static bool ResetOrClear<T>(bool locked, bool clicked, bool allowRevert, bool allowClear,
|
||||||
in T currentItem, in T revertItem, in T clearItem, out T? item) where T : IEquatable<T>
|
in T currentItem, in T revertItem, in T clearItem, out T? item) where T : IEquatable<T>
|
||||||
{
|
{
|
||||||
|
|
@ -590,6 +666,13 @@ public class EquipmentDrawer
|
||||||
data.SetApplyItem(enabled);
|
data.SetApplyItem(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void DrawApply(in BonusDrawData data)
|
||||||
|
{
|
||||||
|
if (UiHelpers.DrawCheckbox($"##apply{data.Slot}", "Apply this bonus item when applying the Design.", data.CurrentApply, out var enabled,
|
||||||
|
data.Locked))
|
||||||
|
data.SetApplyItem(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
private static void DrawApplyStain(in EquipDrawData data)
|
private static void DrawApplyStain(in EquipDrawData data)
|
||||||
{
|
{
|
||||||
if (UiHelpers.DrawCheckbox($"##applyStain{data.Slot}", "Apply this dye to the item when applying the Design.", data.CurrentApplyStain,
|
if (UiHelpers.DrawCheckbox($"##applyStain{data.Slot}", "Apply this dye to the item when applying the Design.", data.CurrentApplyStain,
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,9 @@ public sealed unsafe class AdvancedDyePopup(
|
||||||
public void DrawButton(EquipSlot slot)
|
public void DrawButton(EquipSlot slot)
|
||||||
=> DrawButton(MaterialValueIndex.FromSlot(slot));
|
=> DrawButton(MaterialValueIndex.FromSlot(slot));
|
||||||
|
|
||||||
|
public void DrawButton(BonusItemFlag slot)
|
||||||
|
=> DrawButton(MaterialValueIndex.FromSlot(slot));
|
||||||
|
|
||||||
private void DrawButton(MaterialValueIndex index)
|
private void DrawButton(MaterialValueIndex index)
|
||||||
{
|
{
|
||||||
if (!config.UseAdvancedDyes)
|
if (!config.UseAdvancedDyes)
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,12 @@ public class ActorPanel
|
||||||
var offhand = EquipDrawData.FromState(_stateManager, _state, EquipSlot.OffHand);
|
var offhand = EquipDrawData.FromState(_stateManager, _state, EquipSlot.OffHand);
|
||||||
_equipmentDrawer.DrawWeapons(mainhand, offhand, GameMain.IsInGPose());
|
_equipmentDrawer.DrawWeapons(mainhand, offhand, GameMain.IsInGPose());
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var data = BonusDrawData.FromState(_stateManager, _state!, slot);
|
||||||
|
_equipmentDrawer.DrawBonusItem(data);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||||
DrawEquipmentMetaToggles();
|
DrawEquipmentMetaToggles();
|
||||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||||
|
|
|
||||||
|
|
@ -277,13 +277,13 @@ public class SetPanel(
|
||||||
var size = new Vector2(ImGui.GetFrameHeight());
|
var size = new Vector2(ImGui.GetFrameHeight());
|
||||||
size.X += ImGuiHelpers.GlobalScale;
|
size.X += ImGuiHelpers.GlobalScale;
|
||||||
|
|
||||||
var (equipFlags, customizeFlags, _, _, _) = design.ApplyWhat();
|
var collection = design.ApplyWhat();
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
var designData = design.Design.GetDesignData(default);
|
var designData = design.Design.GetDesignData(default);
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
|
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
|
||||||
{
|
{
|
||||||
var flag = slot.ToFlag();
|
var flag = slot.ToFlag();
|
||||||
if (!equipFlags.HasFlag(flag))
|
if (!collection.Equip.HasFlag(flag))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var item = designData.Item(slot);
|
var item = designData.Item(slot);
|
||||||
|
|
@ -308,7 +308,7 @@ public class SetPanel(
|
||||||
foreach (var type in CustomizationExtensions.All)
|
foreach (var type in CustomizationExtensions.All)
|
||||||
{
|
{
|
||||||
var flag = type.ToFlag();
|
var flag = type.ToFlag();
|
||||||
if (!customizeFlags.HasFlag(flag))
|
if (!collection.Customize.HasFlag(flag))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (flag.RequiresRedraw())
|
if (flag.RequiresRedraw())
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ public class DesignManagerPanel(DesignManager _designManager, DesignFileSystem _
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
DrawDesign(design, _designFileSystem);
|
DrawDesign(design, _designFileSystem);
|
||||||
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw, design.ApplyMeta,
|
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.Application.Equip, design.Application.Customize, design.Application.Meta,
|
||||||
design.WriteProtected());
|
design.WriteProtected());
|
||||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||||
ImGuiUtil.TextWrapped(base64);
|
ImGuiUtil.TextWrapped(base64);
|
||||||
|
|
|
||||||
|
|
@ -112,11 +112,7 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
|
||||||
public DesignBase CreateDesign(in MirageManager.GlamourPlate plate)
|
public DesignBase CreateDesign(in MirageManager.GlamourPlate plate)
|
||||||
{
|
{
|
||||||
var design = _design.CreateTemporary();
|
var design = _design.CreateTemporary();
|
||||||
design.ApplyCustomize = 0;
|
design.Application = ApplicationCollection.None;
|
||||||
design.ApplyCrest = 0;
|
|
||||||
design.ApplyMeta = 0;
|
|
||||||
design.ApplyParameters = 0;
|
|
||||||
design.ApplyEquip = 0;
|
|
||||||
foreach (var (slot, index) in EquipSlotExtensions.FullSlots.WithIndex())
|
foreach (var (slot, index) in EquipSlotExtensions.FullSlots.WithIndex())
|
||||||
{
|
{
|
||||||
var itemId = plate.ItemIds[index];
|
var itemId = plate.ItemIds[index];
|
||||||
|
|
@ -129,7 +125,7 @@ public unsafe class GlamourPlatePanel : IGameDataDrawer
|
||||||
|
|
||||||
design.GetDesignDataRef().SetItem(slot, item);
|
design.GetDesignDataRef().SetItem(slot, item);
|
||||||
design.GetDesignDataRef().SetStain(slot, StainIds.FromGlamourPlate(plate, index));
|
design.GetDesignDataRef().SetStain(slot, StainIds.FromGlamourPlate(plate, index));
|
||||||
design.ApplyEquip |= slot.ToBothFlags();
|
design.Application.Equip |= slot.ToBothFlags();
|
||||||
}
|
}
|
||||||
|
|
||||||
return design;
|
return design;
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public unsafe class ModelEvaluationPanel(
|
||||||
UpdateSlotService _updateSlotService,
|
UpdateSlotService _updateSlotService,
|
||||||
ChangeCustomizeService _changeCustomizeService,
|
ChangeCustomizeService _changeCustomizeService,
|
||||||
CrestService _crestService,
|
CrestService _crestService,
|
||||||
DictGlasses _glasses) : IGameDataDrawer
|
DictBonusItems bonusItems) : IGameDataDrawer
|
||||||
{
|
{
|
||||||
public string Label
|
public string Label
|
||||||
=> "Model Evaluation";
|
=> "Model Evaluation";
|
||||||
|
|
@ -57,6 +57,16 @@ public unsafe class ModelEvaluationPanel(
|
||||||
ImGui.TextUnformatted($"Transformation Id: {actor.AsCharacter->CharacterData.TransformationId}");
|
ImGui.TextUnformatted($"Transformation Id: {actor.AsCharacter->CharacterData.TransformationId}");
|
||||||
if (actor.AsCharacter->CharacterData.ModelCharaId_2 != -1)
|
if (actor.AsCharacter->CharacterData.ModelCharaId_2 != -1)
|
||||||
ImGui.TextUnformatted($"ModelChara2 {actor.AsCharacter->CharacterData.ModelCharaId_2}");
|
ImGui.TextUnformatted($"ModelChara2 {actor.AsCharacter->CharacterData.ModelCharaId_2}");
|
||||||
|
|
||||||
|
ImGuiUtil.DrawTableColumn("Character Mode");
|
||||||
|
ImGuiUtil.DrawTableColumn($"{actor.AsCharacter->Mode}");
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
|
||||||
|
ImGuiUtil.DrawTableColumn("Animation");
|
||||||
|
ImGuiUtil.DrawTableColumn($"{((ushort*)&actor.AsCharacter->Timeline)[0x78]}");
|
||||||
|
ImGui.TableNextColumn();
|
||||||
|
ImGui.TableNextColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiUtil.DrawTableColumn("Mainhand");
|
ImGuiUtil.DrawTableColumn("Mainhand");
|
||||||
|
|
@ -226,7 +236,7 @@ public unsafe class ModelEvaluationPanel(
|
||||||
_updateSlotService.UpdateEquipSlot(model, slot, actor.GetArmor(slot));
|
_updateSlotService.UpdateEquipSlot(model, slot, actor.GetArmor(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var slot in BonusSlotExtensions.AllFlags)
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
{
|
{
|
||||||
using var id2 = ImRaii.PushId((int)slot.ToModelIndex());
|
using var id2 = ImRaii.PushId((int)slot.ToModelIndex());
|
||||||
ImGuiUtil.DrawTableColumn(slot.ToName());
|
ImGuiUtil.DrawTableColumn(slot.ToName());
|
||||||
|
|
@ -236,9 +246,9 @@ public unsafe class ModelEvaluationPanel(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var glassesId = actor.GetBonusSlot(slot);
|
var glassesId = actor.GetBonusItem(slot);
|
||||||
if (_glasses.TryGetValue(glassesId, out var glasses))
|
if (bonusItems.TryGetValue(glassesId, out var glasses))
|
||||||
ImGuiUtil.DrawTableColumn($"{glasses.Id.Id},{glasses.Variant.Id} ({glassesId})");
|
ImGuiUtil.DrawTableColumn($"{glasses.ModelId.Id},{glasses.Variant.Id} ({glassesId})");
|
||||||
else
|
else
|
||||||
ImGuiUtil.DrawTableColumn($"{glassesId}");
|
ImGuiUtil.DrawTableColumn($"{glassesId}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,13 @@ public class DesignPanel
|
||||||
var mainhand = EquipDrawData.FromDesign(_manager, _selector.Selected!, EquipSlot.MainHand);
|
var mainhand = EquipDrawData.FromDesign(_manager, _selector.Selected!, EquipSlot.MainHand);
|
||||||
var offhand = EquipDrawData.FromDesign(_manager, _selector.Selected!, EquipSlot.OffHand);
|
var offhand = EquipDrawData.FromDesign(_manager, _selector.Selected!, EquipSlot.OffHand);
|
||||||
_equipmentDrawer.DrawWeapons(mainhand, offhand, true);
|
_equipmentDrawer.DrawWeapons(mainhand, offhand, true);
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var data = BonusDrawData.FromDesign(_manager, _selector.Selected!, slot);
|
||||||
|
_equipmentDrawer.DrawBonusItem(data);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||||
DrawEquipmentMetaToggles();
|
DrawEquipmentMetaToggles();
|
||||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||||
|
|
@ -149,7 +156,7 @@ public class DesignPanel
|
||||||
if (!h)
|
if (!h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected.ApplyCustomizeRaw,
|
if (_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected.Application.Customize,
|
||||||
_selector.Selected!.WriteProtected(), false))
|
_selector.Selected!.WriteProtected(), false))
|
||||||
foreach (var idx in Enum.GetValues<CustomizeIndex>())
|
foreach (var idx in Enum.GetValues<CustomizeIndex>())
|
||||||
{
|
{
|
||||||
|
|
@ -224,7 +231,7 @@ public class DesignPanel
|
||||||
private void DrawCrestApplication()
|
private void DrawCrestApplication()
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId("Crests");
|
using var id = ImRaii.PushId("Crests");
|
||||||
var flags = (uint)_selector.Selected!.ApplyCrest;
|
var flags = (uint)_selector.Selected!.Application.Crest;
|
||||||
var bigChange = ImGui.CheckboxFlags("Apply All Crests", ref flags, (uint)CrestExtensions.AllRelevant);
|
var bigChange = ImGui.CheckboxFlags("Apply All Crests", ref flags, (uint)CrestExtensions.AllRelevant);
|
||||||
foreach (var flag in CrestExtensions.AllRelevantSet)
|
foreach (var flag in CrestExtensions.AllRelevantSet)
|
||||||
{
|
{
|
||||||
|
|
@ -255,7 +262,7 @@ public class DesignPanel
|
||||||
{
|
{
|
||||||
void ApplyEquip(string label, EquipFlag allFlags, bool stain, IEnumerable<EquipSlot> slots)
|
void ApplyEquip(string label, EquipFlag allFlags, bool stain, IEnumerable<EquipSlot> slots)
|
||||||
{
|
{
|
||||||
var flags = (uint)(allFlags & _selector.Selected!.ApplyEquip);
|
var flags = (uint)(allFlags & _selector.Selected!.Application.Equip);
|
||||||
using var id = ImRaii.PushId(label);
|
using var id = ImRaii.PushId(label);
|
||||||
var bigChange = ImGui.CheckboxFlags($"Apply All {label}", ref flags, (uint)allFlags);
|
var bigChange = ImGui.CheckboxFlags($"Apply All {label}", ref flags, (uint)allFlags);
|
||||||
if (stain)
|
if (stain)
|
||||||
|
|
@ -302,7 +309,7 @@ public class DesignPanel
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId("Meta");
|
using var id = ImRaii.PushId("Meta");
|
||||||
const uint all = (uint)MetaExtensions.All;
|
const uint all = (uint)MetaExtensions.All;
|
||||||
var flags = (uint)_selector.Selected!.ApplyMeta;
|
var flags = (uint)_selector.Selected!.Application.Meta;
|
||||||
var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all);
|
var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all);
|
||||||
|
|
||||||
var labels = new[]
|
var labels = new[]
|
||||||
|
|
@ -324,7 +331,7 @@ public class DesignPanel
|
||||||
private void DrawParameterApplication()
|
private void DrawParameterApplication()
|
||||||
{
|
{
|
||||||
using var id = ImRaii.PushId("Parameter");
|
using var id = ImRaii.PushId("Parameter");
|
||||||
var flags = (uint)_selector.Selected!.ApplyParameters;
|
var flags = (uint)_selector.Selected!.Application.Parameters;
|
||||||
var bigChange = ImGui.CheckboxFlags("Apply All Customize Parameters", ref flags, (uint)CustomizeParameterExtensions.All);
|
var bigChange = ImGui.CheckboxFlags("Apply All Customize Parameters", ref flags, (uint)CustomizeParameterExtensions.All);
|
||||||
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||||
{
|
{
|
||||||
|
|
@ -408,8 +415,7 @@ public class DesignPanel
|
||||||
|
|
||||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
using var _ = _selector.Selected!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||||
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
|
|
||||||
_state.ApplyDesign(state, _selector.Selected!, ApplySettings.ManualWithLinks);
|
_state.ApplyDesign(state, _selector.Selected!, ApplySettings.ManualWithLinks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -427,8 +433,7 @@ public class DesignPanel
|
||||||
|
|
||||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
|
using var _ = _selector.Selected!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||||
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
|
|
||||||
_state.ApplyDesign(state, _selector.Selected!, ApplySettings.ManualWithLinks);
|
_state.ApplyDesign(state, _selector.Selected!, ApplySettings.ManualWithLinks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Glamourer.GameData;
|
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.Unlocks;
|
using Glamourer.Unlocks;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
@ -98,15 +97,6 @@ public static class UiHelpers
|
||||||
return (currentValue != newValue, currentApply != newApply);
|
return (currentValue != newValue, currentApply != newApply);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (EquipFlag, CustomizeFlag, CrestFlag, CustomizeParameterFlag) ConvertKeysToFlags()
|
|
||||||
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
|
||||||
{
|
|
||||||
(false, false) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All, CustomizeParameterExtensions.All),
|
|
||||||
(true, true) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All, CustomizeParameterExtensions.All),
|
|
||||||
(true, false) => (EquipFlagExtensions.All, (CustomizeFlag)0, CrestExtensions.All, 0),
|
|
||||||
(false, true) => ((EquipFlag)0, CustomizeFlagExtensions.AllRelevant, 0, CustomizeParameterExtensions.All),
|
|
||||||
};
|
|
||||||
|
|
||||||
public static (bool, bool) ConvertKeysToBool()
|
public static (bool, bool) ConvertKeysToBool()
|
||||||
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
||||||
{
|
{
|
||||||
|
|
@ -126,16 +116,36 @@ public static class UiHelpers
|
||||||
using var c = ImRaii.PushColor(ImGuiCol.Text,
|
using var c = ImRaii.PushColor(ImGuiCol.Text,
|
||||||
hovering ? ColorId.FavoriteStarHovered.Value() : favorite ? ColorId.FavoriteStarOn.Value() : ColorId.FavoriteStarOff.Value());
|
hovering ? ColorId.FavoriteStarHovered.Value() : favorite ? ColorId.FavoriteStarOn.Value() : ColorId.FavoriteStarOff.Value());
|
||||||
ImGui.TextUnformatted(FontAwesomeIcon.Star.ToIconString());
|
ImGui.TextUnformatted(FontAwesomeIcon.Star.ToIconString());
|
||||||
if (ImGui.IsItemClicked())
|
if (!ImGui.IsItemClicked())
|
||||||
{
|
return false;
|
||||||
|
|
||||||
if (favorite)
|
if (favorite)
|
||||||
favorites.Remove(item);
|
favorites.Remove(item);
|
||||||
else
|
else
|
||||||
favorites.TryAdd(item);
|
favorites.TryAdd(item);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool DrawFavoriteStar(FavoriteManager favorites, BonusItem item)
|
||||||
|
{
|
||||||
|
var favorite = favorites.Contains(item);
|
||||||
|
var hovering = ImGui.IsMouseHoveringRect(ImGui.GetCursorScreenPos(),
|
||||||
|
ImGui.GetCursorScreenPos() + new Vector2(ImGui.GetTextLineHeight()));
|
||||||
|
|
||||||
|
using var font = ImRaii.PushFont(UiBuilder.IconFont);
|
||||||
|
using var c = ImRaii.PushColor(ImGuiCol.Text,
|
||||||
|
hovering ? ColorId.FavoriteStarHovered.Value() : favorite ? ColorId.FavoriteStarOn.Value() : ColorId.FavoriteStarOff.Value());
|
||||||
|
ImGui.TextUnformatted(FontAwesomeIcon.Star.ToIconString());
|
||||||
|
if (!ImGui.IsItemClicked())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (favorite)
|
||||||
|
favorites.Remove(item);
|
||||||
|
else
|
||||||
|
favorites.TryAdd(item);
|
||||||
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool DrawFavoriteStar(FavoriteManager favorites, StainId stain)
|
public static bool DrawFavoriteStar(FavoriteManager favorites, StainId stain)
|
||||||
|
|
@ -149,15 +159,14 @@ public static class UiHelpers
|
||||||
hovering ? ColorId.FavoriteStarHovered.Value() : favorite ? ColorId.FavoriteStarOn.Value() : ColorId.FavoriteStarOff.Value());
|
hovering ? ColorId.FavoriteStarHovered.Value() : favorite ? ColorId.FavoriteStarOn.Value() : ColorId.FavoriteStarOff.Value());
|
||||||
ImGui.AlignTextToFramePadding();
|
ImGui.AlignTextToFramePadding();
|
||||||
ImGui.TextUnformatted(FontAwesomeIcon.Star.ToIconString());
|
ImGui.TextUnformatted(FontAwesomeIcon.Star.ToIconString());
|
||||||
if (ImGui.IsItemClicked())
|
if (!ImGui.IsItemClicked())
|
||||||
{
|
return false;
|
||||||
|
|
||||||
if (favorite)
|
if (favorite)
|
||||||
favorites.Remove(stain);
|
favorites.Remove(stain);
|
||||||
else
|
else
|
||||||
favorites.TryAdd(stain);
|
favorites.TryAdd(stain);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -42,6 +42,12 @@ public readonly record struct MaterialValueIndex(
|
||||||
return Invalid;
|
return Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MaterialValueIndex FromSlot(BonusItemFlag slot)
|
||||||
|
{
|
||||||
|
var idx = slot.ToIndex();
|
||||||
|
return idx > 2 ? Invalid : new MaterialValueIndex(DrawObjectType.Human, (byte)(idx + 16), 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
public EquipSlot ToEquipSlot()
|
public EquipSlot ToEquipSlot()
|
||||||
=> DrawObject switch
|
=> DrawObject switch
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -37,17 +37,13 @@ public class PaletteImport(IDalamudPluginInterface pluginInterface, DesignManage
|
||||||
}
|
}
|
||||||
|
|
||||||
var design = designManager.CreateEmpty(fullPath, true);
|
var design = designManager.CreateEmpty(fullPath, true);
|
||||||
design.ApplyCustomize = 0;
|
design.Application = ApplicationCollection.None;
|
||||||
design.ApplyEquip = 0;
|
|
||||||
design.ApplyCrest = 0;
|
|
||||||
designManager.ChangeApplyMeta(design, MetaIndex.VisorState, false);
|
|
||||||
designManager.ChangeApplyMeta(design, MetaIndex.HatState, false);
|
|
||||||
designManager.ChangeApplyMeta(design, MetaIndex.WeaponState, false);
|
|
||||||
foreach (var flag in flags.Iterate())
|
foreach (var flag in flags.Iterate())
|
||||||
{
|
{
|
||||||
designManager.ChangeApplyParameter(design, flag, true);
|
designManager.ChangeApplyParameter(design, flag, true);
|
||||||
designManager.ChangeCustomizeParameter(design, flag, palette[flag]);
|
designManager.ChangeCustomizeParameter(design, flag, palette[flag]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Glamourer.Log.Information($"Added design for palette {name} at {fullPath}.");
|
Glamourer.Log.Information($"Added design for palette {name} at {fullPath}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,14 +14,14 @@ public unsafe class UpdateSlotService : IDisposable
|
||||||
{
|
{
|
||||||
public readonly EquipSlotUpdating EquipSlotUpdatingEvent;
|
public readonly EquipSlotUpdating EquipSlotUpdatingEvent;
|
||||||
public readonly BonusSlotUpdating BonusSlotUpdatingEvent;
|
public readonly BonusSlotUpdating BonusSlotUpdatingEvent;
|
||||||
private readonly DictGlasses _glasses;
|
private readonly DictBonusItems _bonusItems;
|
||||||
|
|
||||||
public UpdateSlotService(EquipSlotUpdating equipSlotUpdating, BonusSlotUpdating bonusSlotUpdating, IGameInteropProvider interop,
|
public UpdateSlotService(EquipSlotUpdating equipSlotUpdating, BonusSlotUpdating bonusSlotUpdating, IGameInteropProvider interop,
|
||||||
DictGlasses glasses)
|
DictBonusItems bonusItems)
|
||||||
{
|
{
|
||||||
EquipSlotUpdatingEvent = equipSlotUpdating;
|
EquipSlotUpdatingEvent = equipSlotUpdating;
|
||||||
BonusSlotUpdatingEvent = bonusSlotUpdating;
|
BonusSlotUpdatingEvent = bonusSlotUpdating;
|
||||||
_glasses = glasses;
|
_bonusItems = bonusItems;
|
||||||
interop.InitializeFromAttributes(this);
|
interop.InitializeFromAttributes(this);
|
||||||
_flagSlotForUpdateHook.Enable();
|
_flagSlotForUpdateHook.Enable();
|
||||||
_flagBonusSlotForUpdateHook.Enable();
|
_flagBonusSlotForUpdateHook.Enable();
|
||||||
|
|
@ -41,7 +41,7 @@ public unsafe class UpdateSlotService : IDisposable
|
||||||
FlagSlotForUpdateInterop(drawObject, slot, data);
|
FlagSlotForUpdateInterop(drawObject, slot, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateBonusSlot(Model drawObject, BonusEquipFlag slot, CharacterArmor data)
|
public void UpdateBonusSlot(Model drawObject, BonusItemFlag slot, CharacterArmor data)
|
||||||
{
|
{
|
||||||
if (!drawObject.IsCharacterBase)
|
if (!drawObject.IsCharacterBase)
|
||||||
return;
|
return;
|
||||||
|
|
@ -53,13 +53,13 @@ public unsafe class UpdateSlotService : IDisposable
|
||||||
_flagBonusSlotForUpdateHook.Original(drawObject.Address, index, &data);
|
_flagBonusSlotForUpdateHook.Original(drawObject.Address, index, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateGlasses(Model drawObject, GlassesId id)
|
public void UpdateGlasses(Model drawObject, BonusItemId id)
|
||||||
{
|
{
|
||||||
if (!_glasses.TryGetValue(id, out var glasses))
|
if (!_bonusItems.TryGetValue(id, out var glasses))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var armor = new CharacterArmor(glasses.Id, glasses.Variant, StainIds.None);
|
var armor = new CharacterArmor(glasses.ModelId, glasses.Variant, StainIds.None);
|
||||||
_flagBonusSlotForUpdateHook.Original(drawObject.Address, BonusEquipFlag.Glasses.ToIndex(), &armor);
|
_flagBonusSlotForUpdateHook.Original(drawObject.Address, BonusItemFlag.Glasses.ToIndex(), &armor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateArmor(Model drawObject, EquipSlot slot, CharacterArmor armor, StainIds stains)
|
public void UpdateArmor(Model drawObject, EquipSlot slot, CharacterArmor armor, StainIds stains)
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,13 @@ public class ItemManager
|
||||||
public readonly ExcelSheet<Lumina.Excel.GeneratedSheets.Item> ItemSheet;
|
public readonly ExcelSheet<Lumina.Excel.GeneratedSheets.Item> ItemSheet;
|
||||||
public readonly DictStain Stains;
|
public readonly DictStain Stains;
|
||||||
public readonly ItemData ItemData;
|
public readonly ItemData ItemData;
|
||||||
|
public readonly DictBonusItems DictBonusItems;
|
||||||
public readonly RestrictedGear RestrictedGear;
|
public readonly RestrictedGear RestrictedGear;
|
||||||
|
|
||||||
public readonly EquipItem DefaultSword;
|
public readonly EquipItem DefaultSword;
|
||||||
|
|
||||||
public ItemManager(Configuration config, IDataManager gameData, ObjectIdentification objectIdentification,
|
public ItemManager(Configuration config, IDataManager gameData, ObjectIdentification objectIdentification,
|
||||||
ItemData itemData, DictStain stains, RestrictedGear restrictedGear)
|
ItemData itemData, DictStain stains, RestrictedGear restrictedGear, DictBonusItems dictBonusItems)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
ItemSheet = gameData.GetExcelSheet<Lumina.Excel.GeneratedSheets.Item>()!;
|
ItemSheet = gameData.GetExcelSheet<Lumina.Excel.GeneratedSheets.Item>()!;
|
||||||
|
|
@ -33,6 +34,7 @@ public class ItemManager
|
||||||
ItemData = itemData;
|
ItemData = itemData;
|
||||||
Stains = stains;
|
Stains = stains;
|
||||||
RestrictedGear = restrictedGear;
|
RestrictedGear = restrictedGear;
|
||||||
|
DictBonusItems = dictBonusItems;
|
||||||
DefaultSword = EquipItem.FromMainhand(ItemSheet.GetRow(1601)!); // Weathered Shortsword
|
DefaultSword = EquipItem.FromMainhand(ItemSheet.GetRow(1601)!); // Weathered Shortsword
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,6 +126,22 @@ public class ItemManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BonusItem Identify(BonusItemFlag slot, PrimaryId id, Variant variant)
|
||||||
|
{
|
||||||
|
var index = slot.ToIndex();
|
||||||
|
if (index == uint.MaxValue)
|
||||||
|
return new BonusItem($"Invalid ({id.Id}-{variant})", 0, 0, id, variant, slot);
|
||||||
|
|
||||||
|
if (id.Id == 0)
|
||||||
|
return BonusItem.Empty(slot);
|
||||||
|
|
||||||
|
return ObjectIdentification.Identify(id, variant, slot)
|
||||||
|
.FirstOrDefault(new BonusItem($"Invalid ({id.Id}-{variant})", 0, 0, id, variant, slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
public BonusItem Resolve(BonusItemFlag slot, BonusItemId id)
|
||||||
|
=> IsBonusItemValid(slot, id, out var item) ? item : new BonusItem($"Invalid ({id.Id})", 0, id, 0, 0, slot);
|
||||||
|
|
||||||
/// <summary> Return the default offhand for a given mainhand, that is for both handed weapons, return the correct offhand part, and for everything else Nothing. </summary>
|
/// <summary> Return the default offhand for a given mainhand, that is for both handed weapons, return the correct offhand part, and for everything else Nothing. </summary>
|
||||||
public EquipItem GetDefaultOffhand(EquipItem mainhand)
|
public EquipItem GetDefaultOffhand(EquipItem mainhand)
|
||||||
{
|
{
|
||||||
|
|
@ -161,6 +179,18 @@ public class ItemManager
|
||||||
return item.Valid;
|
return item.Valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Returns whether a bonus item id represents a valid item for a slot and gives the item. </summary>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||||
|
public bool IsBonusItemValid(BonusItemFlag slot, BonusItemId itemId, out BonusItem item)
|
||||||
|
{
|
||||||
|
if (itemId.Id != 0)
|
||||||
|
return DictBonusItems.TryGetValue(itemId, out item) && slot == item.Slot;
|
||||||
|
|
||||||
|
item = BonusItem.Empty(slot);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Check whether an item id resolves to an existing item of the correct slot (which should not be weapons.)
|
/// Check whether an item id resolves to an existing item of the correct slot (which should not be weapons.)
|
||||||
/// The returned item is either the resolved correct item, or the Nothing item for that slot.
|
/// The returned item is either the resolved correct item, or the Nothing item for that slot.
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,18 @@ public class InternalStateEditor(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change a single bonus item. </summary>
|
||||||
|
public bool ChangeBonusItem(ActorState state, BonusItemFlag slot, BonusItem item, StateSource source, out BonusItem oldItem, uint key = 0)
|
||||||
|
{
|
||||||
|
oldItem = state.ModelData.BonusItem(slot);
|
||||||
|
if (!state.CanUnlock(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.ModelData.SetBonusItem(slot, item);
|
||||||
|
state.Sources[slot] = source;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Change a single piece of equipment including stain. </summary>
|
/// <summary> Change a single piece of equipment including stain. </summary>
|
||||||
public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainIds stains, StateSource source, out EquipItem oldItem,
|
public bool ChangeEquip(ActorState state, EquipSlot slot, EquipItem item, StainIds stains, StateSource source, out EquipItem oldItem,
|
||||||
out StainIds oldStains, uint key = 0)
|
out StainIds oldStains, uint key = 0)
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,33 @@ public class StateApplier(
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ChangeBonusItem(ActorData data, BonusItemFlag slot, PrimaryId id, Variant variant)
|
||||||
|
{
|
||||||
|
var item = new CharacterArmor(id, variant, StainIds.None);
|
||||||
|
foreach (var actor in data.Objects.Where(a => a.IsCharacter))
|
||||||
|
{
|
||||||
|
var mdl = actor.Model;
|
||||||
|
if (!mdl.IsHuman)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_updateSlot.UpdateBonusSlot(actor.Model, slot, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ChangeBonusItem(ActorData,BonusItemFlag,PrimaryId,Variant)"/>
|
||||||
|
public ActorData ChangeBonusItem(ActorState state, BonusItemFlag slot, bool apply)
|
||||||
|
{
|
||||||
|
// If the source is not IPC we do not want to apply restrictions.
|
||||||
|
var data = GetData(state);
|
||||||
|
if (apply)
|
||||||
|
{
|
||||||
|
var item = state.ModelData.BonusItem(slot);
|
||||||
|
ChangeBonusItem(data, slot, item.ModelId, item.Variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Change the stain of a single piece of armor or weapon.
|
/// Change the stain of a single piece of armor or weapon.
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,18 @@ public class StateEditor(
|
||||||
StateChanged.Invoke(type, settings.Source, state, actors, (old, item, slot));
|
StateChanged.Invoke(type, settings.Source, state, actors, (old, item, slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ChangeBonusItem(object data, BonusItemFlag slot, BonusItem item, ApplySettings settings = default)
|
||||||
|
{
|
||||||
|
var state = (ActorState)data;
|
||||||
|
if (!Editor.ChangeBonusItem(state, slot, item, settings.Source, out var old, settings.Key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var actors = Applier.ChangeBonusItem(state, slot, settings.Source.RequiresChange());
|
||||||
|
Glamourer.Log.Verbose(
|
||||||
|
$"Set {slot.ToName()} in state {state.Identifier.Incognito(null)} from {old.Name} ({old.Id}) to {item.Name} ({item.Id}). [Affecting {actors.ToLazyString("nothing")}.]");
|
||||||
|
StateChanged.Invoke(StateChangeType.BonusItem, settings.Source, state, actors, (old, item, slot));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainIds? stains, ApplySettings settings)
|
public void ChangeEquip(object data, EquipSlot slot, EquipItem? item, StainIds? stains, ApplySettings settings)
|
||||||
{
|
{
|
||||||
|
|
@ -226,7 +238,7 @@ public class StateEditor(
|
||||||
out _, settings.Key);
|
out _, settings.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
var customizeFlags = mergedDesign.Design.ApplyCustomizeRaw;
|
var customizeFlags = mergedDesign.Design.Application.Customize;
|
||||||
if (mergedDesign.Design.DoApplyCustomize(CustomizeIndex.Clan))
|
if (mergedDesign.Design.DoApplyCustomize(CustomizeIndex.Clan))
|
||||||
customizeFlags |= CustomizeFlag.Race;
|
customizeFlags |= CustomizeFlag.Race;
|
||||||
|
|
||||||
|
|
@ -245,7 +257,7 @@ public class StateEditor(
|
||||||
state.Sources[parameter] = StateSource.Game;
|
state.Sources[parameter] = StateSource.Game;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var parameter in mergedDesign.Design.ApplyParameters.Iterate())
|
foreach (var parameter in mergedDesign.Design.Application.Parameters.Iterate())
|
||||||
{
|
{
|
||||||
if (settings.RespectManual && state.Sources[parameter].IsManual())
|
if (settings.RespectManual && state.Sources[parameter].IsManual())
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -273,6 +285,13 @@ public class StateEditor(
|
||||||
Source(slot.ToState(true)), out _, settings.Key);
|
Source(slot.ToState(true)), out _, settings.Key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
if (mergedDesign.Design.DoApplyBonusItem(slot))
|
||||||
|
if (!settings.RespectManual || !state.Sources[slot].IsManual())
|
||||||
|
Editor.ChangeBonusItem(state, slot, mergedDesign.Design.DesignData.BonusItem(slot), Source(slot), out _, settings.Key);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var weaponSlot in EquipSlotExtensions.WeaponSlots)
|
foreach (var weaponSlot in EquipSlotExtensions.WeaponSlots)
|
||||||
{
|
{
|
||||||
if (mergedDesign.Design.DoApplyStain(weaponSlot))
|
if (mergedDesign.Design.DoApplyStain(weaponSlot))
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,13 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
_ => Invalid,
|
_ => Invalid,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static implicit operator StateIndex(BonusItemFlag flag)
|
||||||
|
=> flag switch
|
||||||
|
{
|
||||||
|
BonusItemFlag.Glasses => new StateIndex(BonusItemGlasses),
|
||||||
|
_ => Invalid,
|
||||||
|
};
|
||||||
|
|
||||||
public static implicit operator StateIndex(CustomizeIndex index)
|
public static implicit operator StateIndex(CustomizeIndex index)
|
||||||
=> index switch
|
=> index switch
|
||||||
{
|
{
|
||||||
|
|
@ -198,23 +205,13 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
public const int ParamFacePaintUvOffset = ParamFacePaintUvMultiplier + 1;
|
public const int ParamFacePaintUvOffset = ParamFacePaintUvMultiplier + 1;
|
||||||
public const int ParamDecalColor = ParamFacePaintUvOffset + 1;
|
public const int ParamDecalColor = ParamFacePaintUvOffset + 1;
|
||||||
|
|
||||||
public const int Size = ParamDecalColor + 1;
|
public const int BonusItemGlasses = ParamDecalColor + 1;
|
||||||
|
|
||||||
|
public const int Size = BonusItemGlasses + 1;
|
||||||
|
|
||||||
public static IEnumerable<StateIndex> All
|
public static IEnumerable<StateIndex> All
|
||||||
=> Enumerable.Range(0, Size - 1).Select(i => new StateIndex(i));
|
=> Enumerable.Range(0, Size - 1).Select(i => new StateIndex(i));
|
||||||
|
|
||||||
public bool GetApply(DesignBase data)
|
|
||||||
=> GetFlag() switch
|
|
||||||
{
|
|
||||||
EquipFlag e => data.ApplyEquip.HasFlag(e),
|
|
||||||
CustomizeFlag c => data.ApplyCustomize.HasFlag(c),
|
|
||||||
MetaFlag m => data.ApplyMeta.HasFlag(m),
|
|
||||||
CrestFlag c => data.ApplyCrest.HasFlag(c),
|
|
||||||
CustomizeParameterFlag c => data.ApplyParameters.HasFlag(c),
|
|
||||||
bool v => v,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
public string ToName()
|
public string ToName()
|
||||||
=> GetFlag() switch
|
=> GetFlag() switch
|
||||||
{
|
{
|
||||||
|
|
@ -223,6 +220,7 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
MetaFlag m => m.ToIndex().ToName(),
|
MetaFlag m => m.ToIndex().ToName(),
|
||||||
CrestFlag c => c.ToLabel(),
|
CrestFlag c => c.ToLabel(),
|
||||||
CustomizeParameterFlag c => c.ToName(),
|
CustomizeParameterFlag c => c.ToName(),
|
||||||
|
BonusItemFlag b => b.ToName(),
|
||||||
bool v => "Model ID",
|
bool v => "Model ID",
|
||||||
_ => "Unknown",
|
_ => "Unknown",
|
||||||
};
|
};
|
||||||
|
|
@ -317,6 +315,8 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
ParamFacePaintUvOffset => CustomizeParameterFlag.FacePaintUvOffset,
|
ParamFacePaintUvOffset => CustomizeParameterFlag.FacePaintUvOffset,
|
||||||
ParamDecalColor => CustomizeParameterFlag.DecalColor,
|
ParamDecalColor => CustomizeParameterFlag.DecalColor,
|
||||||
|
|
||||||
|
BonusItemGlasses => BonusItemFlag.Glasses,
|
||||||
|
|
||||||
_ => -1,
|
_ => -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -411,6 +411,8 @@ public readonly record struct StateIndex(int Value) : IEqualityOperators<StateIn
|
||||||
ParamFacePaintUvOffset => data.Parameters[CustomizeParameterFlag.FacePaintUvOffset],
|
ParamFacePaintUvOffset => data.Parameters[CustomizeParameterFlag.FacePaintUvOffset],
|
||||||
ParamDecalColor => data.Parameters[CustomizeParameterFlag.DecalColor],
|
ParamDecalColor => data.Parameters[CustomizeParameterFlag.DecalColor],
|
||||||
|
|
||||||
|
BonusItemGlasses => data.BonusItem(BonusItemFlag.Glasses),
|
||||||
|
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ public class StateListener : IDisposable
|
||||||
private readonly CustomizeService _customizations;
|
private readonly CustomizeService _customizations;
|
||||||
private readonly PenumbraService _penumbra;
|
private readonly PenumbraService _penumbra;
|
||||||
private readonly EquipSlotUpdating _equipSlotUpdating;
|
private readonly EquipSlotUpdating _equipSlotUpdating;
|
||||||
|
private readonly BonusSlotUpdating _bonusSlotUpdating;
|
||||||
private readonly WeaponLoading _weaponLoading;
|
private readonly WeaponLoading _weaponLoading;
|
||||||
private readonly HeadGearVisibilityChanged _headGearVisibility;
|
private readonly HeadGearVisibilityChanged _headGearVisibility;
|
||||||
private readonly VisorStateChanged _visorState;
|
private readonly VisorStateChanged _visorState;
|
||||||
|
|
@ -52,10 +53,11 @@ public class StateListener : IDisposable
|
||||||
private CharacterWeapon _lastFistOffhand = CharacterWeapon.Empty;
|
private CharacterWeapon _lastFistOffhand = CharacterWeapon.Empty;
|
||||||
|
|
||||||
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorManager actors, Configuration config,
|
public StateListener(StateManager manager, ItemManager items, PenumbraService penumbra, ActorManager actors, Configuration config,
|
||||||
EquipSlotUpdating equipSlotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
EquipSlotUpdating equipSlotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState,
|
||||||
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
|
WeaponVisibilityChanged weaponVisibility, HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier,
|
||||||
StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects, GPoseService gPose,
|
FunModule funModule, HumanModelList humans, StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects,
|
||||||
ChangeCustomizeService changeCustomizeService, CustomizeService customizations, ICondition condition, CrestService crestService)
|
GPoseService gPose, ChangeCustomizeService changeCustomizeService, CustomizeService customizations, ICondition condition,
|
||||||
|
CrestService crestService, BonusSlotUpdating bonusSlotUpdating)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_items = items;
|
_items = items;
|
||||||
|
|
@ -78,6 +80,7 @@ public class StateListener : IDisposable
|
||||||
_customizations = customizations;
|
_customizations = customizations;
|
||||||
_condition = condition;
|
_condition = condition;
|
||||||
_crestService = crestService;
|
_crestService = crestService;
|
||||||
|
_bonusSlotUpdating = bonusSlotUpdating;
|
||||||
Subscribe();
|
Subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,6 +230,35 @@ public class StateListener : IDisposable
|
||||||
(_, armor) = _items.RestrictedGear.ResolveRestricted(armor, slot, customize.Race, customize.Gender);
|
(_, armor) = _items.RestrictedGear.ResolveRestricted(armor, slot, customize.Race, customize.Gender);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnBonusSlotUpdating(Model model, BonusItemFlag slot, ref CharacterArmor item, ref ulong returnValue)
|
||||||
|
{
|
||||||
|
var actor = _penumbra.GameObjectFromDrawObject(model);
|
||||||
|
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (actor.Identifier(_actors, out var identifier)
|
||||||
|
&& _manager.TryGetValue(identifier, out var state))
|
||||||
|
switch (UpdateBaseData(actor, state, slot, item))
|
||||||
|
{
|
||||||
|
// Base data changed equipment while actors were not there.
|
||||||
|
// Update model state if not on fixed design.
|
||||||
|
case UpdateState.Change:
|
||||||
|
var apply = false;
|
||||||
|
if (!state.Sources[slot].IsFixed())
|
||||||
|
_manager.ChangeBonusItem(state, slot, state.BaseData.BonusItem(slot), ApplySettings.Game);
|
||||||
|
else
|
||||||
|
apply = true;
|
||||||
|
if (apply)
|
||||||
|
item = state.ModelData.BonusItem(slot).ToArmor();
|
||||||
|
break;
|
||||||
|
// Use current model data.
|
||||||
|
case UpdateState.NoChange:
|
||||||
|
item = state.ModelData.BonusItem(slot).ToArmor();
|
||||||
|
break;
|
||||||
|
case UpdateState.Transformed: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnMovedEquipment((EquipSlot, uint, StainIds)[] items)
|
private void OnMovedEquipment((EquipSlot, uint, StainIds)[] items)
|
||||||
{
|
{
|
||||||
_objects.Update();
|
_objects.Update();
|
||||||
|
|
@ -403,6 +435,28 @@ public class StateListener : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UpdateState UpdateBaseData(Actor actor, ActorState state, BonusItemFlag slot, CharacterArmor item)
|
||||||
|
{
|
||||||
|
var actorItemId = actor.GetBonusItem(slot);
|
||||||
|
if (!_items.IsBonusItemValid(slot, actorItemId, out var actorItem))
|
||||||
|
return UpdateState.NoChange;
|
||||||
|
|
||||||
|
// The actor item does not correspond to the model item, thus the actor is transformed.
|
||||||
|
if (actorItem.ModelId != item.Set || actorItem.Variant != item.Variant)
|
||||||
|
return UpdateState.Transformed;
|
||||||
|
|
||||||
|
var baseData = state.BaseData.BonusItem(slot);
|
||||||
|
var change = UpdateState.NoChange;
|
||||||
|
if (baseData.Id != actorItem.Id || baseData.ModelId != item.Set || baseData.Variant != item.Variant)
|
||||||
|
{
|
||||||
|
var identified = _items.Identify(slot, item.Set, item.Variant);
|
||||||
|
state.BaseData.SetBonusItem(slot, identified);
|
||||||
|
change = UpdateState.Change;
|
||||||
|
}
|
||||||
|
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Handle a full equip slot update for base data and model data. </summary>
|
/// <summary> Handle a full equip slot update for base data and model data. </summary>
|
||||||
private void HandleEquipSlot(Actor actor, ActorState state, EquipSlot slot, ref CharacterArmor armor)
|
private void HandleEquipSlot(Actor actor, ActorState state, EquipSlot slot, ref CharacterArmor armor)
|
||||||
{
|
{
|
||||||
|
|
@ -700,6 +754,7 @@ public class StateListener : IDisposable
|
||||||
_penumbra.CreatingCharacterBase += OnCreatingCharacterBase;
|
_penumbra.CreatingCharacterBase += OnCreatingCharacterBase;
|
||||||
_penumbra.CreatedCharacterBase += OnCreatedCharacterBase;
|
_penumbra.CreatedCharacterBase += OnCreatedCharacterBase;
|
||||||
_equipSlotUpdating.Subscribe(OnEquipSlotUpdating, EquipSlotUpdating.Priority.StateListener);
|
_equipSlotUpdating.Subscribe(OnEquipSlotUpdating, EquipSlotUpdating.Priority.StateListener);
|
||||||
|
_bonusSlotUpdating.Subscribe(OnBonusSlotUpdating, BonusSlotUpdating.Priority.StateListener);
|
||||||
_movedEquipment.Subscribe(OnMovedEquipment, MovedEquipment.Priority.StateListener);
|
_movedEquipment.Subscribe(OnMovedEquipment, MovedEquipment.Priority.StateListener);
|
||||||
_weaponLoading.Subscribe(OnWeaponLoading, WeaponLoading.Priority.StateListener);
|
_weaponLoading.Subscribe(OnWeaponLoading, WeaponLoading.Priority.StateListener);
|
||||||
_visorState.Subscribe(OnVisorChange, VisorStateChanged.Priority.StateListener);
|
_visorState.Subscribe(OnVisorChange, VisorStateChanged.Priority.StateListener);
|
||||||
|
|
@ -716,6 +771,7 @@ public class StateListener : IDisposable
|
||||||
_penumbra.CreatingCharacterBase -= OnCreatingCharacterBase;
|
_penumbra.CreatingCharacterBase -= OnCreatingCharacterBase;
|
||||||
_penumbra.CreatedCharacterBase -= OnCreatedCharacterBase;
|
_penumbra.CreatedCharacterBase -= OnCreatedCharacterBase;
|
||||||
_equipSlotUpdating.Unsubscribe(OnEquipSlotUpdating);
|
_equipSlotUpdating.Unsubscribe(OnEquipSlotUpdating);
|
||||||
|
_bonusSlotUpdating.Unsubscribe(OnBonusSlotUpdating);
|
||||||
_movedEquipment.Unsubscribe(OnMovedEquipment);
|
_movedEquipment.Unsubscribe(OnMovedEquipment);
|
||||||
_weaponLoading.Unsubscribe(OnWeaponLoading);
|
_weaponLoading.Unsubscribe(OnWeaponLoading);
|
||||||
_visorState.Unsubscribe(OnVisorChange);
|
_visorState.Unsubscribe(OnVisorChange);
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,13 @@ public sealed class StateManager(
|
||||||
|
|
||||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
ret.SetCrest(slot, CrestService.GetModelCrest(actor, slot));
|
ret.SetCrest(slot, CrestService.GetModelCrest(actor, slot));
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var data = model.GetBonus(slot);
|
||||||
|
var item = Items.Identify(slot, data.Set, data.Variant);
|
||||||
|
ret.SetBonusItem(slot, item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -181,6 +188,13 @@ public sealed class StateManager(
|
||||||
|
|
||||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
ret.SetCrest(slot, actor.GetCrest(slot));
|
ret.SetCrest(slot, actor.GetCrest(slot));
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var id = actor.GetBonusItem(slot);
|
||||||
|
var item = Items.Resolve(slot, id);
|
||||||
|
ret.SetBonusItem(slot, item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the weapons regardless of source.
|
// Set the weapons regardless of source.
|
||||||
|
|
@ -241,6 +255,9 @@ public sealed class StateManager(
|
||||||
state.Sources[slot, false] = StateSource.Game;
|
state.Sources[slot, false] = StateSource.Game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
state.Sources[slot] = StateSource.Game;
|
||||||
|
|
||||||
foreach (var type in Enum.GetValues<MetaIndex>())
|
foreach (var type in Enum.GetValues<MetaIndex>())
|
||||||
state.Sources[type] = StateSource.Game;
|
state.Sources[type] = StateSource.Game;
|
||||||
|
|
||||||
|
|
@ -328,6 +345,12 @@ public sealed class StateManager(
|
||||||
state.ModelData.IsHatVisible());
|
state.ModelData.IsHatVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
var item = state.ModelData.BonusItem(slot);
|
||||||
|
Applier.ChangeBonusItem(actors, slot, item.ModelId, item.Variant);
|
||||||
|
}
|
||||||
|
|
||||||
var mainhandActors = state.ModelData.MainhandType != state.BaseData.MainhandType ? actors.OnlyGPose() : actors;
|
var mainhandActors = state.ModelData.MainhandType != state.BaseData.MainhandType ? actors.OnlyGPose() : actors;
|
||||||
Applier.ChangeMainhand(mainhandActors, state.ModelData.Item(EquipSlot.MainHand), state.ModelData.Stain(EquipSlot.MainHand));
|
Applier.ChangeMainhand(mainhandActors, state.ModelData.Item(EquipSlot.MainHand), state.ModelData.Stain(EquipSlot.MainHand));
|
||||||
var offhandActors = state.ModelData.OffhandType != state.BaseData.OffhandType ? actors.OnlyGPose() : actors;
|
var offhandActors = state.ModelData.OffhandType != state.BaseData.OffhandType ? actors.OnlyGPose() : actors;
|
||||||
|
|
@ -364,6 +387,15 @@ public sealed class StateManager(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
|
{
|
||||||
|
if (state.Sources[slot] is StateSource.Fixed)
|
||||||
|
{
|
||||||
|
state.Sources[slot] = StateSource.Game;
|
||||||
|
state.ModelData.SetBonusItem(slot, state.BaseData.BonusItem(slot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var slot in CrestExtensions.AllRelevantSet)
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
{
|
{
|
||||||
if (state.Sources[slot] is StateSource.Fixed)
|
if (state.Sources[slot] is StateSource.Fixed)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ public class FavoriteManager : ISavable
|
||||||
private readonly HashSet<ItemId> _favorites = [];
|
private readonly HashSet<ItemId> _favorites = [];
|
||||||
private readonly HashSet<StainId> _favoriteColors = [];
|
private readonly HashSet<StainId> _favoriteColors = [];
|
||||||
private readonly HashSet<FavoriteHairStyle> _favoriteHairStyles = [];
|
private readonly HashSet<FavoriteHairStyle> _favoriteHairStyles = [];
|
||||||
|
private readonly HashSet<BonusItemId> _favoriteBonusItems = [];
|
||||||
|
|
||||||
public FavoriteManager(SaveService saveService)
|
public FavoriteManager(SaveService saveService)
|
||||||
{
|
{
|
||||||
|
|
@ -62,6 +63,7 @@ public class FavoriteManager : ISavable
|
||||||
_favorites.UnionWith(load!.FavoriteItems.Select(i => (ItemId)i));
|
_favorites.UnionWith(load!.FavoriteItems.Select(i => (ItemId)i));
|
||||||
_favoriteColors.UnionWith(load!.FavoriteColors.Select(i => (StainId)i));
|
_favoriteColors.UnionWith(load!.FavoriteColors.Select(i => (StainId)i));
|
||||||
_favoriteHairStyles.UnionWith(load!.FavoriteHairStyles.Select(t => new FavoriteHairStyle(t)));
|
_favoriteHairStyles.UnionWith(load!.FavoriteHairStyles.Select(t => new FavoriteHairStyle(t)));
|
||||||
|
_favoriteBonusItems.UnionWith(load!.FavoriteBonusItems.Select(b => new BonusItemId(b)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: throw new Exception($"Unknown Version {load?.Version ?? 0}");
|
default: throw new Exception($"Unknown Version {load?.Version ?? 0}");
|
||||||
|
|
@ -109,6 +111,11 @@ public class FavoriteManager : ISavable
|
||||||
foreach (var hairStyle in _favoriteHairStyles)
|
foreach (var hairStyle in _favoriteHairStyles)
|
||||||
j.WriteValue(hairStyle.ToValue());
|
j.WriteValue(hairStyle.ToValue());
|
||||||
j.WriteEndArray();
|
j.WriteEndArray();
|
||||||
|
j.WriteStartArray();
|
||||||
|
j.WritePropertyName(nameof(LoadIntermediary.FavoriteBonusItems));
|
||||||
|
foreach (var item in _favoriteBonusItems)
|
||||||
|
j.WriteValue(item.Id);
|
||||||
|
j.WriteEndArray();
|
||||||
j.WriteEndObject();
|
j.WriteEndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,9 +131,6 @@ public class FavoriteManager : ISavable
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAdd(Stain stain)
|
|
||||||
=> TryAdd(stain.RowIndex);
|
|
||||||
|
|
||||||
public bool TryAdd(StainId stain)
|
public bool TryAdd(StainId stain)
|
||||||
{
|
{
|
||||||
if (stain.Id == 0 || !_favoriteColors.Add(stain))
|
if (stain.Id == 0 || !_favoriteColors.Add(stain))
|
||||||
|
|
@ -136,6 +140,15 @@ public class FavoriteManager : ISavable
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryAdd(BonusItem bonusItem)
|
||||||
|
{
|
||||||
|
if (bonusItem.Id == 0 || !_favoriteBonusItems.Add(bonusItem.Id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool TryAdd(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
public bool TryAdd(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
||||||
{
|
{
|
||||||
if (!TypeAllowed(type) || !_favoriteHairStyles.Add(new FavoriteHairStyle(gender, race, type, value)))
|
if (!TypeAllowed(type) || !_favoriteHairStyles.Add(new FavoriteHairStyle(gender, race, type, value)))
|
||||||
|
|
@ -157,9 +170,6 @@ public class FavoriteManager : ISavable
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Remove(Stain stain)
|
|
||||||
=> Remove(stain.RowIndex);
|
|
||||||
|
|
||||||
public bool Remove(StainId stain)
|
public bool Remove(StainId stain)
|
||||||
{
|
{
|
||||||
if (!_favoriteColors.Remove(stain))
|
if (!_favoriteColors.Remove(stain))
|
||||||
|
|
@ -169,6 +179,15 @@ public class FavoriteManager : ISavable
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Remove(BonusItem bonusItem)
|
||||||
|
{
|
||||||
|
if (!_favoriteBonusItems.Remove(bonusItem.Id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool Remove(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
public bool Remove(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
||||||
{
|
{
|
||||||
if (!_favoriteHairStyles.Remove(new FavoriteHairStyle(gender, race, type, value)))
|
if (!_favoriteHairStyles.Remove(new FavoriteHairStyle(gender, race, type, value)))
|
||||||
|
|
@ -181,15 +200,12 @@ public class FavoriteManager : ISavable
|
||||||
public bool Contains(EquipItem item)
|
public bool Contains(EquipItem item)
|
||||||
=> _favorites.Contains(item.ItemId);
|
=> _favorites.Contains(item.ItemId);
|
||||||
|
|
||||||
public bool Contains(Stain stain)
|
|
||||||
=> _favoriteColors.Contains(stain.RowIndex);
|
|
||||||
|
|
||||||
public bool Contains(ItemId item)
|
|
||||||
=> _favorites.Contains(item);
|
|
||||||
|
|
||||||
public bool Contains(StainId stain)
|
public bool Contains(StainId stain)
|
||||||
=> _favoriteColors.Contains(stain);
|
=> _favoriteColors.Contains(stain);
|
||||||
|
|
||||||
|
public bool Contains(BonusItem bonusItem)
|
||||||
|
=> _favoriteBonusItems.Contains(bonusItem.Id);
|
||||||
|
|
||||||
public bool Contains(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
public bool Contains(Gender gender, SubRace race, CustomizeIndex type, CustomizeValue value)
|
||||||
=> _favoriteHairStyles.Contains(new FavoriteHairStyle(gender, race, type, value));
|
=> _favoriteHairStyles.Contains(new FavoriteHairStyle(gender, race, type, value));
|
||||||
|
|
||||||
|
|
@ -199,5 +215,6 @@ public class FavoriteManager : ISavable
|
||||||
public uint[] FavoriteItems = [];
|
public uint[] FavoriteItems = [];
|
||||||
public byte[] FavoriteColors = [];
|
public byte[] FavoriteColors = [];
|
||||||
public uint[] FavoriteHairStyles = [];
|
public uint[] FavoriteHairStyles = [];
|
||||||
|
public ushort[] FavoriteBonusItems = [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit d83303ccc3ec5d7237f5da621e9c2433ad28f9e1
|
Subproject commit 8928015f38f951810a9a6fbb44fb4a0cb9a712dd
|
||||||
Loading…
Add table
Add a link
Reference in a new issue