[Feat] Тонкие спрайты снова в строю (#102)

* Revert "Hair Overhaul (#19298)"

This reverts commit 9491f322de.

# Conflicts:
#	Resources/Textures/Mobs/Customization/human_hair.rsi/a.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/afro.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/afro2.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/bigafro.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/cornrows2.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/emofringe.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/keanu.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/long.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/long2.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/long3.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json
#	Resources/Textures/Mobs/Customization/human_hair.rsi/modern.png
#	Resources/Textures/Mobs/Customization/human_hair.rsi/quiff.png

* add: возврат системы тонкоспрайтов

* fix: небольшие фиксы после реверта причесок

* add: старые текстуры для slim бодитайпа

* fix: фикс причесок после апстрима
This commit is contained in:
Remuchi
2024-02-24 17:06:32 +07:00
committed by GitHub
parent ac2d162c53
commit 3515e87f74
850 changed files with 6170 additions and 675 deletions

View File

@@ -5,12 +5,14 @@ using Content.Shared.Clothing;
using Content.Shared.Clothing.Components; using Content.Shared.Clothing.Components;
using Content.Shared.Clothing.EntitySystems; using Content.Shared.Clothing.EntitySystems;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Inventory; using Content.Shared.Inventory;
using Content.Shared.Inventory.Events; using Content.Shared.Inventory.Events;
using Content.Shared.Item; using Content.Shared.Item;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.ResourceManagement; using Robust.Client.ResourceManagement;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using static Robust.Client.GameObjects.SpriteComponent; using static Robust.Client.GameObjects.SpriteComponent;
@@ -28,30 +30,31 @@ public sealed class ClientClothingSystem : ClothingSystem
/// </summary> /// </summary>
private static readonly Dictionary<string, string> TemporarySlotMap = new() private static readonly Dictionary<string, string> TemporarySlotMap = new()
{ {
{"head", "HELMET"}, { "head", "HELMET" },
{"eyes", "EYES"}, { "eyes", "EYES" },
{"ears", "EARS"}, { "ears", "EARS" },
{"mask", "MASK"}, { "mask", "MASK" },
{"outerClothing", "OUTERCLOTHING"}, { "outerClothing", "OUTERCLOTHING" },
{Jumpsuit, "INNERCLOTHING"}, { Jumpsuit, "INNERCLOTHING" },
{"neck", "NECK"}, { "neck", "NECK" },
{"back", "BACKPACK"}, { "back", "BACKPACK" },
{"belt", "BELT"}, { "belt", "BELT" },
{"gloves", "HAND"}, { "gloves", "HAND" },
{"shoes", "FEET"}, { "shoes", "FEET" },
{"id", "IDCARD"}, { "id", "IDCARD" },
{"pocket1", "POCKET1"}, { "pocket1", "POCKET1" },
{"pocket2", "POCKET2"}, { "pocket2", "POCKET2" },
{"suitstorage", "SUITSTORAGE"}, { "suitstorage", "SUITSTORAGE" },
//WHITE EDIT //WHITE EDIT
{"socks", "SOCKS"}, { "socks", "SOCKS" },
{"underweart", "UNDERWEART"}, { "underweart", "UNDERWEART" },
{"underwearb", "UNDERWEARB"}, { "underwearb", "UNDERWEARB" },
// WHITE EDIT // WHITE EDIT
}; };
[Dependency] private readonly IResourceCache _cache = default!; [Dependency] private readonly IResourceCache _cache = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -99,8 +102,13 @@ public sealed class ClientClothingSystem : ClothingSystem
// if that returned nothing, attempt to find generic data // if that returned nothing, attempt to find generic data
if (layers == null && !item.ClothingVisuals.TryGetValue(args.Slot, out layers)) if (layers == null && !item.ClothingVisuals.TryGetValue(args.Slot, out layers))
{ {
if (!TryComp(args.Equipee, out HumanoidAppearanceComponent? humanoid))
{
return;
}
// No generic data either. Attempt to generate defaults from the item's RSI & item-prefixes // No generic data either. Attempt to generate defaults from the item's RSI & item-prefixes
if (!TryGetDefaultVisuals(uid, item, args.Slot, inventory.SpeciesId, out layers)) if (!TryGetDefaultVisuals(uid, item, args.Slot, inventory.SpeciesId, humanoid, out layers))
return; return;
} }
@@ -126,7 +134,12 @@ public sealed class ClientClothingSystem : ClothingSystem
/// <remarks> /// <remarks>
/// Useful for lazily adding clothing sprites without modifying yaml. And for backwards compatibility. /// Useful for lazily adding clothing sprites without modifying yaml. And for backwards compatibility.
/// </remarks> /// </remarks>
private bool TryGetDefaultVisuals(EntityUid uid, ClothingComponent clothing, string slot, string? speciesId, private bool TryGetDefaultVisuals(
EntityUid uid,
ClothingComponent clothing,
string slot,
string? speciesId,
HumanoidAppearanceComponent humanoid,
[NotNullWhen(true)] out List<PrototypeLayerData>? layers) [NotNullWhen(true)] out List<PrototypeLayerData>? layers)
{ {
layers = null; layers = null;
@@ -138,14 +151,12 @@ public sealed class ClientClothingSystem : ClothingSystem
else if (TryComp(uid, out SpriteComponent? sprite)) else if (TryComp(uid, out SpriteComponent? sprite))
rsi = sprite.BaseRSI; rsi = sprite.BaseRSI;
if (rsi == null || rsi.Path == null) if (rsi?.Path == null)
return false; return false;
var correctedSlot = slot; var correctedSlot = slot;
TemporarySlotMap.TryGetValue(correctedSlot, out correctedSlot); TemporarySlotMap.TryGetValue(correctedSlot, out correctedSlot);
var state = $"equipped-{correctedSlot}"; var state = $"equipped-{correctedSlot}";
if (clothing.EquippedPrefix != null) if (clothing.EquippedPrefix != null)
@@ -154,6 +165,13 @@ public sealed class ClientClothingSystem : ClothingSystem
if (clothing.EquippedState != null) if (clothing.EquippedState != null)
state = $"{clothing.EquippedState}"; state = $"{clothing.EquippedState}";
// body type specific
var bodyTypeProto = _prototypeManager.Index<BodyTypePrototype>(humanoid.BodyType);
if (rsi.TryGetState($"{state}-{bodyTypeProto.Name}", out _))
{
state = $"{state}-{bodyTypeProto.Name}";
}
// species specific // species specific
if (speciesId != null && rsi.TryGetState($"{state}-{speciesId}", out _)) if (speciesId != null && rsi.TryGetState($"{state}-{speciesId}", out _))
{ {
@@ -164,10 +182,13 @@ public sealed class ClientClothingSystem : ClothingSystem
return false; return false;
} }
var layer = new PrototypeLayerData(); var layer = new PrototypeLayerData
layer.RsiPath = rsi.Path.ToString(); {
layer.State = state; RsiPath = rsi.Path.ToString(),
layers = new() { layer }; State = state
};
layers = new List<PrototypeLayerData> { layer };
return true; return true;
} }
@@ -189,7 +210,7 @@ public sealed class ClientClothingSystem : ClothingSystem
&& TryComp(uid, out SpriteComponent? sprite) && TryComp(uid, out SpriteComponent? sprite)
&& sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var maskLayer)) && sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var maskLayer))
{ {
sprite.LayerSetVisible(maskLayer, false); sprite.LayerSetVisible(maskLayer, false);
} }
if (!TryComp(uid, out InventorySlotsComponent? inventorySlots)) if (!TryComp(uid, out InventorySlotsComponent? inventorySlots))
@@ -204,6 +225,7 @@ public sealed class ClientClothingSystem : ClothingSystem
{ {
component.RemoveLayer(layer); component.RemoveLayer(layer);
} }
revealedLayers.Clear(); revealedLayers.Clear();
} }
@@ -226,12 +248,17 @@ public sealed class ClientClothingSystem : ClothingSystem
RenderEquipment(args.Equipee, uid, args.Slot, clothingComponent: component); RenderEquipment(args.Equipee, uid, args.Slot, clothingComponent: component);
} }
private void RenderEquipment(EntityUid equipee, EntityUid equipment, string slot, private void RenderEquipment(
InventoryComponent? inventory = null, SpriteComponent? sprite = null, ClothingComponent? clothingComponent = null, EntityUid equipee,
EntityUid equipment,
string slot,
InventoryComponent? inventory = null,
SpriteComponent? sprite = null,
ClothingComponent? clothingComponent = null,
InventorySlotsComponent? inventorySlots = null) InventorySlotsComponent? inventorySlots = null)
{ {
if (!Resolve(equipee, ref inventory, ref sprite, ref inventorySlots) || if (!Resolve(equipee, ref inventory, ref sprite, ref inventorySlots) ||
!Resolve(equipment, ref clothingComponent, false)) !Resolve(equipment, ref clothingComponent, false))
{ {
return; return;
} }
@@ -250,11 +277,12 @@ public sealed class ClientClothingSystem : ClothingSystem
{ {
sprite.RemoveLayer(key); sprite.RemoveLayer(key);
} }
revealedLayers.Clear(); revealedLayers.Clear();
} }
else else
{ {
revealedLayers = new(); revealedLayers = new HashSet<string>();
inventorySlots.VisualLayerKeys[slot] = revealedLayers; inventorySlots.VisualLayerKeys[slot] = revealedLayers;
} }
@@ -276,7 +304,9 @@ public sealed class ClientClothingSystem : ClothingSystem
{ {
if (!revealedLayers.Add(key)) if (!revealedLayers.Add(key))
{ {
Logger.Warning($"Duplicate key for clothing visuals: {key}. Are multiple components attempting to modify the same layer? Equipment: {ToPrettyString(equipment)}"); Logger.Warning(
$"Duplicate key for clothing visuals: {key}. Are multiple components attempting to modify the same layer? Equipment: {ToPrettyString(equipment)}");
continue; continue;
} }
@@ -315,12 +345,10 @@ public sealed class ClientClothingSystem : ClothingSystem
RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers), true); RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers), true);
} }
/// <summary> /// <summary>
/// Sets a sprite's gendered mask based on gender (obviously). /// Sets a sprite's gendered mask based on gender (obviously).
/// </summary> /// </summary>
/// <param name="sprite">Sprite to modify</param> /// <param name="sprite">Sprite to modify</param>
/// <param name="humanoid">Humanoid, to get gender from</param>
/// <param name="clothing">Clothing component, to get mask sprite type</param> /// <param name="clothing">Clothing component, to get mask sprite type</param>
private void SetGenderedMask(EntityUid uid, SpriteComponent sprite, ClothingComponent clothing) private void SetGenderedMask(EntityUid uid, SpriteComponent sprite, ClothingComponent clothing)
{ {
@@ -330,7 +358,12 @@ public sealed class ClientClothingSystem : ClothingSystem
ClothingMask mask; ClothingMask mask;
string prefix; string prefix;
switch (CompOrNull<HumanoidAppearanceComponent>(uid)?.Sex) if (!TryComp(uid, out HumanoidAppearanceComponent? humanoid))
{
return;
}
switch (humanoid.Sex)
{ {
case Sex.Male: case Sex.Male:
mask = clothing.MaleMask; mask = clothing.MaleMask;
@@ -338,7 +371,8 @@ public sealed class ClientClothingSystem : ClothingSystem
break; break;
case Sex.Female: case Sex.Female:
mask = clothing.FemaleMask; mask = clothing.FemaleMask;
prefix = "female_"; var bodyTypeProto = _prototypeManager.Index<BodyTypePrototype>(humanoid.BodyType!);
prefix = bodyTypeProto.Name != "body-normal" ? $"female_{bodyTypeProto.Name}_" : "female_";
break; break;
default: default:
mask = clothing.UnisexMask; mask = clothing.UnisexMask;
@@ -348,10 +382,11 @@ public sealed class ClientClothingSystem : ClothingSystem
sprite.LayerSetState(layer, mask switch sprite.LayerSetState(layer, mask switch
{ {
ClothingMask.NoMask => $"{prefix}none", ClothingMask.NoMask => $"{prefix}none",
ClothingMask.UniformTop => $"{prefix}top", ClothingMask.UniformTop => $"{prefix}top",
_ => $"{prefix}full", _ => $"{prefix}full",
}); });
sprite.LayerSetVisible(layer, true); sprite.LayerSetVisible(layer, true);
} }
} }

View File

@@ -42,9 +42,8 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
component.BaseLayers.Clear(); component.BaseLayers.Clear();
// add default species layers // add default species layers
var speciesProto = _prototypeManager.Index(component.Species); var bodyTypeProto = _prototypeManager.Index<BodyTypePrototype>(component.BodyType);
var baseSprites = _prototypeManager.Index<HumanoidSpeciesBaseSpritesPrototype>(speciesProto.SpriteSet); foreach (var (key, id) in bodyTypeProto.Sprites)
foreach (var (key, id) in baseSprites.Sprites)
{ {
oldLayers.Remove(key); oldLayers.Remove(key);
if (!component.CustomBaseLayers.ContainsKey(key)) if (!component.CustomBaseLayers.ContainsKey(key))
@@ -108,13 +107,17 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
/// This should not be used if the entity is owned by the server. The server will otherwise /// This should not be used if the entity is owned by the server. The server will otherwise
/// override this with the appearance data it sends over. /// override this with the appearance data it sends over.
/// </remarks> /// </remarks>
public override void LoadProfile(EntityUid uid, HumanoidCharacterProfile profile, HumanoidAppearanceComponent? humanoid = null) public override void LoadProfile(
EntityUid uid,
HumanoidCharacterProfile profile,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid)) if (!Resolve(uid, ref humanoid))
{ {
return; return;
} }
humanoid.BodyType = profile.BodyType;
var customBaseLayers = new Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo>(); var customBaseLayers = new Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo>();
var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(profile.Species); var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(profile.Species);
@@ -142,15 +145,19 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
//markings.RemoveCategory(MarkingCategories.FacialHair); //markings.RemoveCategory(MarkingCategories.FacialHair);
// We need to ensure hair before applying it or coloring can try depend on markings that can be invalid // We need to ensure hair before applying it or coloring can try depend on markings that can be invalid
var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha, _prototypeManager) var hairColor = _markingManager.MustMatchSkin(profile.BodyType, HumanoidVisualLayers.Hair, out var hairAlpha,
_prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(hairAlpha) ? profile.Appearance.SkinColor.WithAlpha(hairAlpha)
: profile.Appearance.HairColor; : profile.Appearance.HairColor;
var hair = new Marking(profile.Appearance.HairStyleId, var hair = new Marking(profile.Appearance.HairStyleId,
new[] { hairColor }); new[] { hairColor });
var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, out var facialHairAlpha, _prototypeManager) var facialHairColor = _markingManager.MustMatchSkin(profile.BodyType, HumanoidVisualLayers.FacialHair,
out var facialHairAlpha, _prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) ? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha)
: profile.Appearance.FacialHairColor; : profile.Appearance.FacialHairColor;
var facialHair = new Marking(profile.Appearance.FacialHairStyleId, var facialHair = new Marking(profile.Appearance.FacialHairStyleId,
new[] { facialHairColor }); new[] { facialHairColor });
@@ -158,6 +165,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
{ {
markings.AddBack(MarkingCategories.Hair, hair); markings.AddBack(MarkingCategories.Hair, hair);
} }
if (_markingManager.CanBeApplied(profile.Species, profile.Sex, facialHair, _prototypeManager)) if (_markingManager.CanBeApplied(profile.Species, profile.Sex, facialHair, _prototypeManager))
{ {
markings.AddBack(MarkingCategories.FacialHair, facialHair); markings.AddBack(MarkingCategories.FacialHair, facialHair);
@@ -172,10 +180,13 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
profile.Appearance.EyeColor, profile.Appearance.EyeColor,
markings markings
); );
markings.AddBack(prototype.MarkingCategory, new Marking(marking.MarkingId, markingColors)); markings.AddBack(prototype.MarkingCategory, new Marking(marking.MarkingId, markingColors));
} }
markings.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager); markings.EnsureSpecies(profile.Species, profile.BodyType, profile.Appearance.SkinColor, _markingManager,
_prototypeManager);
markings.EnsureSexes(profile.Sex, _markingManager); markings.EnsureSexes(profile.Sex, _markingManager);
markings.EnsureDefault( markings.EnsureDefault(
profile.Appearance.SkinColor, profile.Appearance.SkinColor,
@@ -190,6 +201,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
humanoid.CustomBaseLayers = customBaseLayers; humanoid.CustomBaseLayers = customBaseLayers;
humanoid.Sex = profile.Sex; humanoid.Sex = profile.Sex;
humanoid.Gender = profile.Gender; humanoid.Gender = profile.Gender;
humanoid.BodyType = profile.BodyType;
humanoid.Age = profile.Age; humanoid.Age = profile.Age;
humanoid.Species = profile.Species; humanoid.Species = profile.Species;
humanoid.SkinColor = profile.Appearance.SkinColor; humanoid.SkinColor = profile.Appearance.SkinColor;
@@ -261,7 +273,9 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
spriteComp.RemoveLayer(index); spriteComp.RemoveLayer(index);
} }
} }
private void ApplyMarking(MarkingPrototype markingPrototype,
private void ApplyMarking(
MarkingPrototype markingPrototype,
IReadOnlyList<Color>? colors, IReadOnlyList<Color>? colors,
bool visible, bool visible,
HumanoidAppearanceComponent humanoid, HumanoidAppearanceComponent humanoid,
@@ -274,7 +288,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
visible &= !IsHidden(humanoid, markingPrototype.BodyPart); visible &= !IsHidden(humanoid, markingPrototype.BodyPart);
visible &= humanoid.BaseLayers.TryGetValue(markingPrototype.BodyPart, out var setting) visible &= humanoid.BaseLayers.TryGetValue(markingPrototype.BodyPart, out var setting)
&& setting.AllowsMarkings; && setting.AllowsMarkings;
for (var j = 0; j < markingPrototype.Sprites.Count; j++) for (var j = 0; j < markingPrototype.Sprites.Count; j++)
{ {
@@ -315,7 +329,12 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
} }
} }
public override void SetSkinColor(EntityUid uid, Color skinColor, bool sync = true, bool verify = true, HumanoidAppearanceComponent? humanoid = null) public override void SetSkinColor(
EntityUid uid,
Color skinColor,
bool sync = true,
bool verify = true,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid) || humanoid.SkinColor == skinColor) if (!Resolve(uid, ref humanoid) || humanoid.SkinColor == skinColor)
return; return;
@@ -366,7 +385,8 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
{ {
foreach (var marking in markingList) foreach (var marking in markingList)
{ {
if (_markingManager.TryGetMarking(marking, out var markingPrototype) && markingPrototype.BodyPart == layer) if (_markingManager.TryGetMarking(marking, out var markingPrototype) &&
markingPrototype.BodyPart == layer)
ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite); ApplyMarking(markingPrototype, marking.MarkingColors, marking.Visible, humanoid, sprite);
} }
} }

View File

@@ -40,7 +40,7 @@ public sealed class HumanoidMarkingModifierBoundUserInterface : BoundUserInterfa
return; return;
} }
_window.SetState(cast.MarkingSet, cast.Species, cast.Sex, cast.SkinColor, cast.CustomBaseLayers); _window.SetState(cast.MarkingSet, cast.Species, cast.Sex, cast.BodyType, cast.SkinColor, cast.CustomBaseLayers);
} }
private void SendMarkingSet(MarkingSet set) private void SendMarkingSet(MarkingSet set)

View File

@@ -59,10 +59,12 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
string? state = _protoMan.HasIndex<HumanoidSpeciesSpriteLayer>(modifier.Text) ? modifier.Text : null; string? state = _protoMan.HasIndex<HumanoidSpeciesSpriteLayer>(modifier.Text) ? modifier.Text : null;
OnLayerInfoModified?.Invoke(layer, new CustomBaseLayerInfo(state, modifier.Color)); OnLayerInfoModified?.Invoke(layer, new CustomBaseLayerInfo(state, modifier.Color));
} }
public void SetState( public void SetState(
MarkingSet markings, MarkingSet markings,
string species, string species,
Sex sex, Sex sex,
string bodyType,
Color skinColor, Color skinColor,
Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> info Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> info
) )
@@ -84,7 +86,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
eyesColor = eyes.Color.Value; eyesColor = eyes.Color.Value;
} }
MarkingPickerWidget.SetData(markings, species, sex, skinColor, eyesColor); MarkingPickerWidget.SetData(markings, species, sex, bodyType, skinColor, eyesColor);
} }
private sealed class HumanoidBaseLayerModifier : BoxContainer private sealed class HumanoidBaseLayerModifier : BoxContainer
@@ -95,7 +97,9 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
private BoxContainer _infoBox; private BoxContainer _infoBox;
public bool Enabled => _enable.Pressed; public bool Enabled => _enable.Pressed;
public string Text => _lineEdit.Text; public string Text => _lineEdit.Text;
public Color Color => _colorSliders.Color; public Color Color => _colorSliders.Color;
public Action? OnStateChanged; public Action? OnStateChanged;
@@ -109,6 +113,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
MinWidth = 250, MinWidth = 250,
HorizontalExpand = true HorizontalExpand = true
}; };
AddChild(labelBox); AddChild(labelBox);
labelBox.AddChild(new Label labelBox.AddChild(new Label
@@ -116,6 +121,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
HorizontalExpand = true, HorizontalExpand = true,
Text = layer.ToString() Text = layer.ToString()
}); });
_enable = new CheckBox _enable = new CheckBox
{ {
Text = "Enable", Text = "Enable",
@@ -128,6 +134,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
Orientation = LayoutOrientation.Vertical, Orientation = LayoutOrientation.Vertical,
Visible = false Visible = false
}; };
_enable.OnToggled += args => _enable.OnToggled += args =>
{ {
_infoBox.Visible = args.Pressed; _infoBox.Visible = args.Pressed;
@@ -135,7 +142,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
}; };
var lineEditBox = new BoxContainer(); var lineEditBox = new BoxContainer();
lineEditBox.AddChild(new Label { Text = "Prototype id: "}); lineEditBox.AddChild(new Label { Text = "Prototype id: " });
// TODO: This line edit should really be an options / dropdown selector, not text. // TODO: This line edit should really be an options / dropdown selector, not text.
_lineEdit = new() { MinWidth = 200 }; _lineEdit = new() { MinWidth = 200 };

View File

@@ -40,6 +40,7 @@ public sealed partial class MarkingPicker : Control
private List<MarkingCategories> _markingCategories = Enum.GetValues<MarkingCategories>().ToList(); private List<MarkingCategories> _markingCategories = Enum.GetValues<MarkingCategories>().ToList();
private string _currentSpecies = SharedHumanoidAppearanceSystem.DefaultSpecies; private string _currentSpecies = SharedHumanoidAppearanceSystem.DefaultSpecies;
private string _currentBodyType = SharedHumanoidAppearanceSystem.DefaultBodyType;
private Sex _currentSex = Sex.Unsexed; private Sex _currentSex = Sex.Unsexed;
public Color CurrentSkinColor = Color.White; public Color CurrentSkinColor = Color.White;
public Color CurrentEyeColor = Color.Black; public Color CurrentEyeColor = Color.Black;
@@ -83,7 +84,7 @@ public sealed partial class MarkingPicker : Control
} }
} }
public void SetData(List<Marking> newMarkings, string species, Sex sex, Color skinColor, Color eyeColor) public void SetData(List<Marking> newMarkings, string species, Sex sex, string bodyType, Color skinColor, Color eyeColor)
{ {
var pointsProto = _prototypeManager var pointsProto = _prototypeManager
.Index<SpeciesPrototype>(species).MarkingPoints; .Index<SpeciesPrototype>(species).MarkingPoints;
@@ -91,7 +92,7 @@ public sealed partial class MarkingPicker : Control
if (!IgnoreSpecies) if (!IgnoreSpecies)
{ {
_currentMarkings.EnsureSpecies(species, skinColor, _markingManager); // should be validated server-side but it can't hurt _currentMarkings.EnsureSpecies(species, bodyType, skinColor, _markingManager); // should be validated server-side but it can't hurt
} }
_currentSpecies = species; _currentSpecies = species;
@@ -103,13 +104,13 @@ public sealed partial class MarkingPicker : Control
PopulateUsed(); PopulateUsed();
} }
public void SetData(MarkingSet set, string species, Sex sex, Color skinColor, Color eyeColor) public void SetData(MarkingSet set, string species, Sex sex, string bodyType, Color skinColor, Color eyeColor)
{ {
_currentMarkings = set; _currentMarkings = set;
if (!IgnoreSpecies) if (!IgnoreSpecies)
{ {
_currentMarkings.EnsureSpecies(species, skinColor, _markingManager); // should be validated server-side but it can't hurt _currentMarkings.EnsureSpecies(species, bodyType, skinColor, _markingManager); // should be validated server-side but it can't hurt
} }
_currentSpecies = species; _currentSpecies = species;
@@ -234,7 +235,7 @@ public sealed partial class MarkingPicker : Control
if (!IgnoreSpecies) if (!IgnoreSpecies)
{ {
_currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager); _currentMarkings.EnsureSpecies(_currentSpecies, _currentBodyType, null, _markingManager);
} }
// walk backwards through the list for visual purposes // walk backwards through the list for visual purposes
@@ -338,7 +339,7 @@ public sealed partial class MarkingPicker : Control
var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(species); var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(species);
_currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager); _currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager);
_currentMarkings.EnsureSpecies(species, null, _markingManager); _currentMarkings.EnsureSpecies(species, _currentBodyType, null, _markingManager);
_currentMarkings.EnsureSexes(_currentSex, _markingManager); _currentMarkings.EnsureSexes(_currentSex, _markingManager);
Populate(CMarkingSearch.Text); Populate(CMarkingSearch.Text);
@@ -353,7 +354,7 @@ public sealed partial class MarkingPicker : Control
var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(_currentSpecies); var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(_currentSpecies);
_currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager); _currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager);
_currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager); _currentMarkings.EnsureSpecies(_currentSpecies, _currentBodyType, null, _markingManager);
_currentMarkings.EnsureSexes(_currentSex, _markingManager); _currentMarkings.EnsureSexes(_currentSex, _markingManager);
Populate(CMarkingSearch.Text); Populate(CMarkingSearch.Text);

View File

@@ -75,6 +75,12 @@
<Control HorizontalExpand="True"/> <Control HorizontalExpand="True"/>
<OptionButton Name="CSpeciesButton" HorizontalAlignment="Right" /> <OptionButton Name="CSpeciesButton" HorizontalAlignment="Right" />
</BoxContainer> </BoxContainer>
<!-- Body Type -->
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'humanoid-profile-editor-body-type-label'}"/>
<Control HorizontalExpand="True"/>
<OptionButton Name="CBodyTypesButton" HorizontalAlignment="Right" />
</BoxContainer>
<!-- Age --> <!-- Age -->
<BoxContainer HorizontalExpand="True"> <BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-age-label'}" /> <Label Text="{Loc 'humanoid-profile-editor-age-label'}" />

View File

@@ -14,13 +14,11 @@ using Content.Shared.GameTicking;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes; using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Inventory;
using Content.Shared.Preferences; using Content.Shared.Preferences;
using Content.Shared.Roles; using Content.Shared.Roles;
using Content.Shared.StatusIcon; using Content.Shared.StatusIcon;
using Content.Shared.Traits; using Content.Shared.Traits;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
@@ -29,10 +27,8 @@ using Robust.Client.UserInterface.XAML;
using Robust.Client.Utility; using Robust.Client.Utility;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.Log;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing; using Robust.Shared.Timing;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using static Robust.Client.UserInterface.Controls.BoxContainer; using static Robust.Client.UserInterface.Controls.BoxContainer;
@@ -44,7 +40,7 @@ namespace Content.Client.Preferences.UI
{ {
public HighlightedContainer() public HighlightedContainer()
{ {
PanelOverride = new StyleBoxFlat() PanelOverride = new StyleBoxFlat
{ {
BackgroundColor = new Color(25, 25, 25), BackgroundColor = new Color(25, 25, 25),
ContentMarginTopOverride = 10, ContentMarginTopOverride = 10,
@@ -110,6 +106,7 @@ namespace Content.Client.Preferences.UI
private readonly List<SpeciesPrototype> _speciesList; private readonly List<SpeciesPrototype> _speciesList;
private readonly List<AntagPreferenceSelector> _antagPreferences; private readonly List<AntagPreferenceSelector> _antagPreferences;
private readonly List<TraitPreferenceSelector> _traitPreferences; private readonly List<TraitPreferenceSelector> _traitPreferences;
private List<BodyTypePrototype> _bodyTypesList = new();
private SpriteView _previewSpriteView => CSpriteView; private SpriteView _previewSpriteView => CSpriteView;
private Button _previewRotateLeftButton => CSpriteRotateLeft; private Button _previewRotateLeftButton => CSpriteRotateLeft;
@@ -177,6 +174,14 @@ namespace Content.Client.Preferences.UI
#endregion Sex #endregion Sex
#region Body Type
CBodyTypesButton.OnItemSelected += OnBodyTypeSelected;
UpdateBodyTypes();
#endregion Body Type
#region Age #region Age
_ageEdit.OnTextChanged += args => _ageEdit.OnTextChanged += args =>
@@ -845,6 +850,7 @@ namespace Content.Client.Preferences.UI
CMarkings.SetSpecies(newSpecies); // Repopulate the markings tab as well. CMarkings.SetSpecies(newSpecies); // Repopulate the markings tab as well.
UpdateSexControls(); // update sex for new species UpdateSexControls(); // update sex for new species
RebuildSpriteView(); // they might have different inv so we need a new dummy RebuildSpriteView(); // they might have different inv so we need a new dummy
UpdateBodyTypes();
IsDirty = true; IsDirty = true;
_needUpdatePreview = true; _needUpdatePreview = true;
} }
@@ -903,6 +909,38 @@ namespace Content.Client.Preferences.UI
} }
} }
private void OnBodyTypeSelected(OptionButton.ItemSelectedEventArgs args)
{
args.Button.SelectId(args.Id);
SetBodyType(_bodyTypesList[args.Id].ID);
}
private void UpdateBodyTypes()
{
if (Profile is null)
return;
CBodyTypesButton.Clear();
var species = _prototypeManager.Index<SpeciesPrototype>(Profile.Species);
var sex = Profile.Sex;
_bodyTypesList = EntitySystem.Get<HumanoidAppearanceSystem>().GetValidBodyTypes(species, sex);
for (var i = 0; i < _bodyTypesList.Count; i++)
{
CBodyTypesButton.AddItem(Loc.GetString(_bodyTypesList[i].Name), i);
}
// If current body type is not valid.
if (!_bodyTypesList.Select(proto => proto.ID).Contains(Profile.BodyType))
{
// Then replace it with a first valid body type.
SetBodyType(_bodyTypesList.First().ID);
}
CBodyTypesButton.Select(_bodyTypesList.FindIndex(x => x.ID == Profile.BodyType));
IsDirty = true;
}
private bool IsDirty private bool IsDirty
{ {
get => _isDirty; get => _isDirty;
@@ -1025,7 +1063,7 @@ namespace Content.Client.Preferences.UI
} }
CMarkings.SetData(Profile.Appearance.Markings, Profile.Species, CMarkings.SetData(Profile.Appearance.Markings, Profile.Species,
Profile.Sex, Profile.Appearance.SkinColor, Profile.Appearance.EyeColor Profile.Sex, Profile.BodyType, Profile.Appearance.SkinColor, Profile.Appearance.EyeColor
); );
} }
@@ -1090,13 +1128,13 @@ namespace Content.Client.Preferences.UI
var hairMarking = Profile.Appearance.HairStyleId switch var hairMarking = Profile.Appearance.HairStyleId switch
{ {
HairStyles.DefaultHairStyle => new List<Marking>(), HairStyles.DefaultHairStyle => new List<Marking>(),
_ => new() { new(Profile.Appearance.HairStyleId, new List<Color>() { Profile.Appearance.HairColor }) }, _ => new() { new(Profile.Appearance.HairStyleId, new List<Color> { Profile.Appearance.HairColor }) },
}; };
var facialHairMarking = Profile.Appearance.FacialHairStyleId switch var facialHairMarking = Profile.Appearance.FacialHairStyleId switch
{ {
HairStyles.DefaultFacialHairStyle => new List<Marking>(), HairStyles.DefaultFacialHairStyle => new List<Marking>(),
_ => new() { new(Profile.Appearance.FacialHairStyleId, new List<Color>() { Profile.Appearance.FacialHairColor }) }, _ => new() { new(Profile.Appearance.FacialHairStyleId, new List<Color> { Profile.Appearance.FacialHairColor }) },
}; };
_hairPicker.UpdateData( _hairPicker.UpdateData(
@@ -1124,7 +1162,7 @@ namespace Content.Client.Preferences.UI
{ {
if (_markingManager.CanBeApplied(Profile.Species, Profile.Sex, hairProto, _prototypeManager)) if (_markingManager.CanBeApplied(Profile.Species, Profile.Sex, hairProto, _prototypeManager))
{ {
if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, out var _, _prototypeManager)) if (_markingManager.MustMatchSkin(Profile.BodyType, HumanoidVisualLayers.Hair, out _, _prototypeManager))
{ {
hairColor = Profile.Appearance.SkinColor; hairColor = Profile.Appearance.SkinColor;
} }
@@ -1136,7 +1174,7 @@ namespace Content.Client.Preferences.UI
} }
if (hairColor != null) if (hairColor != null)
{ {
CMarkings.HairMarking = new (Profile.Appearance.HairStyleId, new List<Color>() { hairColor.Value }); CMarkings.HairMarking = new (Profile.Appearance.HairStyleId, new List<Color> { hairColor.Value });
} }
else else
{ {
@@ -1159,7 +1197,7 @@ namespace Content.Client.Preferences.UI
{ {
if (_markingManager.CanBeApplied(Profile.Species, Profile.Sex, facialHairProto, _prototypeManager)) if (_markingManager.CanBeApplied(Profile.Species, Profile.Sex, facialHairProto, _prototypeManager))
{ {
if (_markingManager.MustMatchSkin(Profile.Species, HumanoidVisualLayers.Hair, out var _, _prototypeManager)) if (_markingManager.MustMatchSkin(Profile.BodyType, HumanoidVisualLayers.Hair, out _, _prototypeManager))
{ {
facialHairColor = Profile.Appearance.SkinColor; facialHairColor = Profile.Appearance.SkinColor;
} }
@@ -1171,7 +1209,7 @@ namespace Content.Client.Preferences.UI
} }
if (facialHairColor != null) if (facialHairColor != null)
{ {
CMarkings.FacialHairMarking = new (Profile.Appearance.FacialHairStyleId, new List<Color>() { facialHairColor.Value }); CMarkings.FacialHairMarking = new (Profile.Appearance.FacialHairStyleId, new List<Color> { facialHairColor.Value });
} }
else else
{ {
@@ -1237,6 +1275,7 @@ namespace Content.Client.Preferences.UI
//WD-EDIT //WD-EDIT
UpdateTTSVoicesControls(); UpdateTTSVoicesControls();
UpdateBodyTypes();
//WD-EDIT //WD-EDIT
_preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable); _preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable);
@@ -1299,6 +1338,14 @@ namespace Content.Client.Preferences.UI
return allowedSpecies; return allowedSpecies;
} }
private void SetBodyType(string newBodyType)
{
Profile = Profile?.WithBodyType(newBodyType);
IsDirty = true;
_needUpdatePreview = true;
}
//WD EDIT END //WD EDIT END
private void UpdateJobPriorities() private void UpdateJobPriorities()
@@ -1337,7 +1384,7 @@ namespace Content.Client.Preferences.UI
Options.OnItemSelected += args => Options.Select(args.Id); Options.OnItemSelected += args => Options.Select(args.Id);
_requirementsLabel = new Label() _requirementsLabel = new Label
{ {
Text = Loc.GetString("role-timer-locked"), Text = Loc.GetString("role-timer-locked"),
Visible = true, Visible = true,
@@ -1345,7 +1392,7 @@ namespace Content.Client.Preferences.UI
StyleClasses = {StyleBase.StyleClassLabelSubText}, StyleClasses = {StyleBase.StyleClassLabelSubText},
}; };
_lockStripe = new StripeBack() _lockStripe = new StripeBack
{ {
Visible = false, Visible = false,
HorizontalExpand = true, HorizontalExpand = true,
@@ -1369,7 +1416,7 @@ namespace Content.Client.Preferences.UI
Options.AddItem(Loc.GetString(text), value); Options.AddItem(Loc.GetString(text), value);
} }
var titleLabel = new Label() var titleLabel = new Label
{ {
Margin = new Thickness(5f, 0, 5f, 0), Margin = new Thickness(5f, 0, 5f, 0),
Text = title, Text = title,

View File

@@ -11,7 +11,6 @@ using Robust.Shared.Enums;
using Robust.Shared.Log; using Robust.Shared.Log;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.UnitTesting; using Robust.UnitTesting;
namespace Content.IntegrationTests.Tests.Preferences namespace Content.IntegrationTests.Tests.Preferences
@@ -49,6 +48,7 @@ namespace Content.IntegrationTests.Tests.Preferences
21, 21,
Sex.Male, Sex.Male,
Gender.Epicene, Gender.Epicene,
"Normal",
new HumanoidCharacterAppearance( new HumanoidCharacterAppearance(
"Afro", "Afro",
Color.Aqua, Color.Aqua,

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Postgres
{
/// <inheritdoc />
public partial class AddBodyType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "body_type",
table: "profile",
type: "text",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "body_type",
table: "profile");
}
}
}

View File

@@ -760,6 +760,11 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("text") .HasColumnType("text")
.HasColumnName("backpack"); .HasColumnName("backpack");
b.Property<string>("BodyType")
.IsRequired()
.HasColumnType("text")
.HasColumnName("body_type");
b.Property<string>("BorgName") b.Property<string>("BorgName")
.IsRequired() .IsRequired()
.HasColumnType("text") .HasColumnType("text")

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Sqlite
{
/// <inheritdoc />
public partial class AddBodyType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "body_type",
table: "profile",
type: "TEXT",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "body_type",
table: "profile");
}
}
}

View File

@@ -711,6 +711,11 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("TEXT") .HasColumnType("TEXT")
.HasColumnName("backpack"); .HasColumnName("backpack");
b.Property<string>("BodyType")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("body_type");
b.Property<string>("BorgName") b.Property<string>("BorgName")
.IsRequired() .IsRequired()
.HasColumnType("TEXT") .HasColumnType("TEXT")

View File

@@ -343,6 +343,7 @@ namespace Content.Server.Database
public string Gender { get; set; } = null!; public string Gender { get; set; } = null!;
//WD-EDIT //WD-EDIT
public string BodyType { get; set; } = null!;
public string Voice { get; set; } = null!; public string Voice { get; set; } = null!;
//WD-EDIT //WD-EDIT

View File

@@ -180,6 +180,7 @@ namespace Content.Server.Database
if (Enum.TryParse<Sex>(profile.Sex, true, out var sexVal)) if (Enum.TryParse<Sex>(profile.Sex, true, out var sexVal))
sex = sexVal; sex = sexVal;
var bodyType = profile.BodyType;
var clothing = ClothingPreference.Jumpsuit; var clothing = ClothingPreference.Jumpsuit;
if (Enum.TryParse<ClothingPreference>(profile.Clothing, true, out var clothingVal)) if (Enum.TryParse<ClothingPreference>(profile.Clothing, true, out var clothingVal))
clothing = clothingVal; clothing = clothingVal;
@@ -225,6 +226,7 @@ namespace Content.Server.Database
profile.Age, profile.Age,
sex, sex,
gender, gender,
bodyType,
new HumanoidCharacterAppearance new HumanoidCharacterAppearance
( (
profile.HairName, profile.HairName,
@@ -265,6 +267,7 @@ namespace Content.Server.Database
profile.Age = humanoid.Age; profile.Age = humanoid.Age;
profile.Sex = humanoid.Sex.ToString(); profile.Sex = humanoid.Sex.ToString();
profile.Gender = humanoid.Gender.ToString(); profile.Gender = humanoid.Gender.ToString();
profile.BodyType = humanoid.BodyType;
profile.HairName = appearance.HairStyleId; profile.HairName = appearance.HairStyleId;
profile.HairColor = appearance.HairColor.ToHex(); profile.HairColor = appearance.HairColor.ToHex();
profile.FacialHairName = appearance.FacialHairStyleId; profile.FacialHairName = appearance.FacialHairStyleId;

View File

@@ -29,7 +29,7 @@ public sealed partial class HumanoidAppearanceSystem
{ {
Text = "Modify markings", Text = "Modify markings",
Category = VerbCategory.Tricks, Category = VerbCategory.Tricks,
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Customization/reptilian_parts.rsi"), "tail_smooth"), Icon = new SpriteSpecifier.Rsi(new("/Textures/Mobs/Customization/reptilian_parts.rsi"), "tail_smooth"),
Act = () => Act = () =>
{ {
_uiSystem.TryOpen(uid, HumanoidMarkingModifierKey.Key, actor.PlayerSession); _uiSystem.TryOpen(uid, HumanoidMarkingModifierKey.Key, actor.PlayerSession);
@@ -37,6 +37,7 @@ public sealed partial class HumanoidAppearanceSystem
uid, uid,
HumanoidMarkingModifierKey.Key, HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species, new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.BodyType,
component.Sex, component.Sex,
component.SkinColor, component.SkinColor,
component.CustomBaseLayers component.CustomBaseLayers
@@ -45,7 +46,9 @@ public sealed partial class HumanoidAppearanceSystem
}); });
} }
private void OnBaseLayersSet(EntityUid uid, HumanoidAppearanceComponent component, private void OnBaseLayersSet(
EntityUid uid,
HumanoidAppearanceComponent component,
HumanoidMarkingModifierBaseLayersSetMessage message) HumanoidMarkingModifierBaseLayersSetMessage message)
{ {
if (message.Session is not { } player if (message.Session is not { } player
@@ -63,7 +66,7 @@ public sealed partial class HumanoidAppearanceSystem
component.CustomBaseLayers[message.Layer] = message.Info.Value; component.CustomBaseLayers[message.Layer] = message.Info.Value;
} }
Dirty(component); Dirty(uid, component);
if (message.ResendState) if (message.ResendState)
{ {
@@ -71,14 +74,17 @@ public sealed partial class HumanoidAppearanceSystem
uid, uid,
HumanoidMarkingModifierKey.Key, HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species, new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.Sex, component.BodyType,
component.SkinColor, component.Sex,
component.CustomBaseLayers component.SkinColor,
)); component.CustomBaseLayers
));
} }
} }
private void OnMarkingsSet(EntityUid uid, HumanoidAppearanceComponent component, private void OnMarkingsSet(
EntityUid uid,
HumanoidAppearanceComponent component,
HumanoidMarkingModifierMarkingSetMessage message) HumanoidMarkingModifierMarkingSetMessage message)
{ {
if (message.Session is not { } player if (message.Session is not { } player
@@ -88,7 +94,7 @@ public sealed partial class HumanoidAppearanceSystem
} }
component.MarkingSet = message.MarkingSet; component.MarkingSet = message.MarkingSet;
Dirty(component); Dirty(uid, component);
if (message.ResendState) if (message.ResendState)
{ {
@@ -96,11 +102,11 @@ public sealed partial class HumanoidAppearanceSystem
uid, uid,
HumanoidMarkingModifierKey.Key, HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species, new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.Sex, component.BodyType,
component.SkinColor, component.Sex,
component.CustomBaseLayers component.SkinColor,
)); component.CustomBaseLayers
));
} }
} }
} }

View File

@@ -1,4 +1,3 @@
using System.Linq;
using Content.Shared.Examine; using Content.Shared.Examine;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Markings;
@@ -27,11 +26,12 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
private void OnExamined(EntityUid uid, HumanoidAppearanceComponent component, ExaminedEvent args) private void OnExamined(EntityUid uid, HumanoidAppearanceComponent component, ExaminedEvent args)
{ {
var identity = Identity.Entity(component.Owner, EntityManager); var identity = Identity.Entity(uid, EntityManager);
var species = GetSpeciesRepresentation(component.Species).ToLower(); var species = GetSpeciesRepresentation(component.Species).ToLower();
var age = GetAgeRepresentation(component.Species, component.Age); var age = GetAgeRepresentation(component.Species, component.Age);
args.PushText(Loc.GetString("humanoid-appearance-component-examine", ("user", identity), ("age", age), ("species", species))); args.PushText(Loc.GetString("humanoid-appearance-component-examine", ("user", identity), ("age", age),
("species", species)));
} }
/// <summary> /// <summary>
@@ -40,7 +40,10 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="uid">The mob's entity UID.</param> /// <param name="uid">The mob's entity UID.</param>
/// <param name="profile">The character profile to load.</param> /// <param name="profile">The character profile to load.</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void LoadProfile(EntityUid uid, HumanoidCharacterProfile profile, HumanoidAppearanceComponent? humanoid = null) public void LoadProfile(
EntityUid uid,
HumanoidCharacterProfile profile,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid)) if (!Resolve(uid, ref humanoid))
{ {
@@ -51,6 +54,8 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
SetSex(uid, profile.Sex, false, humanoid); SetSex(uid, profile.Sex, false, humanoid);
humanoid.EyeColor = profile.Appearance.EyeColor; humanoid.EyeColor = profile.Appearance.EyeColor;
SetBodyType(uid, profile.BodyType, false, humanoid);
SetSkinColor(uid, profile.Appearance.SkinColor, false); SetSkinColor(uid, profile.Appearance.SkinColor, false);
humanoid.MarkingSet.Clear(); humanoid.MarkingSet.Clear();
@@ -74,10 +79,15 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
// Hair/facial hair - this may eventually be deprecated. // Hair/facial hair - this may eventually be deprecated.
// We need to ensure hair before applying it or coloring can try depend on markings that can be invalid // We need to ensure hair before applying it or coloring can try depend on markings that can be invalid
var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha, _prototypeManager) var hairColor = _markingManager.MustMatchSkin(profile.BodyType, HumanoidVisualLayers.Hair, out var hairAlpha,
? profile.Appearance.SkinColor.WithAlpha(hairAlpha) : profile.Appearance.HairColor; _prototypeManager)
var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, out var facialHairAlpha, _prototypeManager) ? profile.Appearance.SkinColor.WithAlpha(hairAlpha)
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor; : profile.Appearance.HairColor;
var facialHairColor = _markingManager.MustMatchSkin(profile.BodyType, HumanoidVisualLayers.FacialHair,
out var facialHairAlpha, _prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha)
: profile.Appearance.FacialHairColor;
if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) && if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) &&
_markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _prototypeManager)) _markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _prototypeManager))
@@ -86,12 +96,14 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
} }
if (_markingManager.Markings.TryGetValue(profile.Appearance.FacialHairStyleId, out var facialHairPrototype) && if (_markingManager.Markings.TryGetValue(profile.Appearance.FacialHairStyleId, out var facialHairPrototype) &&
_markingManager.CanBeApplied(profile.Species,profile.Sex, facialHairPrototype, _prototypeManager)) _markingManager.CanBeApplied(profile.Species, profile.Sex, facialHairPrototype, _prototypeManager))
{ {
AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false); AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false);
} }
humanoid.MarkingSet.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager); humanoid.MarkingSet.EnsureSpecies(profile.Species, profile.BodyType, profile.Appearance.SkinColor,
_markingManager,
_prototypeManager);
// Finally adding marking with forced colors // Finally adding marking with forced colors
foreach (var (marking, prototype) in markingFColored) foreach (var (marking, prototype) in markingFColored)
@@ -102,6 +114,7 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
profile.Appearance.EyeColor, profile.Appearance.EyeColor,
humanoid.MarkingSet humanoid.MarkingSet
); );
AddMarking(uid, marking.MarkingId, markingColors, false); AddMarking(uid, marking.MarkingId, markingColors, false);
} }
@@ -128,7 +141,10 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="target">Target entity to apply the source entity's appearance to.</param> /// <param name="target">Target entity to apply the source entity's appearance to.</param>
/// <param name="sourceHumanoid">Source entity's humanoid component.</param> /// <param name="sourceHumanoid">Source entity's humanoid component.</param>
/// <param name="targetHumanoid">Target entity's humanoid component.</param> /// <param name="targetHumanoid">Target entity's humanoid component.</param>
public void CloneAppearance(EntityUid source, EntityUid target, HumanoidAppearanceComponent? sourceHumanoid = null, public void CloneAppearance(
EntityUid source,
EntityUid target,
HumanoidAppearanceComponent? sourceHumanoid = null,
HumanoidAppearanceComponent? targetHumanoid = null) HumanoidAppearanceComponent? targetHumanoid = null)
{ {
if (!Resolve(source, ref sourceHumanoid) || !Resolve(target, ref targetHumanoid)) if (!Resolve(source, ref sourceHumanoid) || !Resolve(target, ref targetHumanoid))
@@ -143,6 +159,8 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
SetSex(target, sourceHumanoid.Sex, false, targetHumanoid); SetSex(target, sourceHumanoid.Sex, false, targetHumanoid);
targetHumanoid.CustomBaseLayers = new(sourceHumanoid.CustomBaseLayers); targetHumanoid.CustomBaseLayers = new(sourceHumanoid.CustomBaseLayers);
targetHumanoid.MarkingSet = new(sourceHumanoid.MarkingSet); targetHumanoid.MarkingSet = new(sourceHumanoid.MarkingSet);
targetHumanoid.BodyType = sourceHumanoid.BodyType;
SetTTSVoice(target, sourceHumanoid.Voice, targetHumanoid);
targetHumanoid.Gender = sourceHumanoid.Gender; targetHumanoid.Gender = sourceHumanoid.Gender;
if (TryComp<GrammarComponent>(target, out var grammar)) if (TryComp<GrammarComponent>(target, out var grammar))
@@ -153,6 +171,32 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
Dirty(targetHumanoid); Dirty(targetHumanoid);
} }
/// <summary>
/// Set a humanoid mob's body yupe. This will change their base sprites.
/// </summary>
/// <param name="uid">The humanoid mob's UID.</param>
/// <param name="bodyType">The body type to set the mob to. Will return if the body type prototype was invalid.</param>
/// <param name="sync">Whether to immediately synchronize this to the humanoid mob, or not.</param>
/// <param name="humanoid">Humanoid component of the entity</param>
public void SetBodyType(
EntityUid uid,
string bodyType,
bool sync = true,
HumanoidAppearanceComponent? humanoid = null)
{
if (!Resolve(uid, ref humanoid) || !_prototypeManager.TryIndex<BodyTypePrototype>(bodyType, out _))
{
return;
}
humanoid.BodyType = bodyType;
if (sync)
{
Dirty(uid, humanoid);
}
}
/// <summary> /// <summary>
/// Adds a marking to this humanoid. /// Adds a marking to this humanoid.
/// </summary> /// </summary>
@@ -162,7 +206,13 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="sync">Whether to immediately sync this marking or not</param> /// <param name="sync">Whether to immediately sync this marking or not</param>
/// <param name="forced">If this marking was forced (ignores marking points)</param> /// <param name="forced">If this marking was forced (ignores marking points)</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void AddMarking(EntityUid uid, string marking, Color? color = null, bool sync = true, bool forced = false, HumanoidAppearanceComponent? humanoid = null) public void AddMarking(
EntityUid uid,
string marking,
Color? color = null,
bool sync = true,
bool forced = false,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid) if (!Resolve(uid, ref humanoid)
|| !_markingManager.Markings.TryGetValue(marking, out var prototype)) || !_markingManager.Markings.TryGetValue(marking, out var prototype))
@@ -195,7 +245,13 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="sync">Whether to immediately sync this marking or not</param> /// <param name="sync">Whether to immediately sync this marking or not</param>
/// <param name="forced">If this marking was forced (ignores marking points)</param> /// <param name="forced">If this marking was forced (ignores marking points)</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void AddMarking(EntityUid uid, string marking, IReadOnlyList<Color> colors, bool sync = true, bool forced = false, HumanoidAppearanceComponent? humanoid = null) public void AddMarking(
EntityUid uid,
string marking,
IReadOnlyList<Color> colors,
bool sync = true,
bool forced = false,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid) if (!Resolve(uid, ref humanoid)
|| !_markingManager.Markings.TryGetValue(marking, out var prototype)) || !_markingManager.Markings.TryGetValue(marking, out var prototype))
@@ -218,7 +274,11 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="marking">The marking to try and remove.</param> /// <param name="marking">The marking to try and remove.</param>
/// <param name="sync">Whether to immediately sync this to the humanoid</param> /// <param name="sync">Whether to immediately sync this to the humanoid</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void RemoveMarking(EntityUid uid, string marking, bool sync = true, HumanoidAppearanceComponent? humanoid = null) public void RemoveMarking(
EntityUid uid,
string marking,
bool sync = true,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid) if (!Resolve(uid, ref humanoid)
|| !_markingManager.Markings.TryGetValue(marking, out var prototype)) || !_markingManager.Markings.TryGetValue(marking, out var prototype))
@@ -239,7 +299,11 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="category">Category of the marking</param> /// <param name="category">Category of the marking</param>
/// <param name="index">Index of the marking</param> /// <param name="index">Index of the marking</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void RemoveMarking(EntityUid uid, MarkingCategories category, int index, HumanoidAppearanceComponent? humanoid = null) public void RemoveMarking(
EntityUid uid,
MarkingCategories category,
int index,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (index < 0 if (index < 0
|| !Resolve(uid, ref humanoid) || !Resolve(uid, ref humanoid)
@@ -261,7 +325,12 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="index">Index of the marking</param> /// <param name="index">Index of the marking</param>
/// <param name="markingId">The marking ID to use</param> /// <param name="markingId">The marking ID to use</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void SetMarkingId(EntityUid uid, MarkingCategories category, int index, string markingId, HumanoidAppearanceComponent? humanoid = null) public void SetMarkingId(
EntityUid uid,
MarkingCategories category,
int index,
string markingId,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (index < 0 if (index < 0
|| !_markingManager.MarkingsByCategory(category).TryGetValue(markingId, out var markingPrototype) || !_markingManager.MarkingsByCategory(category).TryGetValue(markingId, out var markingPrototype)
@@ -290,7 +359,11 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="index">Index of the marking</param> /// <param name="index">Index of the marking</param>
/// <param name="colors">The marking colors to use</param> /// <param name="colors">The marking colors to use</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void SetMarkingColor(EntityUid uid, MarkingCategories category, int index, List<Color> colors, public void SetMarkingColor(
EntityUid uid,
MarkingCategories category,
int index,
List<Color> colors,
HumanoidAppearanceComponent? humanoid = null) HumanoidAppearanceComponent? humanoid = null)
{ {
if (index < 0 if (index < 0
@@ -314,37 +387,24 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// </summary> /// </summary>
public string GetSpeciesRepresentation(string speciesId) public string GetSpeciesRepresentation(string speciesId)
{ {
if (_prototypeManager.TryIndex<SpeciesPrototype>(speciesId, out var species)) return Loc.GetString(_prototypeManager.TryIndex<SpeciesPrototype>(speciesId, out var species)
{ ? species.Name
return Loc.GetString(species.Name); : "humanoid-appearance-component-unknown-species");
}
else
{
return Loc.GetString("humanoid-appearance-component-unknown-species");
}
} }
public string GetAgeRepresentation(string species, int age) public string GetAgeRepresentation(string species, int age)
{ {
_prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype); _prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype);
if (speciesPrototype == null) if (speciesPrototype != null)
{ {
Logger.Error("Tried to get age representation of species that couldn't be indexed: " + species); return age < speciesPrototype.YoungAge
return Loc.GetString("identity-age-young"); ? Loc.GetString("identity-age-young")
: Loc.GetString(age < speciesPrototype.OldAge ? "identity-age-middle-aged" : "identity-age-old");
} }
if (age < speciesPrototype.YoungAge) Logger.Error("Tried to get age representation of species that couldn't be indexed: " + species);
{ return Loc.GetString("identity-age-young");
return Loc.GetString("identity-age-young");
}
if (age < speciesPrototype.OldAge)
{
return Loc.GetString("identity-age-middle-aged");
}
return Loc.GetString("identity-age-old");
} }
private void EnsureDefaultMarkings(EntityUid uid, HumanoidAppearanceComponent? humanoid) private void EnsureDefaultMarkings(EntityUid uid, HumanoidAppearanceComponent? humanoid)
@@ -353,6 +413,7 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
{ {
return; return;
} }
humanoid.MarkingSet.EnsureDefault(humanoid.SkinColor, humanoid.EyeColor, _markingManager); humanoid.MarkingSet.EnsureDefault(humanoid.SkinColor, humanoid.EyeColor, _markingManager);
} }
} }

View File

@@ -7,6 +7,7 @@ using Content.Server.Database;
using Content.Server.Humanoid; using Content.Server.Humanoid;
using Content.Server._White.Sponsors; using Content.Server._White.Sponsors;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes; using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences; using Content.Shared.Preferences;
using Content.Shared.Roles; using Content.Shared.Roles;
@@ -16,7 +17,6 @@ using Robust.Shared.Network;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Server.Preferences.Managers namespace Content.Server.Preferences.Managers
{ {
/// <summary> /// <summary>
@@ -90,6 +90,7 @@ namespace Content.Server.Preferences.Managers
{ {
Logger.WarningS("prefs", Logger.WarningS("prefs",
$"User {userId} sent a {nameof(MsgUpdateCharacter)} with a null profile in slot {slot}."); $"User {userId} sent a {nameof(MsgUpdateCharacter)} with a null profile in slot {slot}.");
return; return;
} }
@@ -107,7 +108,9 @@ namespace Content.Server.Preferences.Managers
var curPrefs = prefsData.Prefs!; var curPrefs = prefsData.Prefs!;
// WD-EDIT // WD-EDIT
var allowedMarkings = _sponsors.TryGetInfo(message.MsgChannel.UserId, out var sponsor) ? sponsor.AllowedMarkings : new string[]{}; var allowedMarkings = _sponsors.TryGetInfo(message.MsgChannel.UserId, out var sponsor)
? sponsor.AllowedMarkings
: new string[] { };
bool isAdminSpecie = false; bool isAdminSpecie = false;
if (_playerManager.TryGetSessionById(message.MsgChannel.UserId, out var session)) if (_playerManager.TryGetSessionById(message.MsgChannel.UserId, out var session))
@@ -168,7 +171,8 @@ namespace Content.Server.Preferences.Managers
var arr = new Dictionary<int, ICharacterProfile>(curPrefs.Characters); var arr = new Dictionary<int, ICharacterProfile>(curPrefs.Characters);
arr.Remove(slot); arr.Remove(slot);
prefsData.Prefs = new PlayerPreferences(arr, nextSlot ?? curPrefs.SelectedCharacterIndex, curPrefs.AdminOOCColor); prefsData.Prefs =
new PlayerPreferences(arr, nextSlot ?? curPrefs.SelectedCharacterIndex, curPrefs.AdminOOCColor);
if (ShouldStorePrefs(message.MsgChannel.AuthType)) if (ShouldStorePrefs(message.MsgChannel.AuthType))
{ {
@@ -193,7 +197,7 @@ namespace Content.Server.Preferences.Managers
{ {
PrefsLoaded = true, PrefsLoaded = true,
Prefs = new PlayerPreferences( Prefs = new PlayerPreferences(
new[] {new KeyValuePair<int, ICharacterProfile>(0, HumanoidCharacterProfile.Random())}, new[] { new KeyValuePair<int, ICharacterProfile>(0, HumanoidCharacterProfile.Random()) },
0, Color.Transparent) 0, Color.Transparent)
}; };
@@ -214,8 +218,13 @@ namespace Content.Server.Preferences.Managers
// WD-EDIT // WD-EDIT
foreach (var (_, profile) in prefs.Characters) foreach (var (_, profile) in prefs.Characters)
{ {
var allowedMarkings = _sponsors.TryGetInfo(session.UserId, out var sponsor) ? sponsor.AllowedMarkings : new string[]{}; var allowedMarkings = _sponsors.TryGetInfo(session.UserId, out var sponsor)
bool isAdminSpecie = _adminManager.HasAdminFlag(session, Shared.Administration.AdminFlags.AdminSpecies); ? sponsor.AllowedMarkings
: new string[] { };
bool isAdminSpecie =
_adminManager.HasAdminFlag(session, Shared.Administration.AdminFlags.AdminSpecies);
profile.EnsureValid(allowedMarkings, isAdminSpecie); profile.EnsureValid(allowedMarkings, isAdminSpecie);
} }
// WD-EDIT // WD-EDIT
@@ -229,6 +238,7 @@ namespace Content.Server.Preferences.Managers
{ {
MaxCharacterSlots = GetMaxUserCharacterSlots(session.UserId) MaxCharacterSlots = GetMaxUserCharacterSlots(session.UserId)
}; };
_netManager.ServerSendMessage(msg, session.Channel); _netManager.ServerSendMessage(msg, session.Channel);
} }
} }
@@ -257,7 +267,8 @@ namespace Content.Server.Preferences.Managers
/// <param name="userId">User Id to get preferences for</param> /// <param name="userId">User Id to get preferences for</param>
/// <param name="playerPreferences">The user preferences if true, otherwise null</param> /// <param name="playerPreferences">The user preferences if true, otherwise null</param>
/// <returns>If preferences are not null</returns> /// <returns>If preferences are not null</returns>
public bool TryGetCachedPreferences(NetUserId userId, public bool TryGetCachedPreferences(
NetUserId userId,
[NotNullWhen(true)] out PlayerPreferences? playerPreferences) [NotNullWhen(true)] out PlayerPreferences? playerPreferences)
{ {
if (_cachedPlayerPrefs.TryGetValue(userId, out var prefs)) if (_cachedPlayerPrefs.TryGetValue(userId, out var prefs))
@@ -309,21 +320,27 @@ namespace Content.Server.Preferences.Managers
case HumanoidCharacterProfile hp: case HumanoidCharacterProfile hp:
{ {
var prototypeManager = IoCManager.Resolve<IPrototypeManager>(); var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
var selectedSpecies = HumanoidAppearanceSystem.DefaultSpecies;
if (prototypeManager.TryIndex<SpeciesPrototype>(hp.Species, out var species) && species.RoundStart) if (!prototypeManager.TryIndex<SpeciesPrototype>(hp.Species, out var selectedSpecies) ||
selectedSpecies.RoundStart)
{ {
selectedSpecies = hp.Species; selectedSpecies = prototypeManager.Index<SpeciesPrototype>(hp.Species);
}
if (!prototypeManager.TryIndex<BodyTypePrototype>(hp.BodyType, out var selectedBodyType) ||
!SharedHumanoidAppearanceSystem.IsBodyTypeValid(selectedBodyType, selectedSpecies, hp.Sex))
{
selectedBodyType = prototypeManager.Index<BodyTypePrototype>(
SharedHumanoidAppearanceSystem.DefaultBodyType);
} }
newProf = hp newProf = hp
.WithJobPriorities( .WithJobPriorities(hp.JobPriorities.Where(job => _protos.HasIndex<JobPrototype>(job.Key)))
hp.JobPriorities.Where(job => .WithAntagPreferences(hp.AntagPreferences.Where(antag =>
_protos.HasIndex<JobPrototype>(job.Key))) _protos.HasIndex<AntagPrototype>(antag)))
.WithAntagPreferences( .WithSpecies(selectedSpecies.ID)
hp.AntagPreferences.Where(antag => .WithBodyType(selectedBodyType.ID);
_protos.HasIndex<AntagPrototype>(antag)))
.WithSpecies(selectedSpecies);
break; break;
} }
default: default:

View File

@@ -70,10 +70,16 @@ public sealed partial class HumanoidAppearanceComponent : Component
[DataField, AutoNetworkedField] [DataField, AutoNetworkedField]
public Sex Sex = Sex.Male; public Sex Sex = Sex.Male;
/// <summary>
/// Current body type.
/// </summary>
[DataField("bodyType", customTypeSerializer: typeof(PrototypeIdSerializer<BodyTypePrototype>)), AutoNetworkedField]
public string BodyType = SharedHumanoidAppearanceSystem.DefaultBodyType;
[DataField, AutoNetworkedField] [DataField, AutoNetworkedField]
public Color EyeColor = Color.Brown; public Color EyeColor = Color.Brown;
[DataField("voice", customTypeSerializer: typeof(PrototypeIdSerializer<TTSVoicePrototype>))] [DataField("voice", customTypeSerializer: typeof(PrototypeIdSerializer<TTSVoicePrototype>)), AutoNetworkedField]
public string Voice { get; set; } = SharedHumanoidAppearanceSystem.DefaultVoice; public string Voice { get; set; } = SharedHumanoidAppearanceSystem.DefaultVoice;
/// <summary> /// <summary>

View File

@@ -11,7 +11,8 @@ namespace Content.Shared.Humanoid
[Serializable, NetSerializable] [Serializable, NetSerializable]
public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance
{ {
public HumanoidCharacterAppearance(string hairStyleId, public HumanoidCharacterAppearance(
string hairStyleId,
Color hairColor, Color hairColor,
string facialHairStyleId, string facialHairStyleId,
Color facialHairColor, Color facialHairColor,
@@ -91,20 +92,27 @@ namespace Content.Shared.Humanoid
Color.Black, Color.Black,
Color.Black, Color.Black,
Humanoid.SkinColor.ValidHumanSkinTone, Humanoid.SkinColor.ValidHumanSkinTone,
new () new List<Marking>()
) )
{ {
} }
public static string DefaultWithBodyType(string species)
{
var speciesPrototype = IoCManager.Resolve<IPrototypeManager>().Index<SpeciesPrototype>(species);
return speciesPrototype.BodyTypes.First();
}
public static HumanoidCharacterAppearance DefaultWithSpecies(string species) public static HumanoidCharacterAppearance DefaultWithSpecies(string species)
{ {
var speciesPrototype = IoCManager.Resolve<IPrototypeManager>().Index<SpeciesPrototype>(species); var speciesPrototype = IoCManager.Resolve<IPrototypeManager>().Index<SpeciesPrototype>(species);
var skinColor = speciesPrototype.SkinColoration switch var skinColor = speciesPrototype.SkinColoration switch
{ {
HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone), HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone),
HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone, HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone,
HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone), HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone),
_ => Humanoid.SkinColor.ValidHumanSkinTone _ => Humanoid.SkinColor.ValidHumanSkinTone
}; };
return new( return new(
@@ -114,7 +122,7 @@ namespace Content.Shared.Humanoid
Color.Black, Color.Black,
Color.Black, Color.Black,
skinColor, skinColor,
new () new()
); );
} }
@@ -132,7 +140,8 @@ namespace Content.Shared.Humanoid
var random = IoCManager.Resolve<IRobustRandom>(); var random = IoCManager.Resolve<IRobustRandom>();
var markingManager = IoCManager.Resolve<MarkingManager>(); var markingManager = IoCManager.Resolve<MarkingManager>();
var hairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.Hair, species).Keys.ToList(); var hairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.Hair, species).Keys.ToList();
var facialHairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.FacialHair, species).Keys.ToList(); var facialHairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.FacialHair, species)
.Keys.ToList();
var newHairStyle = hairStyles.Count > 0 var newHairStyle = hairStyles.Count > 0
? random.Pick(hairStyles) ? random.Pick(hairStyles)
@@ -175,7 +184,8 @@ namespace Content.Shared.Humanoid
newSkinColor = Humanoid.SkinColor.ValidTintedHuesSkinTone(newSkinColor); newSkinColor = Humanoid.SkinColor.ValidTintedHuesSkinTone(newSkinColor);
} }
return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, newEyeColor, newSkinColor, new ()); return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor,
newEyeColor, newSkinColor, new());
float RandomizeColor(float channel) float RandomizeColor(float channel)
{ {
@@ -188,7 +198,11 @@ namespace Content.Shared.Humanoid
return new(color.RByte, color.GByte, color.BByte); return new(color.RByte, color.GByte, color.BByte);
} }
public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, string[] sponsorMarkings) //WD-EDIT public static HumanoidCharacterAppearance EnsureValid(
HumanoidCharacterAppearance appearance,
string species,
string bodyType,
string[] sponsorMarkings) //WD-EDIT
{ {
var hairStyleId = appearance.HairStyleId; var hairStyleId = appearance.HairStyleId;
var facialHairStyleId = appearance.FacialHairStyleId; var facialHairStyleId = appearance.FacialHairStyleId;
@@ -250,7 +264,7 @@ namespace Content.Shared.Humanoid
skinColor = Humanoid.SkinColor.ValidSkinTone(speciesProto.SkinColoration, skinColor); skinColor = Humanoid.SkinColor.ValidSkinTone(speciesProto.SkinColoration, skinColor);
} }
markingSet.EnsureSpecies(species, skinColor, markingManager); markingSet.EnsureSpecies(species, bodyType, skinColor, markingManager);
// WD-EDIT // WD-EDIT
markingSet.FilterSponsor(sponsorMarkings, markingManager); markingSet.FilterSponsor(sponsorMarkings, markingManager);
@@ -270,19 +284,23 @@ namespace Content.Shared.Humanoid
{ {
if (maybeOther is not HumanoidCharacterAppearance other) if (maybeOther is not HumanoidCharacterAppearance other)
return false; return false;
if (HairStyleId != other.HairStyleId) if (HairStyleId != other.HairStyleId)
return false; return false;
if (!HairColor.Equals(other.HairColor)) if (!HairColor.Equals(other.HairColor))
return false; return false;
if (FacialHairStyleId != other.FacialHairStyleId) if (FacialHairStyleId != other.FacialHairStyleId)
return false; return false;
if (!FacialHairColor.Equals(other.FacialHairColor)) if (!FacialHairColor.Equals(other.FacialHairColor))
return false; return false;
if (!EyeColor.Equals(other.EyeColor)) if (!EyeColor.Equals(other.EyeColor))
return false; return false;
if (!SkinColor.Equals(other.SkinColor))
return false; return SkinColor.Equals(other.SkinColor) && Markings.SequenceEqual(other.Markings);
return Markings.SequenceEqual(other.Markings);
} }
} }
} }

View File

@@ -1,5 +1,4 @@
using Content.Shared.Humanoid.Markings; using Robust.Shared.Serialization;
using Robust.Shared.Serialization;
namespace Content.Shared.Humanoid namespace Content.Shared.Humanoid
{ {

View File

@@ -1,4 +1,3 @@
using Content.Shared.Body.Components;
using Content.Shared.Body.Part; using Content.Shared.Body.Part;
namespace Content.Shared.Humanoid namespace Content.Shared.Humanoid
@@ -10,14 +9,14 @@ namespace Content.Shared.Humanoid
return layer switch return layer switch
{ {
HumanoidVisualLayers.Chest => true, HumanoidVisualLayers.Chest => true,
HumanoidVisualLayers.Head => true, HumanoidVisualLayers.Head => true,
_ => false _ => false
}; };
} }
public static string GetSexMorph(HumanoidVisualLayers layer, Sex sex, string id) public static string GetSexMorph(HumanoidVisualLayers layer, Sex sex, string id)
{ {
if (!HasSexMorph(layer) || sex == Sex.Unsexed) if (!HasSexMorph(layer) || sex == Sex.Unsexed || sex == Sex.Male)
return id; return id;
return $"{id}{sex}"; return $"{id}{sex}";
@@ -42,26 +41,32 @@ namespace Content.Shared.Humanoid
yield return HumanoidVisualLayers.Hair; yield return HumanoidVisualLayers.Hair;
yield return HumanoidVisualLayers.FacialHair; yield return HumanoidVisualLayers.FacialHair;
yield return HumanoidVisualLayers.Snout; yield return HumanoidVisualLayers.Snout;
break; break;
case HumanoidVisualLayers.LArm: case HumanoidVisualLayers.LArm:
yield return HumanoidVisualLayers.LArm; yield return HumanoidVisualLayers.LArm;
yield return HumanoidVisualLayers.LHand; yield return HumanoidVisualLayers.LHand;
break; break;
case HumanoidVisualLayers.RArm: case HumanoidVisualLayers.RArm:
yield return HumanoidVisualLayers.RArm; yield return HumanoidVisualLayers.RArm;
yield return HumanoidVisualLayers.RHand; yield return HumanoidVisualLayers.RHand;
break; break;
case HumanoidVisualLayers.LLeg: case HumanoidVisualLayers.LLeg:
yield return HumanoidVisualLayers.LLeg; yield return HumanoidVisualLayers.LLeg;
yield return HumanoidVisualLayers.LFoot; yield return HumanoidVisualLayers.LFoot;
break; break;
case HumanoidVisualLayers.RLeg: case HumanoidVisualLayers.RLeg:
yield return HumanoidVisualLayers.RLeg; yield return HumanoidVisualLayers.RLeg;
yield return HumanoidVisualLayers.RFoot; yield return HumanoidVisualLayers.RFoot;
break; break;
case HumanoidVisualLayers.Chest: case HumanoidVisualLayers.Chest:
yield return HumanoidVisualLayers.Chest; yield return HumanoidVisualLayers.Chest;
yield return HumanoidVisualLayers.Tail; yield return HumanoidVisualLayers.Tail;
break; break;
default: default:
yield break; yield break;

View File

@@ -1,6 +1,5 @@
using System.Collections.Frozen; using System.Collections.Frozen;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared.Humanoid.Prototypes; using Content.Shared.Humanoid.Prototypes;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -11,7 +10,10 @@ namespace Content.Shared.Humanoid.Markings
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly List<MarkingPrototype> _index = new(); private readonly List<MarkingPrototype> _index = new();
public FrozenDictionary<MarkingCategories, FrozenDictionary<string, MarkingPrototype>> CategorizedMarkings = default!;
public FrozenDictionary<MarkingCategories, FrozenDictionary<string, MarkingPrototype>> CategorizedMarkings =
default!;
public FrozenDictionary<string, MarkingPrototype> Markings = default!; public FrozenDictionary<string, MarkingPrototype> Markings = default!;
public void Initialize() public void Initialize()
@@ -27,7 +29,7 @@ namespace Content.Shared.Humanoid.Markings
foreach (var category in Enum.GetValues<MarkingCategories>()) foreach (var category in Enum.GetValues<MarkingCategories>())
{ {
markingDict.Add(category, new()); markingDict.Add(category, new Dictionary<string, MarkingPrototype>());
} }
foreach (var prototype in _prototypeManager.EnumeratePrototypes<MarkingPrototype>()) foreach (var prototype in _prototypeManager.EnumeratePrototypes<MarkingPrototype>())
@@ -58,11 +60,14 @@ namespace Content.Shared.Humanoid.Markings
/// Please make a pull request if you find a use case for that behavior. /// Please make a pull request if you find a use case for that behavior.
/// </remarks> /// </remarks>
/// <returns></returns> /// <returns></returns>
public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSpecies(MarkingCategories category, public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSpecies(
MarkingCategories category,
string species) string species)
{ {
var speciesProto = _prototypeManager.Index<SpeciesPrototype>(species); var speciesProto = _prototypeManager.Index<SpeciesPrototype>(species);
var onlyWhitelisted = _prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted; var onlyWhitelisted = _prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints)
.OnlyWhitelisted;
var res = new Dictionary<string, MarkingPrototype>(); var res = new Dictionary<string, MarkingPrototype>();
foreach (var (key, marking) in MarkingsByCategory(category)) foreach (var (key, marking) in MarkingsByCategory(category))
@@ -76,6 +81,7 @@ namespace Content.Shared.Humanoid.Markings
{ {
continue; continue;
} }
res.Add(key, marking); res.Add(key, marking);
} }
@@ -92,7 +98,8 @@ namespace Content.Shared.Humanoid.Markings
/// Please make a pull request if you find a use case for that behavior. /// Please make a pull request if you find a use case for that behavior.
/// </remarks> /// </remarks>
/// <returns></returns> /// <returns></returns>
public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSex(MarkingCategories category, public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSex(
MarkingCategories category,
Sex sex) Sex sex)
{ {
var res = new Dictionary<string, MarkingPrototype>(); var res = new Dictionary<string, MarkingPrototype>();
@@ -121,11 +128,15 @@ namespace Content.Shared.Humanoid.Markings
/// Please make a pull request if you find a use case for that behavior. /// Please make a pull request if you find a use case for that behavior.
/// </remarks> /// </remarks>
/// <returns></returns> /// <returns></returns>
public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSpeciesAndSex(MarkingCategories category, public IReadOnlyDictionary<string, MarkingPrototype> MarkingsByCategoryAndSpeciesAndSex(
string species, Sex sex) MarkingCategories category,
string species,
Sex sex)
{ {
var speciesProto = _prototypeManager.Index<SpeciesPrototype>(species); var speciesProto = _prototypeManager.Index<SpeciesPrototype>(species);
var onlyWhitelisted = _prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted; var onlyWhitelisted = _prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints)
.OnlyWhitelisted;
var res = new Dictionary<string, MarkingPrototype>(); var res = new Dictionary<string, MarkingPrototype>();
foreach (var (key, marking) in MarkingsByCategory(category)) foreach (var (key, marking) in MarkingsByCategory(category))
@@ -178,12 +189,7 @@ namespace Content.Shared.Humanoid.Markings
return false; return false;
} }
if (marking.MarkingColors.Count != proto.Sprites.Count) return marking.MarkingColors.Count == proto.Sprites.Count;
{
return false;
}
return true;
} }
private void OnPrototypeReload(PrototypesReloadedEventArgs args) private void OnPrototypeReload(PrototypesReloadedEventArgs args)
@@ -197,7 +203,8 @@ namespace Content.Shared.Humanoid.Markings
IoCManager.Resolve(ref prototypeManager); IoCManager.Resolve(ref prototypeManager);
var speciesProto = prototypeManager.Index<SpeciesPrototype>(species); var speciesProto = prototypeManager.Index<SpeciesPrototype>(species);
var onlyWhitelisted = prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted; var onlyWhitelisted = prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints)
.OnlyWhitelisted;
if (!TryGetMarking(marking, out var prototype)) if (!TryGetMarking(marking, out var prototype))
{ {
@@ -223,12 +230,17 @@ namespace Content.Shared.Humanoid.Markings
return true; return true;
} }
public bool CanBeApplied(string species, Sex sex, MarkingPrototype prototype, IPrototypeManager? prototypeManager = null) public bool CanBeApplied(
string species,
Sex sex,
MarkingPrototype prototype,
IPrototypeManager? prototypeManager = null)
{ {
IoCManager.Resolve(ref prototypeManager); IoCManager.Resolve(ref prototypeManager);
var speciesProto = prototypeManager.Index<SpeciesPrototype>(species); var speciesProto = prototypeManager.Index<SpeciesPrototype>(species);
var onlyWhitelisted = prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted; var onlyWhitelisted = prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints)
.OnlyWhitelisted;
if (onlyWhitelisted && prototype.SpeciesRestrictions == null) if (onlyWhitelisted && prototype.SpeciesRestrictions == null)
{ {
@@ -249,16 +261,19 @@ namespace Content.Shared.Humanoid.Markings
return true; return true;
} }
public bool MustMatchSkin(string species, HumanoidVisualLayers layer, out float alpha, IPrototypeManager? prototypeManager = null) public bool MustMatchSkin(
string speciesBodyType,
HumanoidVisualLayers layer,
out float alpha,
IPrototypeManager? prototypeManager = null)
{ {
IoCManager.Resolve(ref prototypeManager); IoCManager.Resolve(ref prototypeManager);
var speciesProto = prototypeManager.Index<SpeciesPrototype>(species); // var speciesProto = prototypeManager.Index<SpeciesPrototype>(species);
if ( if (
!prototypeManager.TryIndex(speciesProto.SpriteSet, out HumanoidSpeciesBaseSpritesPrototype? baseSprites) || !prototypeManager.TryIndex(speciesBodyType, out BodyTypePrototype? baseSprites) ||
!baseSprites.Sprites.TryGetValue(layer, out var spriteName) || !baseSprites.Sprites.TryGetValue(layer, out var spriteName) ||
!prototypeManager.TryIndex(spriteName, out HumanoidSpeciesSpriteLayer? sprite) || !prototypeManager.TryIndex(spriteName, out HumanoidSpeciesSpriteLayer? sprite) ||
sprite == null || sprite is not { MarkingsMatchSkin: true }
!sprite.MarkingsMatchSkin
) )
{ {
alpha = 1f; alpha = 1f;

View File

@@ -51,7 +51,8 @@ public sealed partial class MarkingSet
public Dictionary<MarkingCategories, MarkingPoints> Points = new(); public Dictionary<MarkingCategories, MarkingPoints> Points = new();
public MarkingSet() public MarkingSet()
{} {
}
/// <summary> /// <summary>
/// Construct a MarkingSet using a list of markings, and a points /// Construct a MarkingSet using a list of markings, and a points
@@ -61,7 +62,11 @@ public sealed partial class MarkingSet
/// </summary> /// </summary>
/// <param name="markings">The lists of markings to use.</param> /// <param name="markings">The lists of markings to use.</param>
/// <param name="pointsPrototype">The ID of the points dictionary prototype.</param> /// <param name="pointsPrototype">The ID of the points dictionary prototype.</param>
public MarkingSet(List<Marking> markings, string pointsPrototype, MarkingManager? markingManager = null, IPrototypeManager? prototypeManager = null) public MarkingSet(
List<Marking> markings,
string pointsPrototype,
MarkingManager? markingManager = null,
IPrototypeManager? prototypeManager = null)
{ {
IoCManager.Resolve(ref markingManager, ref prototypeManager); IoCManager.Resolve(ref markingManager, ref prototypeManager);
@@ -108,7 +113,10 @@ public sealed partial class MarkingSet
/// Construct a MarkingSet only with a points dictionary. /// Construct a MarkingSet only with a points dictionary.
/// </summary> /// </summary>
/// <param name="pointsPrototype">The ID of the points dictionary prototype.</param> /// <param name="pointsPrototype">The ID of the points dictionary prototype.</param>
public MarkingSet(string pointsPrototype, MarkingManager? markingManager = null, IPrototypeManager? prototypeManager = null) public MarkingSet(
string pointsPrototype,
MarkingManager? markingManager = null,
IPrototypeManager? prototypeManager = null)
{ {
IoCManager.Resolve(ref markingManager, ref prototypeManager); IoCManager.Resolve(ref markingManager, ref prototypeManager);
@@ -141,17 +149,24 @@ public sealed partial class MarkingSet
/// Filters and colors markings based on species and it's restrictions in the marking's prototype from this marking set. /// Filters and colors markings based on species and it's restrictions in the marking's prototype from this marking set.
/// </summary> /// </summary>
/// <param name="species">The species to filter.</param> /// <param name="species">The species to filter.</param>
/// <param name="bodyType">Body type.</param>
/// <param name="skinColor">The skin color for recoloring (i.e. slimes). Use null if you want only filter markings</param> /// <param name="skinColor">The skin color for recoloring (i.e. slimes). Use null if you want only filter markings</param>
/// <param name="markingManager">Marking manager.</param> /// <param name="markingManager">Marking manager.</param>
/// <param name="prototypeManager">Prototype manager.</param> /// <param name="prototypeManager">Prototype manager.</param>
public void EnsureSpecies(string species, Color? skinColor, MarkingManager? markingManager = null, IPrototypeManager? prototypeManager = null) public void EnsureSpecies(
string species,
string bodyType,
Color? skinColor,
MarkingManager? markingManager = null,
IPrototypeManager? prototypeManager = null)
{ {
IoCManager.Resolve(ref markingManager); IoCManager.Resolve(ref markingManager);
IoCManager.Resolve(ref prototypeManager); IoCManager.Resolve(ref prototypeManager);
var toRemove = new List<(MarkingCategories category, string id)>(); var toRemove = new List<(MarkingCategories category, string id)>();
var speciesProto = prototypeManager.Index<SpeciesPrototype>(species); var speciesProto = prototypeManager.Index<SpeciesPrototype>(species);
var onlyWhitelisted = prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted; var onlyWhitelisted =
prototypeManager.Index<MarkingPointsPrototype>(speciesProto.MarkingPoints).OnlyWhitelisted;
foreach (var (category, list) in Markings) foreach (var (category, list) in Markings)
{ {
@@ -182,17 +197,17 @@ public sealed partial class MarkingSet
} }
// Re-color left markings them into skin color if needed (i.e. for slimes) // Re-color left markings them into skin color if needed (i.e. for slimes)
if (skinColor != null) if (skinColor == null)
return;
foreach (var (_, list) in Markings)
{ {
foreach (var (category, list) in Markings) foreach (var marking in list)
{ {
foreach (var marking in list) if (markingManager.TryGetMarking(marking, out var prototype) &&
markingManager.MustMatchSkin(bodyType, prototype.BodyPart, out var alpha, prototypeManager))
{ {
if (markingManager.TryGetMarking(marking, out var prototype) && marking.SetColor(skinColor.Value.WithAlpha(alpha));
markingManager.MustMatchSkin(species, prototype.BodyPart, out var alpha, prototypeManager))
{
marking.SetColor(skinColor.Value.WithAlpha(alpha));
}
} }
} }
} }
@@ -265,7 +280,10 @@ public sealed partial class MarkingSet
} }
// WD-EDIT // WD-EDIT
public void FilterSponsor(string[] sponsorMarkings, MarkingManager? markingManager = null, IPrototypeManager? prototypeManager = null) public void FilterSponsor(
string[] sponsorMarkings,
MarkingManager? markingManager = null,
IPrototypeManager? prototypeManager = null)
{ {
IoCManager.Resolve(ref markingManager); IoCManager.Resolve(ref markingManager);
IoCManager.Resolve(ref prototypeManager); IoCManager.Resolve(ref prototypeManager);
@@ -319,11 +337,12 @@ public sealed partial class MarkingSet
if (markingManager.Markings.TryGetValue(points.DefaultMarkings[index], out var prototype)) if (markingManager.Markings.TryGetValue(points.DefaultMarkings[index], out var prototype))
{ {
var colors = MarkingColoring.GetMarkingLayerColors( var colors = MarkingColoring.GetMarkingLayerColors(
prototype, prototype,
skinColor, skinColor,
eyeColor, eyeColor,
this this
); );
var marking = new Marking(points.DefaultMarkings[index], colors); var marking = new Marking(points.DefaultMarkings[index], colors);
AddBack(category, marking); AddBack(category, marking);
@@ -398,7 +417,6 @@ public sealed partial class MarkingSet
Markings[category] = markings; Markings[category] = markings;
} }
markings.Add(marking); markings.Add(marking);
} }
@@ -854,7 +872,8 @@ public sealed class MarkingsEnumerator : IEnumerator<Marking>
} }
public void Dispose() public void Dispose()
{} {
}
object IEnumerator.Current object IEnumerator.Current
{ {

View File

@@ -0,0 +1,35 @@
using Robust.Shared.Prototypes;
namespace Content.Shared.Humanoid.Prototypes
{
[Prototype("bodyType")]
public sealed class BodyTypePrototype : IPrototype
{
/// <summary>
/// Which sex can't use this body type.
/// </summary>
[DataField("sexRestrictions")]
public List<string> SexRestrictions = new();
/// <summary>
/// Sprites that this species will use on the given humanoid
/// visual layer. If a key entry is empty, it is assumed that the
/// visual layer will not be in use on this species, and will
/// be ignored.
/// </summary>
[DataField("sprites", required: true)]
public Dictionary<HumanoidVisualLayers, string> Sprites = new();
/// <summary>
/// User visible name of the body type.
/// </summary>
[DataField("name", required: true)]
public string Name { get; } = default!;
/// <summary>
/// Prototype ID of the body type.
/// </summary>
[IdDataField]
public string ID { get; } = default!;
}
}

View File

@@ -3,7 +3,7 @@ using Robust.Shared.Utility;
namespace Content.Shared.Humanoid.Prototypes; namespace Content.Shared.Humanoid.Prototypes;
/// <summary> /*/// <summary>
/// Base sprites for a species (e.g., what replaces the empty tagged layer, /// Base sprites for a species (e.g., what replaces the empty tagged layer,
/// or settings per layer) /// or settings per layer)
/// </summary> /// </summary>
@@ -21,7 +21,7 @@ public sealed partial class HumanoidSpeciesBaseSpritesPrototype : IPrototype
/// </summary> /// </summary>
[DataField("sprites", required: true)] [DataField("sprites", required: true)]
public Dictionary<HumanoidVisualLayers, string> Sprites = new(); public Dictionary<HumanoidVisualLayers, string> Sprites = new();
} }*/
/// <summary> /// <summary>
/// Humanoid species sprite layer. This is what defines the base layer of /// Humanoid species sprite layer. This is what defines the base layer of

View File

@@ -1,5 +1,6 @@
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Humanoid.Prototypes; namespace Content.Shared.Humanoid.Prototypes;
@@ -18,6 +19,9 @@ public sealed partial class SpeciesPrototype : IPrototype
[DataField("name", required: true)] [DataField("name", required: true)]
public string Name { get; private set; } = default!; public string Name { get; private set; } = default!;
[DataField("bodyTypes", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<BodyTypePrototype>))]
public List<string> BodyTypes { get; } = default!;
/// <summary> /// <summary>
/// Descriptor. Unused...? This is intended /// Descriptor. Unused...? This is intended
/// for an eventual integration into IdentitySystem /// for an eventual integration into IdentitySystem
@@ -41,8 +45,8 @@ public sealed partial class SpeciesPrototype : IPrototype
// sprite layout, and leave this null. Keep in mind that this will disable // sprite layout, and leave this null. Keep in mind that this will disable
// sprite accessories. // sprite accessories.
[DataField("sprites")] // [DataField("sprites")]
public string SpriteSet { get; private set; } = default!; // public string SpriteSet { get; private set; } = default!;
/// <summary> /// <summary>
/// Default skin tone for this species. This applies for non-human skin tones. /// Default skin tone for this species. This applies for non-human skin tones.
@@ -66,13 +70,13 @@ public sealed partial class SpeciesPrototype : IPrototype
/// <summary> /// <summary>
/// Humanoid species variant used by this entity. /// Humanoid species variant used by this entity.
/// </summary> /// </summary>
[DataField("prototype", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))] [DataField("prototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Prototype { get; private set; } = default!; public string Prototype { get; private set; } = default!;
/// <summary> /// <summary>
/// Prototype used by the species for the dress-up doll in various menus. /// Prototype used by the species for the dress-up doll in various menus.
/// </summary> /// </summary>
[DataField("dollPrototype", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))] [DataField("dollPrototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string DollPrototype { get; private set; } = default!; public string DollPrototype { get; private set; } = default!;
/// <summary> /// <summary>

View File

@@ -1,5 +1,4 @@
using System.Linq; using System.Linq;
using Content.Shared.Decals;
using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes; using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences; using Content.Shared.Preferences;
@@ -26,12 +25,15 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
[ValidatePrototypeId<SpeciesPrototype>] [ValidatePrototypeId<SpeciesPrototype>]
public const string DefaultSpecies = "Human"; public const string DefaultSpecies = "Human";
public const string DefaultBodyType = "HumanNormal";
public const string DefaultVoice = "Eugene"; public const string DefaultVoice = "Eugene";
public static readonly Dictionary<Sex, string> DefaultSexVoice = new() public static readonly Dictionary<Sex, string> DefaultSexVoice = new()
{ {
{Sex.Male, "Eugene"}, { Sex.Male, "Eugene" },
{Sex.Female, "Kseniya"}, { Sex.Female, "Kseniya" },
{Sex.Unsexed, "Xenia"}, { Sex.Unsexed, "Xenia" },
}; };
public override void Initialize() public override void Initialize()
@@ -69,7 +71,8 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="uid">Humanoid mob's UID</param> /// <param name="uid">Humanoid mob's UID</param>
/// <param name="layer">Layer to toggle visibility for</param> /// <param name="layer">Layer to toggle visibility for</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void SetLayerVisibility(EntityUid uid, public void SetLayerVisibility(
EntityUid uid,
HumanoidVisualLayers layer, HumanoidVisualLayers layer,
bool visible, bool visible,
bool permanent = false, bool permanent = false,
@@ -92,7 +95,11 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="visible">The visibility state of the layers given</param> /// <param name="visible">The visibility state of the layers given</param>
/// <param name="permanent">If this is a permanent change, or temporary. Permanent layers are stored in their own hash set.</param> /// <param name="permanent">If this is a permanent change, or temporary. Permanent layers are stored in their own hash set.</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void SetLayersVisibility(EntityUid uid, IEnumerable<HumanoidVisualLayers> layers, bool visible, bool permanent = false, public void SetLayersVisibility(
EntityUid uid,
IEnumerable<HumanoidVisualLayers> layers,
bool visible,
bool permanent = false,
HumanoidAppearanceComponent? humanoid = null) HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid)) if (!Resolve(uid, ref humanoid))
@@ -141,7 +148,11 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="species">The species to set the mob to. Will return if the species prototype was invalid.</param> /// <param name="species">The species to set the mob to. Will return if the species prototype was invalid.</param>
/// <param name="sync">Whether to immediately synchronize this to the humanoid mob, or not.</param> /// <param name="sync">Whether to immediately synchronize this to the humanoid mob, or not.</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void SetSpecies(EntityUid uid, string species, bool sync = true, HumanoidAppearanceComponent? humanoid = null) public void SetSpecies(
EntityUid uid,
string species,
bool sync = true,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid) || !_prototypeManager.TryIndex<SpeciesPrototype>(species, out var prototype)) if (!Resolve(uid, ref humanoid) || !_prototypeManager.TryIndex<SpeciesPrototype>(species, out var prototype))
{ {
@@ -149,12 +160,14 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
} }
humanoid.Species = species; humanoid.Species = species;
humanoid.MarkingSet.EnsureSpecies(species, humanoid.SkinColor, _markingManager); humanoid.MarkingSet.EnsureSpecies(species, humanoid.BodyType, humanoid.SkinColor, _markingManager);
var oldMarkings = humanoid.MarkingSet.GetForwardEnumerator().ToList(); var oldMarkings = humanoid.MarkingSet.GetForwardEnumerator().ToList();
humanoid.MarkingSet = new(oldMarkings, prototype.MarkingPoints, _markingManager, _prototypeManager); humanoid.MarkingSet = new MarkingSet(oldMarkings, prototype.MarkingPoints, _markingManager, _prototypeManager);
if (sync) if (sync)
Dirty(humanoid); {
Dirty(uid, humanoid);
}
} }
/// <summary> /// <summary>
@@ -166,7 +179,12 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="sync">Whether to synchronize this to the humanoid mob, or not.</param> /// <param name="sync">Whether to synchronize this to the humanoid mob, or not.</param>
/// <param name="verify">Whether to verify the skin color can be set on this humanoid or not</param> /// <param name="verify">Whether to verify the skin color can be set on this humanoid or not</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public virtual void SetSkinColor(EntityUid uid, Color skinColor, bool sync = true, bool verify = true, HumanoidAppearanceComponent? humanoid = null) public virtual void SetSkinColor(
EntityUid uid,
Color skinColor,
bool sync = true,
bool verify = true,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid)) if (!Resolve(uid, ref humanoid))
return; return;
@@ -196,7 +214,11 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="id">The ID of the sprite to use. See <see cref="HumanoidSpeciesSpriteLayer"/>.</param> /// <param name="id">The ID of the sprite to use. See <see cref="HumanoidSpeciesSpriteLayer"/>.</param>
/// <param name="sync">Whether to synchronize this to the humanoid mob, or not.</param> /// <param name="sync">Whether to synchronize this to the humanoid mob, or not.</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void SetBaseLayerId(EntityUid uid, HumanoidVisualLayers layer, string? id, bool sync = true, public void SetBaseLayerId(
EntityUid uid,
HumanoidVisualLayers layer,
string? id,
bool sync = true,
HumanoidAppearanceComponent? humanoid = null) HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid)) if (!Resolve(uid, ref humanoid))
@@ -218,7 +240,12 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="uid">The humanoid mob's UID.</param> /// <param name="uid">The humanoid mob's UID.</param>
/// <param name="layer">The layer to target on this humanoid mob.</param> /// <param name="layer">The layer to target on this humanoid mob.</param>
/// <param name="color">The color to set this base layer to.</param> /// <param name="color">The color to set this base layer to.</param>
public void SetBaseLayerColor(EntityUid uid, HumanoidVisualLayers layer, Color? color, bool sync = true, HumanoidAppearanceComponent? humanoid = null) public void SetBaseLayerColor(
EntityUid uid,
HumanoidVisualLayers layer,
Color? color,
bool sync = true,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid)) if (!Resolve(uid, ref humanoid))
return; return;
@@ -255,13 +282,27 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
} }
} }
public List<BodyTypePrototype> GetValidBodyTypes(SpeciesPrototype species, Sex sex)
{
return species.BodyTypes.Select(protoId => _prototypeManager.Index<BodyTypePrototype>(protoId))
.Where(proto => !proto.SexRestrictions.Contains(sex.ToString())).ToList();
}
public static bool IsBodyTypeValid(BodyTypePrototype bodyType, SpeciesPrototype species, Sex sex)
{
return species.BodyTypes.Contains(bodyType.ID);
}
/// <summary> /// <summary>
/// Loads a humanoid character profile directly onto this humanoid mob. /// Loads a humanoid character profile directly onto this humanoid mob.
/// </summary> /// </summary>
/// <param name="uid">The mob's entity UID.</param> /// <param name="uid">The mob's entity UID.</param>
/// <param name="profile">The character profile to load.</param> /// <param name="profile">The character profile to load.</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public virtual void LoadProfile(EntityUid uid, HumanoidCharacterProfile profile, HumanoidAppearanceComponent? humanoid = null) public virtual void LoadProfile(
EntityUid uid,
HumanoidCharacterProfile profile,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid)) if (!Resolve(uid, ref humanoid))
{ {
@@ -295,10 +336,15 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
// Hair/facial hair - this may eventually be deprecated. // Hair/facial hair - this may eventually be deprecated.
// We need to ensure hair before applying it or coloring can try depend on markings that can be invalid // We need to ensure hair before applying it or coloring can try depend on markings that can be invalid
var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha, _prototypeManager) var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha,
? profile.Appearance.SkinColor.WithAlpha(hairAlpha) : profile.Appearance.HairColor; _prototypeManager)
var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, out var facialHairAlpha, _prototypeManager) ? profile.Appearance.SkinColor.WithAlpha(hairAlpha)
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor; : profile.Appearance.HairColor;
var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair,
out var facialHairAlpha, _prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha)
: profile.Appearance.FacialHairColor;
if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) && if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) &&
_markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _prototypeManager)) _markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _prototypeManager))
@@ -312,7 +358,9 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false); AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false);
} }
humanoid.MarkingSet.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _prototypeManager); humanoid.MarkingSet.EnsureSpecies(profile.Species, profile.BodyType, profile.Appearance.SkinColor,
_markingManager,
_prototypeManager);
// Finally adding marking with forced colors // Finally adding marking with forced colors
foreach (var (marking, prototype) in markingFColored) foreach (var (marking, prototype) in markingFColored)
@@ -323,6 +371,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
profile.Appearance.EyeColor, profile.Appearance.EyeColor,
humanoid.MarkingSet humanoid.MarkingSet
); );
AddMarking(uid, marking.MarkingId, markingColors, false); AddMarking(uid, marking.MarkingId, markingColors, false);
} }
@@ -348,7 +397,13 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="sync">Whether to immediately sync this marking or not</param> /// <param name="sync">Whether to immediately sync this marking or not</param>
/// <param name="forced">If this marking was forced (ignores marking points)</param> /// <param name="forced">If this marking was forced (ignores marking points)</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void AddMarking(EntityUid uid, string marking, Color? color = null, bool sync = true, bool forced = false, HumanoidAppearanceComponent? humanoid = null) public void AddMarking(
EntityUid uid,
string marking,
Color? color = null,
bool sync = true,
bool forced = false,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid) if (!Resolve(uid, ref humanoid)
|| !_markingManager.Markings.TryGetValue(marking, out var prototype)) || !_markingManager.Markings.TryGetValue(marking, out var prototype))
@@ -378,6 +433,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
{ {
return; return;
} }
humanoid.MarkingSet.EnsureDefault(humanoid.SkinColor, humanoid.EyeColor, _markingManager); humanoid.MarkingSet.EnsureDefault(humanoid.SkinColor, humanoid.EyeColor, _markingManager);
} }
@@ -390,7 +446,13 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="sync">Whether to immediately sync this marking or not</param> /// <param name="sync">Whether to immediately sync this marking or not</param>
/// <param name="forced">If this marking was forced (ignores marking points)</param> /// <param name="forced">If this marking was forced (ignores marking points)</param>
/// <param name="humanoid">Humanoid component of the entity</param> /// <param name="humanoid">Humanoid component of the entity</param>
public void AddMarking(EntityUid uid, string marking, IReadOnlyList<Color> colors, bool sync = true, bool forced = false, HumanoidAppearanceComponent? humanoid = null) public void AddMarking(
EntityUid uid,
string marking,
IReadOnlyList<Color> colors,
bool sync = true,
bool forced = false,
HumanoidAppearanceComponent? humanoid = null)
{ {
if (!Resolve(uid, ref humanoid) if (!Resolve(uid, ref humanoid)
|| !_markingManager.Markings.TryGetValue(marking, out var prototype)) || !_markingManager.Markings.TryGetValue(marking, out var prototype))

View File

@@ -44,6 +44,7 @@ public sealed class HumanoidMarkingModifierState : BoundUserInterfaceState
public HumanoidMarkingModifierState( public HumanoidMarkingModifierState(
MarkingSet markingSet, MarkingSet markingSet,
string species, string species,
string bodyType,
Sex sex, Sex sex,
Color skinColor, Color skinColor,
Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayers Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> customBaseLayers
@@ -51,6 +52,7 @@ public sealed class HumanoidMarkingModifierState : BoundUserInterfaceState
{ {
MarkingSet = markingSet; MarkingSet = markingSet;
Species = species; Species = species;
BodyType = bodyType;
Sex = sex; Sex = sex;
SkinColor = skinColor; SkinColor = skinColor;
CustomBaseLayers = customBaseLayers; CustomBaseLayers = customBaseLayers;
@@ -60,6 +62,7 @@ public sealed class HumanoidMarkingModifierState : BoundUserInterfaceState
public string Species { get; } public string Species { get; }
public Sex Sex { get; } public Sex Sex { get; }
public Color SkinColor { get; } public Color SkinColor { get; }
public string BodyType { get; }
public Color EyeColor { get; } public Color EyeColor { get; }
public Color? HairColor { get; } public Color? HairColor { get; }
public Color? FacialHairColor { get; } public Color? FacialHairColor { get; }

View File

@@ -1,11 +1,9 @@
using System.Linq; using System.Linq;
using System.Globalization;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.GameTicking; using Content.Shared.GameTicking;
using Content.Shared.Humanoid; using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes; using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Random.Helpers;
using Content.Shared.Roles; using Content.Shared.Roles;
using Content.Shared.Traits; using Content.Shared.Traits;
using Content.Shared._White.TTS; using Content.Shared._White.TTS;
@@ -15,8 +13,6 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using Content.Shared.Administration.Managers;
using Content.Shared.Administration;
namespace Content.Shared.Preferences namespace Content.Shared.Preferences
{ {
@@ -45,6 +41,7 @@ namespace Content.Shared.Preferences
Sex sex, Sex sex,
string voice, string voice,
Gender gender, Gender gender,
string bodyType,
HumanoidCharacterAppearance appearance, HumanoidCharacterAppearance appearance,
ClothingPreference clothing, ClothingPreference clothing,
BackpackPreference backpack, BackpackPreference backpack,
@@ -64,6 +61,7 @@ namespace Content.Shared.Preferences
Age = age; Age = age;
Sex = sex; Sex = sex;
Gender = gender; Gender = gender;
BodyType = bodyType;
Appearance = appearance; Appearance = appearance;
Clothing = clothing; Clothing = clothing;
Backpack = backpack; Backpack = backpack;
@@ -80,14 +78,17 @@ namespace Content.Shared.Preferences
Dictionary<string, JobPriority> jobPriorities, Dictionary<string, JobPriority> jobPriorities,
List<string> antagPreferences, List<string> antagPreferences,
List<string> traitPreferences) List<string> traitPreferences)
: this(other.Name, other.ClownName, other.MimeName, other.BorgName, other.FlavorText, other.Species, other.Voice, other.Age, other.Sex, other.Gender, other.Appearance, other.Clothing, other.Backpack, other.SpawnPriority, : this(other.Name, other.ClownName, other.MimeName, other.BorgName, other.FlavorText, other.Species,
other.Voice, other.Age, other.Sex, other.Gender, other.BodyType, other.Appearance, other.Clothing,
other.Backpack, other.SpawnPriority,
jobPriorities, other.PreferenceUnavailable, antagPreferences, traitPreferences) jobPriorities, other.PreferenceUnavailable, antagPreferences, traitPreferences)
{ {
} }
/// <summary>Copy constructor</summary> /// <summary>Copy constructor</summary>
private HumanoidCharacterProfile(HumanoidCharacterProfile other) private HumanoidCharacterProfile(HumanoidCharacterProfile other)
: this(other, new Dictionary<string, JobPriority>(other.JobPriorities), new List<string>(other.AntagPreferences), new List<string>(other.TraitPreferences)) : this(other, new Dictionary<string, JobPriority>(other.JobPriorities),
new List<string>(other.AntagPreferences), new List<string>(other.TraitPreferences))
{ {
} }
@@ -102,6 +103,7 @@ namespace Content.Shared.Preferences
int age, int age,
Sex sex, Sex sex,
Gender gender, Gender gender,
string bodyType,
HumanoidCharacterAppearance appearance, HumanoidCharacterAppearance appearance,
ClothingPreference clothing, ClothingPreference clothing,
BackpackPreference backpack, BackpackPreference backpack,
@@ -110,7 +112,8 @@ namespace Content.Shared.Preferences
PreferenceUnavailableMode preferenceUnavailable, PreferenceUnavailableMode preferenceUnavailable,
IReadOnlyList<string> antagPreferences, IReadOnlyList<string> antagPreferences,
IReadOnlyList<string> traitPreferences) IReadOnlyList<string> traitPreferences)
: this(name, clownName, mimeName, borgName, flavortext, species, age, sex, voice, gender, appearance, clothing, backpack, spawnPriority, new Dictionary<string, JobPriority>(jobPriorities), : this(name, clownName, mimeName, borgName, flavortext, species, age, sex, voice, gender, bodyType,
appearance, clothing, backpack, spawnPriority, new Dictionary<string, JobPriority>(jobPriorities),
preferenceUnavailable, new List<string>(antagPreferences), new List<string>(traitPreferences)) preferenceUnavailable, new List<string>(antagPreferences), new List<string>(traitPreferences))
{ {
} }
@@ -131,13 +134,14 @@ namespace Content.Shared.Preferences
18, 18,
Sex.Male, Sex.Male,
Gender.Male, Gender.Male,
SharedHumanoidAppearanceSystem.DefaultBodyType,
new HumanoidCharacterAppearance(), new HumanoidCharacterAppearance(),
ClothingPreference.Jumpsuit, ClothingPreference.Jumpsuit,
BackpackPreference.Backpack, BackpackPreference.Backpack,
SpawnPriorityPreference.None, SpawnPriorityPreference.None,
new Dictionary<string, JobPriority> new Dictionary<string, JobPriority>
{ {
{SharedGameTicker.FallbackOverflowJob, JobPriority.High} { SharedGameTicker.FallbackOverflowJob, JobPriority.High }
}, },
PreferenceUnavailableMode.SpawnAsOverflow, PreferenceUnavailableMode.SpawnAsOverflow,
new List<string>(), new List<string>(),
@@ -150,7 +154,8 @@ namespace Content.Shared.Preferences
/// </summary> /// </summary>
/// <param name="species">The species to use in this default profile. The default species is <see cref="SharedHumanoidAppearanceSystem.DefaultSpecies"/>.</param> /// <param name="species">The species to use in this default profile. The default species is <see cref="SharedHumanoidAppearanceSystem.DefaultSpecies"/>.</param>
/// <returns>Humanoid character profile with default settings.</returns> /// <returns>Humanoid character profile with default settings.</returns>
public static HumanoidCharacterProfile DefaultWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies) public static HumanoidCharacterProfile DefaultWithSpecies(
string species = SharedHumanoidAppearanceSystem.DefaultSpecies)
{ {
return new( return new(
"John Doe", "John Doe",
@@ -163,13 +168,14 @@ namespace Content.Shared.Preferences
18, 18,
Sex.Male, Sex.Male,
Gender.Male, Gender.Male,
SharedHumanoidAppearanceSystem.DefaultBodyType,
HumanoidCharacterAppearance.DefaultWithSpecies(species), HumanoidCharacterAppearance.DefaultWithSpecies(species),
ClothingPreference.Jumpsuit, ClothingPreference.Jumpsuit,
BackpackPreference.Backpack, BackpackPreference.Backpack,
SpawnPriorityPreference.None, SpawnPriorityPreference.None,
new Dictionary<string, JobPriority> new Dictionary<string, JobPriority>
{ {
{SharedGameTicker.FallbackOverflowJob, JobPriority.High} { SharedGameTicker.FallbackOverflowJob, JobPriority.High }
}, },
PreferenceUnavailableMode.SpawnAsOverflow, PreferenceUnavailableMode.SpawnAsOverflow,
new List<string>(), new List<string>(),
@@ -191,17 +197,21 @@ namespace Content.Shared.Preferences
return RandomWithSpecies(species); return RandomWithSpecies(species);
} }
public static HumanoidCharacterProfile RandomWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies) public static HumanoidCharacterProfile RandomWithSpecies(
string species = SharedHumanoidAppearanceSystem.DefaultSpecies)
{ {
var prototypeManager = IoCManager.Resolve<IPrototypeManager>(); var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
var random = IoCManager.Resolve<IRobustRandom>(); var random = IoCManager.Resolve<IRobustRandom>();
var sex = Sex.Unsexed; var sex = Sex.Unsexed;
var age = 18; var age = 18;
var bodyType = SharedHumanoidAppearanceSystem.DefaultBodyType;
if (prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype)) if (prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype))
{ {
sex = random.Pick(speciesPrototype.Sexes); sex = random.Pick(speciesPrototype.Sexes);
age = random.Next(speciesPrototype.MinAge, speciesPrototype.OldAge); // people don't look and keep making 119 year old characters with zero rp, cap it at middle aged age = random.Next(speciesPrototype.MinAge,
speciesPrototype
.OldAge); // people don't look and keep making 119 year old characters with zero rp, cap it at middle aged
} }
var voiceId = random.Pick(prototypeManager var voiceId = random.Pick(prototypeManager
@@ -226,18 +236,25 @@ namespace Content.Shared.Preferences
var mimeName = GetMimeName(); var mimeName = GetMimeName();
var borgName = GetBorgName(); var borgName = GetBorgName();
return new HumanoidCharacterProfile(name, clownName, mimeName, borgName, "", species, voiceId, age, sex, gender, HumanoidCharacterAppearance.Random(species, sex), ClothingPreference.Jumpsuit, BackpackPreference.Backpack, SpawnPriorityPreference.None, return new HumanoidCharacterProfile(name, clownName, mimeName, borgName, "", species, voiceId, age, sex,
gender, bodyType, HumanoidCharacterAppearance.Random(species, sex), ClothingPreference.Jumpsuit,
BackpackPreference.Backpack, SpawnPriorityPreference.None,
new Dictionary<string, JobPriority> new Dictionary<string, JobPriority>
{ {
{SharedGameTicker.FallbackOverflowJob, JobPriority.High}, { SharedGameTicker.FallbackOverflowJob, JobPriority.High },
}, PreferenceUnavailableMode.StayInLobby, new List<string>(), new List<string>()); }, PreferenceUnavailableMode.StayInLobby, new List<string>(), new List<string>());
} }
public string Name { get; private set; } public string Name { get; private set; }
public string ClownName { get; private set; } public string ClownName { get; private set; }
public string MimeName { get; private set; } public string MimeName { get; private set; }
public string BorgName { get; private set; } public string BorgName { get; private set; }
public string FlavorText { get; private set; } public string FlavorText { get; private set; }
public string Species { get; private set; } public string Species { get; private set; }
public string Voice { get; private set; } public string Voice { get; private set; }
@@ -251,24 +268,38 @@ namespace Content.Shared.Preferences
[DataField("gender")] [DataField("gender")]
public Gender Gender { get; private set; } public Gender Gender { get; private set; }
[DataField]
public string BodyType { get; private set; }
public ICharacterAppearance CharacterAppearance => Appearance; public ICharacterAppearance CharacterAppearance => Appearance;
[DataField("appearance")] [DataField("appearance")]
public HumanoidCharacterAppearance Appearance { get; private set; } public HumanoidCharacterAppearance Appearance { get; private set; }
public ClothingPreference Clothing { get; private set; }
public BackpackPreference Backpack { get; private set; }
public SpawnPriorityPreference SpawnPriority { get; private set; }
public IReadOnlyDictionary<string, JobPriority> JobPriorities => _jobPriorities;
public IReadOnlyList<string> AntagPreferences => _antagPreferences;
public IReadOnlyList<string> TraitPreferences => _traitPreferences;
public PreferenceUnavailableMode PreferenceUnavailable { get; private set; }
public ClothingPreference Clothing { get; private set; }
public BackpackPreference Backpack { get; private set; }
public SpawnPriorityPreference SpawnPriority { get; private set; }
public IReadOnlyDictionary<string, JobPriority> JobPriorities => _jobPriorities;
public IReadOnlyList<string> AntagPreferences => _antagPreferences;
public IReadOnlyList<string> TraitPreferences => _traitPreferences;
public PreferenceUnavailableMode PreferenceUnavailable { get; private set; }
public HumanoidCharacterProfile WithVoice(string voice) public HumanoidCharacterProfile WithVoice(string voice)
{ {
return new(this) { Voice = voice }; return new(this) { Voice = voice };
} }
public HumanoidCharacterProfile WithBodyType(string bodyType)
{
return new(this) { BodyType = bodyType };
}
public HumanoidCharacterProfile WithName(string name) public HumanoidCharacterProfile WithName(string name)
{ {
return new(this) { Name = name }; return new(this) { Name = name };
@@ -278,10 +309,12 @@ namespace Content.Shared.Preferences
{ {
return new(this) { ClownName = name }; return new(this) { ClownName = name };
} }
public HumanoidCharacterProfile WithMimeName(string name) public HumanoidCharacterProfile WithMimeName(string name)
{ {
return new(this) { MimeName = name }; return new(this) { MimeName = name };
} }
public HumanoidCharacterProfile WithBorgName(string name) public HumanoidCharacterProfile WithBorgName(string name)
{ {
return new(this) { BorgName = name }; return new(this) { BorgName = name };
@@ -312,7 +345,6 @@ namespace Content.Shared.Preferences
return new(this) { Species = species }; return new(this) { Species = species };
} }
public HumanoidCharacterProfile WithCharacterAppearance(HumanoidCharacterAppearance appearance) public HumanoidCharacterProfile WithCharacterAppearance(HumanoidCharacterAppearance appearance)
{ {
return new(this) { Appearance = appearance }; return new(this) { Appearance = appearance };
@@ -322,14 +354,17 @@ namespace Content.Shared.Preferences
{ {
return new(this) { Clothing = clothing }; return new(this) { Clothing = clothing };
} }
public HumanoidCharacterProfile WithBackpackPreference(BackpackPreference backpack) public HumanoidCharacterProfile WithBackpackPreference(BackpackPreference backpack)
{ {
return new(this) { Backpack = backpack }; return new(this) { Backpack = backpack };
} }
public HumanoidCharacterProfile WithSpawnPriorityPreference(SpawnPriorityPreference spawnPriority) public HumanoidCharacterProfile WithSpawnPriorityPreference(SpawnPriorityPreference spawnPriority)
{ {
return new(this) { SpawnPriority = spawnPriority }; return new(this) { SpawnPriority = spawnPriority };
} }
public HumanoidCharacterProfile WithJobPriorities(IEnumerable<KeyValuePair<string, JobPriority>> jobPriorities) public HumanoidCharacterProfile WithJobPriorities(IEnumerable<KeyValuePair<string, JobPriority>> jobPriorities)
{ {
return new(this, new Dictionary<string, JobPriority>(jobPriorities), _antagPreferences, _traitPreferences); return new(this, new Dictionary<string, JobPriority>(jobPriorities), _antagPreferences, _traitPreferences);
@@ -346,6 +381,7 @@ namespace Content.Shared.Preferences
{ {
dictionary[jobId] = priority; dictionary[jobId] = priority;
} }
return new(this, dictionary, _antagPreferences, _traitPreferences); return new(this, dictionary, _antagPreferences, _traitPreferences);
} }
@@ -376,6 +412,7 @@ namespace Content.Shared.Preferences
list.Remove(antagId); list.Remove(antagId);
} }
} }
return new(this, _jobPriorities, list, _traitPreferences); return new(this, _jobPriorities, list, _traitPreferences);
} }
@@ -398,6 +435,7 @@ namespace Content.Shared.Preferences
list.Remove(traitId); list.Remove(traitId);
} }
} }
return new(this, _jobPriorities, _antagPreferences, list); return new(this, _jobPriorities, _antagPreferences, list);
} }
@@ -411,21 +449,54 @@ namespace Content.Shared.Preferences
public bool MemberwiseEquals(ICharacterProfile maybeOther) public bool MemberwiseEquals(ICharacterProfile maybeOther)
{ {
if (maybeOther is not HumanoidCharacterProfile other) return false; if (maybeOther is not HumanoidCharacterProfile other)
if (Name != other.Name) return false; return false;
if (ClownName != other.ClownName) return false;
if (MimeName != other.MimeName) return false; if (Name != other.Name)
if (BorgName != other.BorgName) return false; return false;
if (Age != other.Age) return false;
if (Sex != other.Sex) return false; if (ClownName != other.ClownName)
if (Gender != other.Gender) return false; return false;
if (PreferenceUnavailable != other.PreferenceUnavailable) return false;
if (Clothing != other.Clothing) return false; if (MimeName != other.MimeName)
if (Backpack != other.Backpack) return false; return false;
if (SpawnPriority != other.SpawnPriority) return false;
if (!_jobPriorities.SequenceEqual(other._jobPriorities)) return false; if (BorgName != other.BorgName)
if (!_antagPreferences.SequenceEqual(other._antagPreferences)) return false; return false;
if (!_traitPreferences.SequenceEqual(other._traitPreferences)) return false;
if (Age != other.Age)
return false;
if (Sex != other.Sex)
return false;
if (Gender != other.Gender)
return false;
if (BodyType != other.BodyType)
return false;
if (PreferenceUnavailable != other.PreferenceUnavailable)
return false;
if (Clothing != other.Clothing)
return false;
if (Backpack != other.Backpack)
return false;
if (SpawnPriority != other.SpawnPriority)
return false;
if (!_jobPriorities.SequenceEqual(other._jobPriorities))
return false;
if (!_antagPreferences.SequenceEqual(other._antagPreferences))
return false;
if (!_traitPreferences.SequenceEqual(other._traitPreferences))
return false;
return Appearance.MemberwiseEquals(other.Appearance); return Appearance.MemberwiseEquals(other.Appearance);
} }
@@ -448,10 +519,10 @@ namespace Content.Shared.Preferences
var sex = Sex switch var sex = Sex switch
{ {
Sex.Male => Sex.Male, Sex.Male => Sex.Male,
Sex.Female => Sex.Female, Sex.Female => Sex.Female,
Sex.Unsexed => Sex.Unsexed, Sex.Unsexed => Sex.Unsexed,
_ => Sex.Male // Invalid enum values. _ => Sex.Male // Invalid enum values.
}; };
// ensure the species can be that sex and their age fits the founds // ensure the species can be that sex and their age fits the founds
@@ -462,16 +533,24 @@ namespace Content.Shared.Preferences
{ {
sex = speciesPrototype.Sexes[0]; sex = speciesPrototype.Sexes[0];
} }
age = Math.Clamp(Age, speciesPrototype.MinAge, speciesPrototype.MaxAge); age = Math.Clamp(Age, speciesPrototype.MinAge, speciesPrototype.MaxAge);
if (!prototypeManager.TryIndex<BodyTypePrototype>(BodyType, out var bodyType) ||
!SharedHumanoidAppearanceSystem.IsBodyTypeValid(bodyType, speciesPrototype, Sex))
{
BodyType =
prototypeManager.Index<BodyTypePrototype>(SharedHumanoidAppearanceSystem.DefaultBodyType).ID;
}
} }
var gender = Gender switch var gender = Gender switch
{ {
Gender.Epicene => Gender.Epicene, Gender.Epicene => Gender.Epicene,
Gender.Female => Gender.Female, Gender.Female => Gender.Female,
Gender.Male => Gender.Male, Gender.Male => Gender.Male,
Gender.Neuter => Gender.Neuter, Gender.Neuter => Gender.Neuter,
_ => Gender.Epicene // Invalid enum values. _ => Gender.Epicene // Invalid enum values.
}; };
string name; string name;
@@ -490,6 +569,7 @@ namespace Content.Shared.Preferences
{ {
name = Name; name = Name;
} }
if (string.IsNullOrEmpty(ClownName)) if (string.IsNullOrEmpty(ClownName))
{ {
clownName = GetClownName(); clownName = GetClownName();
@@ -502,6 +582,7 @@ namespace Content.Shared.Preferences
{ {
clownName = ClownName; clownName = ClownName;
} }
if (string.IsNullOrEmpty(MimeName)) if (string.IsNullOrEmpty(MimeName))
{ {
mimeName = GetMimeName(); mimeName = GetMimeName();
@@ -514,6 +595,7 @@ namespace Content.Shared.Preferences
{ {
mimeName = MimeName; mimeName = MimeName;
} }
if (string.IsNullOrEmpty(BorgName)) if (string.IsNullOrEmpty(BorgName))
{ {
borgName = GetBorgName(); borgName = GetBorgName();
@@ -545,14 +627,17 @@ namespace Content.Shared.Preferences
{ {
// This regex replaces the first character of the first and last words of the name with their uppercase version // This regex replaces the first character of the first and last words of the name with their uppercase version
name = Regex.Replace(name, name = Regex.Replace(name,
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)", @"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper()); m => m.Groups["word"].Value.ToUpper());
clownName = Regex.Replace(clownName, clownName = Regex.Replace(clownName,
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)", @"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper()); m => m.Groups["word"].Value.ToUpper());
mimeName = Regex.Replace(mimeName, mimeName = Regex.Replace(mimeName,
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)", @"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper()); m => m.Groups["word"].Value.ToUpper());
borgName = Regex.Replace(borgName, borgName = Regex.Replace(borgName,
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)", @"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper()); m => m.Groups["word"].Value.ToUpper());
@@ -577,7 +662,7 @@ namespace Content.Shared.Preferences
} }
// WD-EDIT // WD-EDIT
var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, sponsorMarkings); var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, BodyType, sponsorMarkings);
// WD-EDIT // WD-EDIT
var prefsUnavailableMode = PreferenceUnavailable switch var prefsUnavailableMode = PreferenceUnavailable switch
@@ -589,35 +674,35 @@ namespace Content.Shared.Preferences
var clothing = Clothing switch var clothing = Clothing switch
{ {
ClothingPreference.Jumpsuit => ClothingPreference.Jumpsuit, ClothingPreference.Jumpsuit => ClothingPreference.Jumpsuit,
ClothingPreference.Jumpskirt => ClothingPreference.Jumpskirt, ClothingPreference.Jumpskirt => ClothingPreference.Jumpskirt,
_ => ClothingPreference.Jumpsuit // Invalid enum values. _ => ClothingPreference.Jumpsuit // Invalid enum values.
}; };
var backpack = Backpack switch var backpack = Backpack switch
{ {
BackpackPreference.Backpack => BackpackPreference.Backpack, BackpackPreference.Backpack => BackpackPreference.Backpack,
BackpackPreference.Satchel => BackpackPreference.Satchel, BackpackPreference.Satchel => BackpackPreference.Satchel,
BackpackPreference.Duffelbag => BackpackPreference.Duffelbag, BackpackPreference.Duffelbag => BackpackPreference.Duffelbag,
_ => BackpackPreference.Backpack // Invalid enum values. _ => BackpackPreference.Backpack // Invalid enum values.
}; };
var spawnPriority = SpawnPriority switch var spawnPriority = SpawnPriority switch
{ {
SpawnPriorityPreference.None => SpawnPriorityPreference.None, SpawnPriorityPreference.None => SpawnPriorityPreference.None,
SpawnPriorityPreference.Arrivals => SpawnPriorityPreference.Arrivals, SpawnPriorityPreference.Arrivals => SpawnPriorityPreference.Arrivals,
SpawnPriorityPreference.Cryosleep => SpawnPriorityPreference.Cryosleep, SpawnPriorityPreference.Cryosleep => SpawnPriorityPreference.Cryosleep,
_ => SpawnPriorityPreference.None // Invalid enum values. _ => SpawnPriorityPreference.None // Invalid enum values.
}; };
var priorities = new Dictionary<string, JobPriority>(JobPriorities var priorities = new Dictionary<string, JobPriority>(JobPriorities
.Where(p => prototypeManager.HasIndex<JobPrototype>(p.Key) && p.Value switch .Where(p => prototypeManager.HasIndex<JobPrototype>(p.Key) && p.Value switch
{ {
JobPriority.Never => false, // Drop never since that's assumed default. JobPriority.Never => false, // Drop never since that's assumed default.
JobPriority.Low => true, JobPriority.Low => true,
JobPriority.Medium => true, JobPriority.Medium => true,
JobPriority.High => true, JobPriority.High => true,
_ => false _ => false
})); }));
var antags = AntagPreferences var antags = AntagPreferences
@@ -625,8 +710,8 @@ namespace Content.Shared.Preferences
.ToList(); .ToList();
var traits = TraitPreferences var traits = TraitPreferences
.Where(prototypeManager.HasIndex<TraitPrototype>) .Where(prototypeManager.HasIndex<TraitPrototype>)
.ToList(); .ToList();
Name = name; Name = name;
ClownName = clownName; ClownName = clownName;

View File

@@ -37,15 +37,6 @@ marking-HumanHairBusiness3 = Business Hair 3
marking-HumanHairBusiness4 = Business Hair 4 marking-HumanHairBusiness4 = Business Hair 4
marking-HumanHairBuzzcut = Buzzcut marking-HumanHairBuzzcut = Buzzcut
marking-HumanHairCia = CIA marking-HumanHairCia = CIA
marking-HumanHairClassicAfro = Classic Afro
marking-HumanHairClassicBigAfro = Classic Big Afro
marking-HumanHairClassicBusiness = Classic Business Hair
marking-HumanHairClassicCia = Classic CIA
marking-HumanHairClassicCornrows2 = Classic Cornrows 2
marking-HumanHairClassicFloorlengthBedhead = Classic Floorlength Bedhead
marking-HumanHairClassicModern = Classic Modern
marking-HumanHairClassicMulder = Classic Mulder
marking-HumanHairClassicWisp = Classic Wisp
marking-HumanHairCoffeehouse = Coffee House marking-HumanHairCoffeehouse = Coffee House
marking-HumanHairCombover = Combover marking-HumanHairCombover = Combover
marking-HumanHairCornrows = Cornrows marking-HumanHairCornrows = Cornrows

View File

@@ -21,7 +21,7 @@
components: components:
- type: Sprite - type: Sprite
sprite: Mobs/Species/Human/parts.rsi sprite: Mobs/Species/Human/parts.rsi
state: "torso_m" state: "torso"
- type: Extractable - type: Extractable
juiceSolution: juiceSolution:
reagents: reagents:
@@ -30,6 +30,14 @@
- ReagentId: Blood - ReagentId: Blood
Quantity: 20 Quantity: 20
- type: entity
id: TorsoHumanSlim
name: "human torso"
parent: TorsoHuman
components:
- type: Sprite
state: "torso_slim"
- type: entity - type: entity
id: HeadHuman id: HeadHuman
name: "human head" name: "human head"
@@ -37,7 +45,7 @@
components: components:
- type: Sprite - type: Sprite
sprite: Mobs/Species/Human/parts.rsi sprite: Mobs/Species/Human/parts.rsi
state: "head_m" state: "head"
- type: Extractable - type: Extractable
juiceSolution: juiceSolution:
reagents: reagents:
@@ -46,6 +54,13 @@
- ReagentId: Blood - ReagentId: Blood
Quantity: 10 Quantity: 10
- type: entity
id: HeadHumanSlim
parent: HeadHuman
components:
- type: Sprite
state: "head_slim"
- type: entity - type: entity
id: LeftArmHuman id: LeftArmHuman
name: "left human arm" name: "left human arm"

View File

@@ -271,69 +271,6 @@
sprites: sprites:
- sprite: Mobs/Customization/human_hair.rsi - sprite: Mobs/Customization/human_hair.rsi
state: cia state: cia
- type: marking
id: HumanHairClassicAfro
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classicafro
- type: marking
id: HumanHairClassicBigAfro
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classicbigafro
- type: marking
id: HumanHairClassicBusiness
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classicbusiness
- type: marking
id: HumanHairClassicCia
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classiccia
- type: marking
id: HumanHairClassicCornrows2
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classiccornrows2
- type: marking
id: HumanHairClassicFloorlengthBedhead
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classicfloorlength_bedhead
- type: marking
id: HumanHairClassicModern
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classicmodern
- type: marking
id: HumanHairClassicMulder
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classicmulder
- type: marking
id: HumanHairClassicWisp
bodyPart: Hair
markingCategory: Hair
sprites:
- sprite: Mobs/Customization/human_hair.rsi
state: classicwisp
- type: marking - type: marking
id: HumanHairCoffeehouse id: HumanHairCoffeehouse
bodyPart: Hair bodyPart: Hair

View File

@@ -3,7 +3,8 @@
name: species-name-arachnid name: species-name-arachnid
roundStart: true roundStart: true
prototype: MobArachnid prototype: MobArachnid
sprites: MobArachnidSprites bodyTypes:
- ArachnidNormal
defaultSkinTone: "#385878" defaultSkinTone: "#385878"
markingLimits: MobArachnidMarkingLimits markingLimits: MobArachnidMarkingLimits
dollPrototype: MobArachnidDummy dollPrototype: MobArachnidDummy
@@ -15,25 +16,6 @@
sexes: sexes:
- Unsexed - Unsexed
- type: speciesBaseSprites
id: MobArachnidSprites
sprites:
Head: MobArachnidHead
Snout: MobHumanoidAnyMarking
Chest: MobArachnidTorso
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobHumanoidAnyMarking
LArm: MobArachnidLArm
RArm: MobArachnidRArm
LHand: MobArachnidLHand
RHand: MobArachnidRHand
LLeg: MobArachnidLLeg
RLeg: MobArachnidRLeg
LFoot: MobArachnidLFoot
RFoot: MobArachnidRFoot
- type: markingPoints - type: markingPoints
id: MobArachnidMarkingLimits id: MobArachnidMarkingLimits
onlyWhitelisted: true onlyWhitelisted: true

View File

@@ -3,7 +3,8 @@
name: species-name-diona name: species-name-diona
roundStart: true roundStart: true
prototype: MobDiona prototype: MobDiona
sprites: MobDionaSprites bodyTypes:
- DionaNormal
defaultSkinTone: "#cdb369" defaultSkinTone: "#cdb369"
markingLimits: MobDionaMarkingLimits markingLimits: MobDionaMarkingLimits
dollPrototype: MobDionaDummy dollPrototype: MobDionaDummy
@@ -14,23 +15,6 @@
femaleLastNames: DionaLast femaleLastNames: DionaLast
naming: TheFirstofLast naming: TheFirstofLast
- type: speciesBaseSprites
id: MobDionaSprites
sprites:
Head: MobDionaHead
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Chest: MobDionaTorso
Eyes: MobDionaEyes
LArm: MobDionaLArm
RArm: MobDionaRArm
LHand: MobDionaLHand
RHand: MobDionaRHand
LLeg: MobDionaLLeg
RLeg: MobDionaRLeg
LFoot: MobDionaLFoot
RFoot: MobDionaRFoot
- type: markingPoints - type: markingPoints
id: MobDionaMarkingLimits id: MobDionaMarkingLimits
onlyWhitelisted: true onlyWhitelisted: true

View File

@@ -3,7 +3,8 @@
name: species-name-dwarf name: species-name-dwarf
roundStart: true roundStart: true
prototype: MobDwarf prototype: MobDwarf
sprites: MobHumanSprites bodyTypes:
- HumanNormal
markingLimits: MobHumanMarkingLimits markingLimits: MobHumanMarkingLimits
dollPrototype: MobDwarfDummy dollPrototype: MobDwarfDummy
skinColoration: HumanToned skinColoration: HumanToned

View File

@@ -3,29 +3,13 @@
name: species-name-human name: species-name-human
roundStart: false roundStart: false
prototype: MobGingerbread prototype: MobGingerbread
sprites: MobGingerbreadSprites bodyTypes:
- GingerbreadNormal
markingLimits: MobHumanMarkingLimits markingLimits: MobHumanMarkingLimits
dollPrototype: MobGingerbreadDummy dollPrototype: MobGingerbreadDummy
skinColoration: HumanToned skinColoration: HumanToned
defaultSkinTone: "#9a7c5a" defaultSkinTone: "#9a7c5a"
- type: speciesBaseSprites
id: MobGingerbreadSprites
sprites:
Head: MobGingerbreadHead
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Chest: MobGingerbreadTorso
Eyes: MobGingerbreadEyes
LArm: MobGingerbreadLArm
RArm: MobGingerbreadRArm
LHand: MobGingerbreadLHand
RHand: MobGingerbreadRHand
LLeg: MobGingerbreadLLeg
RLeg: MobGingerbreadRLeg
LFoot: MobGingerbreadLFoot
RFoot: MobGingerbreadRFoot
- type: humanoidBaseSprite - type: humanoidBaseSprite
id: MobGingerbreadEyes id: MobGingerbreadEyes
baseSprite: baseSprite:

View File

@@ -3,7 +3,9 @@
name: species-name-human name: species-name-human
roundStart: true roundStart: true
prototype: MobHuman prototype: MobHuman
sprites: MobHumanSprites bodyTypes:
- HumanNormal
- HumanSlim
markingLimits: MobHumanMarkingLimits markingLimits: MobHumanMarkingLimits
dollPrototype: MobHumanDummy dollPrototype: MobHumanDummy
skinColoration: HumanToned skinColoration: HumanToned
@@ -14,24 +16,6 @@
# be defined as a 'custom base layer' # be defined as a 'custom base layer'
# in either the mob's starting marking prototype, # in either the mob's starting marking prototype,
# or it has to be added in C#. # or it has to be added in C#.
- type: speciesBaseSprites
id: MobHumanSprites
sprites:
Head: MobHumanHead
Hair: MobHumanoidAnyMarking
FacialHair: MobHumanoidAnyMarking
Chest: MobHumanTorso
HeadTop: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobHumanoidEyes
LArm: MobHumanLArm
RArm: MobHumanRArm
LHand: MobHumanLHand
RHand: MobHumanRHand
LLeg: MobHumanLLeg
RLeg: MobHumanRLeg
LFoot: MobHumanLFoot
RFoot: MobHumanRFoot
- type: markingPoints - type: markingPoints
id: MobHumanMarkingLimits id: MobHumanMarkingLimits
@@ -71,17 +55,12 @@
id: MobHumanoidMarkingMatchSkin id: MobHumanoidMarkingMatchSkin
markingsMatchSkin: true markingsMatchSkin: true
# Normal body type sprites
- type: humanoidBaseSprite - type: humanoidBaseSprite
id: MobHumanHead id: MobHumanHead
baseSprite: baseSprite:
sprite: Mobs/Species/Human/parts.rsi sprite: Mobs/Species/Human/parts.rsi
state: head_m state: head
- type: humanoidBaseSprite
id: MobHumanHeadMale
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: head_m
- type: humanoidBaseSprite - type: humanoidBaseSprite
id: MobHumanHeadFemale id: MobHumanHeadFemale
@@ -93,13 +72,7 @@
id: MobHumanTorso id: MobHumanTorso
baseSprite: baseSprite:
sprite: Mobs/Species/Human/parts.rsi sprite: Mobs/Species/Human/parts.rsi
state: torso_m state: torso
- type: humanoidBaseSprite
id: MobHumanTorsoMale
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: torso_m
- type: humanoidBaseSprite - type: humanoidBaseSprite
id: MobHumanTorsoFemale id: MobHumanTorsoFemale
@@ -154,3 +127,77 @@
baseSprite: baseSprite:
sprite: Mobs/Species/Human/parts.rsi sprite: Mobs/Species/Human/parts.rsi
state: r_foot state: r_foot
# Slim types
- type: humanoidBaseSprite
id: MobHumanSlimHead
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: head_slim
- type: humanoidBaseSprite
id: MobHumanSlimHeadFemale
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: head_slim_f
- type: humanoidBaseSprite
id: MobHumanSlimTorso
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: torso_slim
- type: humanoidBaseSprite
id: MobHumanSlimTorsoFemale
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: torso_slim_f
- type: humanoidBaseSprite
id: MobHumanSlimLLeg
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: l_leg_slim
- type: humanoidBaseSprite
id: MobHumanSlimLArm
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: l_arm_slim
- type: humanoidBaseSprite
id: MobHumanSlimLHand
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: l_hand_slim
- type: humanoidBaseSprite
id: MobHumanSlimLFoot
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: l_foot_slim
- type: humanoidBaseSprite
id: MobHumanSlimRLeg
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: r_leg_slim
- type: humanoidBaseSprite
id: MobHumanSlimRArm
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: r_arm_slim
- type: humanoidBaseSprite
id: MobHumanSlimRHand
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: r_hand_slim
- type: humanoidBaseSprite
id: MobHumanSlimRFoot
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: r_foot_slim

View File

@@ -3,7 +3,8 @@
name: species-name-moth name: species-name-moth
roundStart: true roundStart: true
prototype: MobMoth prototype: MobMoth
sprites: MobMothSprites bodyTypes:
- MothNormal
defaultSkinTone: "#ffda93" defaultSkinTone: "#ffda93"
markingLimits: MobMothMarkingLimits markingLimits: MobMothMarkingLimits
dollPrototype: MobMothDummy dollPrototype: MobMothDummy
@@ -12,25 +13,6 @@
femaleFirstNames: names_moth_first_female femaleFirstNames: names_moth_first_female
lastNames: names_moth_last lastNames: names_moth_last
- type: speciesBaseSprites
id: MobMothSprites
sprites:
Head: MobMothHead
Snout: MobHumanoidAnyMarking
Chest: MobMothTorso
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobMothEyes
LArm: MobMothLArm
RArm: MobMothRArm
LHand: MobMothLHand
RHand: MobMothRHand
LLeg: MobMothLLeg
RLeg: MobMothRLeg
LFoot: MobMothLFoot
RFoot: MobMothRFoot
- type: humanoidBaseSprite - type: humanoidBaseSprite
id: MobMothEyes id: MobMothEyes
baseSprite: baseSprite:

View File

@@ -3,7 +3,8 @@
name: species-name-reptilian name: species-name-reptilian
roundStart: true roundStart: true
prototype: MobReptilian prototype: MobReptilian
sprites: MobReptilianSprites bodyTypes:
- ReptilianNormal
defaultSkinTone: "#34a223" defaultSkinTone: "#34a223"
markingLimits: MobReptilianMarkingLimits markingLimits: MobReptilianMarkingLimits
dollPrototype: MobReptilianDummy dollPrototype: MobReptilianDummy
@@ -12,24 +13,6 @@
femaleFirstNames: names_reptilian_female femaleFirstNames: names_reptilian_female
naming: FirstDashFirst naming: FirstDashFirst
- type: speciesBaseSprites
id: MobReptilianSprites
sprites:
Head: MobReptilianHead
Snout: MobHumanoidAnyMarking
Chest: MobReptilianTorso
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobHumanoidEyes
LArm: MobReptilianLArm
RArm: MobReptilianRArm
LHand: MobReptilianLHand
RHand: MobReptilianRHand
LLeg: MobReptilianLLeg
RLeg: MobReptilianRLeg
LFoot: MobReptilianLFoot
RFoot: MobReptilianRFoot
- type: markingPoints - type: markingPoints
id: MobReptilianMarkingLimits id: MobReptilianMarkingLimits

View File

@@ -3,7 +3,8 @@
name: species-name-skeleton name: species-name-skeleton
roundStart: false roundStart: false
prototype: MobSkeletonPerson prototype: MobSkeletonPerson
sprites: MobSkeletonSprites bodyTypes:
- SkeletonNormal
defaultSkinTone: "#fff9e2" defaultSkinTone: "#fff9e2"
markingLimits: MobHumanMarkingLimits markingLimits: MobHumanMarkingLimits
maleFirstNames: skeletonNamesFirst maleFirstNames: skeletonNamesFirst
@@ -11,20 +12,6 @@
dollPrototype: MobSkeletonPersonDummy dollPrototype: MobSkeletonPersonDummy
skinColoration: TintedHues skinColoration: TintedHues
- type: speciesBaseSprites
id: MobSkeletonSprites
sprites:
Head: MobSkeletonHead
Chest: MobSkeletonTorso
LArm: MobSkeletonLArm
RArm: MobSkeletonRArm
LHand: MobSkeletonLHand
RHand: MobSkeletonRHand
LLeg: MobSkeletonLLeg
RLeg: MobSkeletonRLeg
LFoot: MobSkeletonLFoot
RFoot: MobSkeletonRFoot
- type: humanoidBaseSprite - type: humanoidBaseSprite
id: MobSkeletonHead id: MobSkeletonHead
baseSprite: baseSprite:

View File

@@ -3,29 +3,13 @@
name: species-name-slime name: species-name-slime
roundStart: true roundStart: true
prototype: MobSlimePerson prototype: MobSlimePerson
sprites: MobSlimeSprites bodyTypes:
- SlimeNormal
defaultSkinTone: "#b8b8b8" defaultSkinTone: "#b8b8b8"
markingLimits: MobSlimeMarkingLimits markingLimits: MobSlimeMarkingLimits
dollPrototype: MobSlimePersonDummy dollPrototype: MobSlimePersonDummy
skinColoration: Hues skinColoration: Hues
- type: speciesBaseSprites
id: MobSlimeSprites
sprites:
Head: MobSlimeHead
Hair: MobSlimeMarkingFollowSkin
FacialHair: MobSlimeMarkingFollowSkin
Chest: MobSlimeTorso
Eyes: MobHumanoidEyes
LArm: MobSlimeLArm
RArm: MobSlimeRArm
LHand: MobSlimeLHand
RHand: MobSlimeRHand
LLeg: MobSlimeLLeg
RLeg: MobSlimeRLeg
LFoot: MobSlimeLFoot
RFoot: MobSlimeRFoot
- type: markingPoints - type: markingPoints
id: MobSlimeMarkingLimits id: MobSlimeMarkingLimits
points: points:

View File

@@ -3,7 +3,8 @@
name: Terminator name: Terminator
roundStart: false roundStart: false
prototype: MobTerminatorEndoskeleton prototype: MobTerminatorEndoskeleton
sprites: MobTerminatorSprites bodyTypes:
- TerminatorNormal
defaultSkinTone: "#fff9e2" defaultSkinTone: "#fff9e2"
markingLimits: MobHumanMarkingLimits markingLimits: MobHumanMarkingLimits
maleFirstNames: skeletonNamesFirst maleFirstNames: skeletonNamesFirst
@@ -11,19 +12,6 @@
dollPrototype: MobSkeletonPersonDummy dollPrototype: MobSkeletonPersonDummy
skinColoration: TintedHues skinColoration: TintedHues
- type: speciesBaseSprites
id: MobTerminatorSprites
sprites:
Head: MobTerminatorHead
Chest: MobTerminatorTorso
LArm: MobTerminatorLArm
RArm: MobTerminatorRArm
LHand: MobTerminatorLHand
RHand: MobTerminatorRHand
LLeg: MobTerminatorLLeg
RLeg: MobTerminatorRLeg
LFoot: MobTerminatorLFoot
RFoot: MobTerminatorRFoot
- type: humanoidBaseSprite - type: humanoidBaseSprite
id: MobTerminatorHead id: MobTerminatorHead

View File

@@ -3,7 +3,8 @@
name: species-name-vox name: species-name-vox
roundStart: false # sad... roundStart: false # sad...
prototype: MobVox prototype: MobVox
sprites: MobVoxSprites bodyTypes:
- VoxNormal
markingLimits: MobVoxMarkingLimits markingLimits: MobVoxMarkingLimits
dollPrototype: MobVoxDummy dollPrototype: MobVoxDummy
skinColoration: Hues skinColoration: Hues
@@ -14,23 +15,6 @@
- Unsexed - Unsexed
- type: speciesBaseSprites
id: MobVoxSprites
sprites:
Head: MobVoxHead
Hair: MobHumanoidAnyMarking
FacialHair: MobHumanoidAnyMarking
Chest: MobVoxTorso
Eyes: MobVoxEyes
LArm: MobVoxLArm
RArm: MobVoxRArm
LHand: MobVoxLHand
RHand: MobVoxRHand
LLeg: MobVoxLLeg
RLeg: MobVoxRLeg
LFoot: MobVoxLFoot
RFoot: MobVoxRFoot
- type: markingPoints - type: markingPoints
id: MobVoxMarkingLimits id: MobVoxMarkingLimits
onlyWhitelisted: true onlyWhitelisted: true

View File

@@ -0,0 +1,180 @@
- type: bodyType
id: HumanNormal
name: body-normal
sprites:
Head: MobHumanHead
Hair: MobHumanoidAnyMarking
FacialHair: MobHumanoidAnyMarking
Chest: MobHumanTorso
HeadTop: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobHumanoidEyes
LArm: MobHumanLArm
RArm: MobHumanRArm
LHand: MobHumanLHand
RHand: MobHumanRHand
LLeg: MobHumanLLeg
RLeg: MobHumanRLeg
LFoot: MobHumanLFoot
RFoot: MobHumanRFoot
- type: bodyType
id: ReptilianNormal
name: body-normal
sprites:
Head: MobReptilianHead
Snout: MobHumanoidAnyMarking
Chest: MobReptilianTorso
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobHumanoidEyes
LArm: MobReptilianLArm
RArm: MobReptilianRArm
LHand: MobReptilianLHand
RHand: MobReptilianRHand
LLeg: MobReptilianLLeg
RLeg: MobReptilianRLeg
LFoot: MobReptilianLFoot
RFoot: MobReptilianRFoot
- type: bodyType
id: SkeletonNormal
name: body-normal
sprites:
Head: MobSkeletonHead
Chest: MobSkeletonTorso
LArm: MobSkeletonLArm
RArm: MobSkeletonRArm
LHand: MobSkeletonLHand
RHand: MobSkeletonRHand
LLeg: MobSkeletonLLeg
RLeg: MobSkeletonRLeg
LFoot: MobSkeletonLFoot
RFoot: MobSkeletonRFoot
- type: bodyType
id: SlimeNormal
name: body-normal
sprites:
Head: MobSlimeHead
Hair: MobSlimeMarkingFollowSkin
FacialHair: MobSlimeMarkingFollowSkin
Chest: MobSlimeTorso
Eyes: MobHumanoidEyes
LArm: MobSlimeLArm
RArm: MobSlimeRArm
LHand: MobSlimeLHand
RHand: MobSlimeRHand
LLeg: MobSlimeLLeg
RLeg: MobSlimeRLeg
LFoot: MobSlimeLFoot
RFoot: MobSlimeRFoot
- type: bodyType
id: VoxNormal
name: body-normal
sprites:
Head: MobVoxHead
Hair: MobHumanoidAnyMarking
FacialHair: MobHumanoidAnyMarking
Chest: MobVoxTorso
Eyes: MobVoxEyes
LArm: MobVoxLArm
RArm: MobVoxRArm
LHand: MobVoxLHand
RHand: MobVoxRHand
LLeg: MobVoxLLeg
RLeg: MobVoxRLeg
LFoot: MobVoxLFoot
RFoot: MobVoxRFoot
- type: bodyType
id: DionaNormal
name: body-normal
sprites:
Head: MobDionaHead
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Chest: MobDionaTorso
LArm: MobDionaLArm
RArm: MobDionaRArm
LHand: MobDionaLHand
RHand: MobDionaRHand
LLeg: MobDionaLLeg
RLeg: MobDionaRLeg
LFoot: MobDionaLFoot
RFoot: MobDionaRFoot
- type: bodyType
id: ArachnidNormal
name: body-normal
sprites:
Head: MobArachnidHead
Snout: MobHumanoidAnyMarking
Chest: MobArachnidTorso
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobArachnidEyes
LArm: MobArachnidLArm
RArm: MobArachnidRArm
LHand: MobArachnidLHand
RHand: MobArachnidRHand
LLeg: MobArachnidLLeg
RLeg: MobArachnidRLeg
LFoot: MobArachnidLFoot
RFoot: MobArachnidRFoot
- type: bodyType
id: TerminatorNormal
name: body-normal
sprites:
Head: MobTerminatorHead
Chest: MobTerminatorTorso
LArm: MobTerminatorLArm
RArm: MobTerminatorRArm
LHand: MobTerminatorLHand
RHand: MobTerminatorRHand
LLeg: MobTerminatorLLeg
RLeg: MobTerminatorRLeg
LFoot: MobTerminatorLFoot
RFoot: MobTerminatorRFoot
- type: bodyType
id: GingerbreadNormal
name: body-normal
sprites:
Head: MobGingerbreadHead
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Chest: MobGingerbreadTorso
Eyes: MobGingerbreadEyes
LArm: MobGingerbreadLArm
RArm: MobGingerbreadRArm
LHand: MobGingerbreadLHand
RHand: MobGingerbreadRHand
LLeg: MobGingerbreadLLeg
RLeg: MobGingerbreadRLeg
LFoot: MobGingerbreadLFoot
RFoot: MobGingerbreadRFoot
- type: bodyType
id: MothNormal
name: body-normal
sprites:
Head: MobMothHead
Snout: MobHumanoidAnyMarking
Chest: MobMothTorso
HeadTop: MobHumanoidAnyMarking
HeadSide: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobMothEyes
LArm: MobMothLArm
RArm: MobMothRArm
LHand: MobMothLHand
RHand: MobMothRHand
LLeg: MobMothLLeg
RLeg: MobMothRLeg
LFoot: MobMothLFoot
RFoot: MobMothRFoot

View File

@@ -0,0 +1,43 @@
- type: bodyType
id: HumanSlim
name: body-slim
sexRestrictions:
- Male
sprites:
Head: MobHumanSlimHead
Hair: MobHumanoidAnyMarking
FacialHair: MobHumanoidAnyMarking
Chest: MobHumanSlimTorso
HeadTop: MobHumanoidAnyMarking
Tail: MobHumanoidAnyMarking
Eyes: MobHumanoidEyes
LArm: MobHumanSlimLArm
RArm: MobHumanSlimRArm
LHand: MobHumanSlimLHand
RHand: MobHumanSlimRHand
LLeg: MobHumanSlimLLeg
RLeg: MobHumanSlimRLeg
LFoot: MobHumanSlimLFoot
RFoot: MobHumanSlimRFoot
# - type: bodyType
# id: ReptilianSlim
# name: body-slim
# sexRestrictions:
# - Male
# sprites:
# Head: MobReptilianSlimHead
# Snout: MobHumanoidAnyMarking
# Chest: MobReptilianSlimTorso
# HeadTop: MobHumanoidAnyMarking
# HeadSide: MobHumanoidAnyMarking
# Tail: MobHumanoidAnyMarking
# Eyes: MobHumanoidEyes
# LArm: MobReptilianSlimLArm
# RArm: MobReptilianSlimRArm
# LHand: MobReptilianSlimLHand
# RHand: MobReptilianSlimRHand
# LLeg: MobReptilianSlimLLeg
# RLeg: MobReptilianSlimRLeg
# LFoot: MobReptilianSlimLFoot
# RFoot: MobReptilianSlimRFoot

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "equipped-HAND-kangaroo", "name": "equipped-HAND-kangaroo",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "equipped-HAND-kangaroo", "name": "equipped-HAND-kangaroo",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "equipped-HAND-kangaroo", "name": "equipped-HAND-kangaroo",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "equipped-HAND-kangaroo", "name": "equipped-HAND-kangaroo",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1 +1,35 @@
{"version": 1, "license": "CC-BY-SA-3.0", "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", "size": {"x": 32, "y": 32}, "states": [{"name": "icon"}, {"name": "equipped-HAND", "directions": 4}, {"name": "inhand-left", "directions": 4}, {"name": "inhand-right", "directions": 4}, {"name": "equipped-HAND-vox", "directions": 4}]} {
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "equipped-HAND",
"directions": 4
},
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
},
{
"name": "equipped-HAND-vox",
"directions": 4,
"delays": [[1.0], [1.0], [1.0], [1.0]]
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -17,10 +17,18 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "on-equipped-HAND", "name": "on-equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "on-equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND", "name": "equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -28,6 +28,18 @@
"name": "green-equipped-HAND", "name": "green-equipped-HAND",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{
"name": "red-equipped-HAND-body-slim",
"directions": 4
},
{
"name": "green-equipped-HAND-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-OUTERCLOTHING", "name": "equipped-OUTERCLOTHING",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-OUTERCLOTHING-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

View File

@@ -14,6 +14,10 @@
"name": "equipped-OUTERCLOTHING", "name": "equipped-OUTERCLOTHING",
"directions": 4 "directions": 4
}, },
{
"name": "equipped-OUTERCLOTHING-body-slim",
"directions": 4
},
{ {
"name": "inhand-left", "name": "inhand-left",
"directions": 4 "directions": 4

Some files were not shown because too many files have changed in this diff Show More