Utility class that defines clothing layer rules and normalization for the CharacterEditor. It computes consistent Under/Over slot pairs, fixes assets that declare upper-body slots on the inner layer for outerwear, checks compatibility between two clothing items, and adds items into a ClothingContainer while removing incompatible entries.
using System;
namespace CharacterEditor;
/// <summary>Consistent layer slots for selection, fitting and native Dresser entries.</summary>
public static class ClothingLayers
{
public const Clothing.Slots UpperBody = Clothing.Slots.Chest | Clothing.Slots.LeftArm | Clothing.Slots.RightArm;
static (Clothing.Slots Under, Clothing.Slots Over) Normalize(Clothing.Slots under, Clothing.Slots over, bool outerwear)
{
// Some outerwear declares its upper-body slots on the inner layer. Correct
// that contradiction without changing the source asset or its other slots.
if (outerwear && (over & UpperBody) == 0)
{
over |= under & UpperBody;
under &= ~UpperBody;
}
return (under, over);
}
public static (Clothing.Slots Under, Clothing.Slots Over) Slots(Clothing item) =>
Normalize(item.SlotsUnder, item.SlotsOver, ClothingResources.IsOuterwear(item));
internal static (Clothing.Slots Under, Clothing.Slots Over) Slots(WardrobeItem item)
{
Enum.TryParse<Clothing.Slots>(item.SlotsUnder, out var under);
Enum.TryParse<Clothing.Slots>(item.SlotsOver, out var over);
return Normalize(under, over, item.Category == "Outerwear");
}
public static bool IsOuterwear(Clothing item) => (Slots(item).Over & UpperBody) != 0;
public static bool CanBeWornWith(Clothing first, Clothing second)
{
if (first is null || second is null) return true;
if (first == second || (first.HasHumanSkin && second.HasHumanSkin)) return false;
var a = Slots(first);
var b = Slots(second);
return (a.Under & b.Under) == 0 && (a.Over & b.Over) == 0;
}
/// <summary>Use the same effective slots when assembling a native clothing container.</summary>
public static void Add(ClothingContainer container, Clothing item)
{
container.Clothing.RemoveAll(entry => !CanBeWornWith(entry.Clothing, item));
container.Clothing.Add(new ClothingContainer.ClothingEntry { Clothing = item });
}
}