Enhance apparel definitions: Introduce 'UpperUnderwear' layer and related items (Bra, SportsBra, SoftBra) to support gender-specific clothing. Update inventory and dress generation logic to accommodate new layers and ensure proper coverage. Adjust localization for new apparel terms and refine tests for underwear functionality.

This commit is contained in:
Leonid Pershin
2026-08-20 07:20:40 +03:00
parent 2af85e1c41
commit 660340c216
24 changed files with 527 additions and 108 deletions
+7 -1
View File
@@ -7,6 +7,7 @@ namespace HSchool.Content;
public static class ApparelLayers
{
public const string Underwear = "Underwear";
public const string UpperUnderwear = "UpperUnderwear";
public const string Socks = "Socks";
public const string Bottom = "Bottom";
public const string Top = "Top";
@@ -17,10 +18,15 @@ public static class ApparelLayers
public const string Accessory = "Accessory";
public static readonly IReadOnlyList<string> All =
[Underwear, Socks, Bottom, Top, OverTop, Outer, Shoes, Head, Accessory];
[Underwear, UpperUnderwear, Socks, Bottom, Top, OverTop, Outer, Shoes, Head, Accessory];
public static bool IsKnown(string layer) =>
All.Any(candidate => candidate.Equals(layer, StringComparison.Ordinal));
public static bool IsUnder(string layer) =>
layer.Equals(Underwear, StringComparison.Ordinal)
|| layer.Equals(UpperUnderwear, StringComparison.Ordinal)
|| layer.Equals(Socks, StringComparison.Ordinal);
}
/// <summary>
+1 -3
View File
@@ -213,7 +213,5 @@ public static class Appropriateness
}
private static bool IsUnderLayer(ThingDef def) =>
def.Layers.All(layer =>
layer.Equals(ApparelLayers.Underwear, StringComparison.Ordinal)
|| layer.Equals(ApparelLayers.Socks, StringComparison.Ordinal));
def.Layers.All(ApparelLayers.IsUnder);
}
+8
View File
@@ -628,6 +628,14 @@ public sealed class CatalogLoader
}
}
foreach (var covered in thing.FullyCoversLayers)
{
if (!ApparelLayers.IsKnown(covered))
{
throw new ContentLoadException($"ThingDef '{thing.DefName}' fullyCoversLayers has unknown layer '{covered}'.");
}
}
var colors = new HashSet<string>(StringComparer.Ordinal);
foreach (var color in thing.Colors)
{
+6
View File
@@ -78,6 +78,12 @@ public sealed class ThingDef : Def
/// <summary>Layers this occupies when worn. Empty — not apparel, so it can sit on the map.</summary>
public IReadOnlyList<string> Layers { get; init; } = [];
/// <summary>
/// Worn layers fully hidden beneath this piece while condition stays above torn.
/// Example: pants list <see cref="ApparelLayers.Underwear"/>.
/// </summary>
public IReadOnlyList<string> FullyCoversLayers { get; init; } = [];
/// <summary>Can live in a bag, locker or at home. Furniture stays false.</summary>
public bool Portable { get; init; }