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

View File

@@ -42,9 +42,8 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
component.BaseLayers.Clear();
// add default species layers
var speciesProto = _prototypeManager.Index(component.Species);
var baseSprites = _prototypeManager.Index<HumanoidSpeciesBaseSpritesPrototype>(speciesProto.SpriteSet);
foreach (var (key, id) in baseSprites.Sprites)
var bodyTypeProto = _prototypeManager.Index<BodyTypePrototype>(component.BodyType);
foreach (var (key, id) in bodyTypeProto.Sprites)
{
oldLayers.Remove(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
/// override this with the appearance data it sends over.
/// </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))
{
return;
}
humanoid.BodyType = profile.BodyType;
var customBaseLayers = new Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo>();
var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(profile.Species);
@@ -142,15 +145,19 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
//markings.RemoveCategory(MarkingCategories.FacialHair);
// 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.HairColor;
var hair = new Marking(profile.Appearance.HairStyleId,
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.FacialHairColor;
var facialHair = new Marking(profile.Appearance.FacialHairStyleId,
new[] { facialHairColor });
@@ -158,6 +165,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
{
markings.AddBack(MarkingCategories.Hair, hair);
}
if (_markingManager.CanBeApplied(profile.Species, profile.Sex, facialHair, _prototypeManager))
{
markings.AddBack(MarkingCategories.FacialHair, facialHair);
@@ -172,10 +180,13 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
profile.Appearance.EyeColor,
markings
);
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.EnsureDefault(
profile.Appearance.SkinColor,
@@ -190,6 +201,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
humanoid.CustomBaseLayers = customBaseLayers;
humanoid.Sex = profile.Sex;
humanoid.Gender = profile.Gender;
humanoid.BodyType = profile.BodyType;
humanoid.Age = profile.Age;
humanoid.Species = profile.Species;
humanoid.SkinColor = profile.Appearance.SkinColor;
@@ -261,7 +273,9 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
spriteComp.RemoveLayer(index);
}
}
private void ApplyMarking(MarkingPrototype markingPrototype,
private void ApplyMarking(
MarkingPrototype markingPrototype,
IReadOnlyList<Color>? colors,
bool visible,
HumanoidAppearanceComponent humanoid,
@@ -274,7 +288,7 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
visible &= !IsHidden(humanoid, markingPrototype.BodyPart);
visible &= humanoid.BaseLayers.TryGetValue(markingPrototype.BodyPart, out var setting)
&& setting.AllowsMarkings;
&& setting.AllowsMarkings;
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)
return;
@@ -366,7 +385,8 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
{
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);
}
}

View File

@@ -40,7 +40,7 @@ public sealed class HumanoidMarkingModifierBoundUserInterface : BoundUserInterfa
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)

View File

@@ -59,10 +59,12 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
string? state = _protoMan.HasIndex<HumanoidSpeciesSpriteLayer>(modifier.Text) ? modifier.Text : null;
OnLayerInfoModified?.Invoke(layer, new CustomBaseLayerInfo(state, modifier.Color));
}
public void SetState(
MarkingSet markings,
string species,
Sex sex,
string bodyType,
Color skinColor,
Dictionary<HumanoidVisualLayers, CustomBaseLayerInfo> info
)
@@ -84,7 +86,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
eyesColor = eyes.Color.Value;
}
MarkingPickerWidget.SetData(markings, species, sex, skinColor, eyesColor);
MarkingPickerWidget.SetData(markings, species, sex, bodyType, skinColor, eyesColor);
}
private sealed class HumanoidBaseLayerModifier : BoxContainer
@@ -95,7 +97,9 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
private BoxContainer _infoBox;
public bool Enabled => _enable.Pressed;
public string Text => _lineEdit.Text;
public Color Color => _colorSliders.Color;
public Action? OnStateChanged;
@@ -109,6 +113,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
MinWidth = 250,
HorizontalExpand = true
};
AddChild(labelBox);
labelBox.AddChild(new Label
@@ -116,6 +121,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
HorizontalExpand = true,
Text = layer.ToString()
});
_enable = new CheckBox
{
Text = "Enable",
@@ -128,6 +134,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
Orientation = LayoutOrientation.Vertical,
Visible = false
};
_enable.OnToggled += args =>
{
_infoBox.Visible = args.Pressed;
@@ -135,7 +142,7 @@ public sealed partial class HumanoidMarkingModifierWindow : DefaultWindow
};
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.
_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 string _currentSpecies = SharedHumanoidAppearanceSystem.DefaultSpecies;
private string _currentBodyType = SharedHumanoidAppearanceSystem.DefaultBodyType;
private Sex _currentSex = Sex.Unsexed;
public Color CurrentSkinColor = Color.White;
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
.Index<SpeciesPrototype>(species).MarkingPoints;
@@ -91,7 +92,7 @@ public sealed partial class MarkingPicker : Control
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;
@@ -103,13 +104,13 @@ public sealed partial class MarkingPicker : Control
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;
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;
@@ -234,7 +235,7 @@ public sealed partial class MarkingPicker : Control
if (!IgnoreSpecies)
{
_currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager);
_currentMarkings.EnsureSpecies(_currentSpecies, _currentBodyType, null, _markingManager);
}
// walk backwards through the list for visual purposes
@@ -338,7 +339,7 @@ public sealed partial class MarkingPicker : Control
var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(species);
_currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager);
_currentMarkings.EnsureSpecies(species, null, _markingManager);
_currentMarkings.EnsureSpecies(species, _currentBodyType, null, _markingManager);
_currentMarkings.EnsureSexes(_currentSex, _markingManager);
Populate(CMarkingSearch.Text);
@@ -353,7 +354,7 @@ public sealed partial class MarkingPicker : Control
var speciesPrototype = _prototypeManager.Index<SpeciesPrototype>(_currentSpecies);
_currentMarkings = new(markingList, speciesPrototype.MarkingPoints, _markingManager, _prototypeManager);
_currentMarkings.EnsureSpecies(_currentSpecies, null, _markingManager);
_currentMarkings.EnsureSpecies(_currentSpecies, _currentBodyType, null, _markingManager);
_currentMarkings.EnsureSexes(_currentSex, _markingManager);
Populate(CMarkingSearch.Text);

View File

@@ -75,6 +75,12 @@
<Control HorizontalExpand="True"/>
<OptionButton Name="CSpeciesButton" HorizontalAlignment="Right" />
</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 -->
<BoxContainer HorizontalExpand="True">
<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.Markings;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Inventory;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Content.Shared.StatusIcon;
using Content.Shared.Traits;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@@ -29,10 +27,8 @@ using Robust.Client.UserInterface.XAML;
using Robust.Client.Utility;
using Robust.Shared.Configuration;
using Robust.Shared.Enums;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using static Robust.Client.UserInterface.Controls.BoxContainer;
@@ -44,7 +40,7 @@ namespace Content.Client.Preferences.UI
{
public HighlightedContainer()
{
PanelOverride = new StyleBoxFlat()
PanelOverride = new StyleBoxFlat
{
BackgroundColor = new Color(25, 25, 25),
ContentMarginTopOverride = 10,
@@ -110,6 +106,7 @@ namespace Content.Client.Preferences.UI
private readonly List<SpeciesPrototype> _speciesList;
private readonly List<AntagPreferenceSelector> _antagPreferences;
private readonly List<TraitPreferenceSelector> _traitPreferences;
private List<BodyTypePrototype> _bodyTypesList = new();
private SpriteView _previewSpriteView => CSpriteView;
private Button _previewRotateLeftButton => CSpriteRotateLeft;
@@ -177,6 +174,14 @@ namespace Content.Client.Preferences.UI
#endregion Sex
#region Body Type
CBodyTypesButton.OnItemSelected += OnBodyTypeSelected;
UpdateBodyTypes();
#endregion Body Type
#region Age
_ageEdit.OnTextChanged += args =>
@@ -845,6 +850,7 @@ namespace Content.Client.Preferences.UI
CMarkings.SetSpecies(newSpecies); // Repopulate the markings tab as well.
UpdateSexControls(); // update sex for new species
RebuildSpriteView(); // they might have different inv so we need a new dummy
UpdateBodyTypes();
IsDirty = 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
{
get => _isDirty;
@@ -1025,7 +1063,7 @@ namespace Content.Client.Preferences.UI
}
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
{
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
{
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(
@@ -1124,7 +1162,7 @@ namespace Content.Client.Preferences.UI
{
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;
}
@@ -1136,7 +1174,7 @@ namespace Content.Client.Preferences.UI
}
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
{
@@ -1159,7 +1197,7 @@ namespace Content.Client.Preferences.UI
{
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;
}
@@ -1171,7 +1209,7 @@ namespace Content.Client.Preferences.UI
}
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
{
@@ -1237,6 +1275,7 @@ namespace Content.Client.Preferences.UI
//WD-EDIT
UpdateTTSVoicesControls();
UpdateBodyTypes();
//WD-EDIT
_preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable);
@@ -1299,6 +1338,14 @@ namespace Content.Client.Preferences.UI
return allowedSpecies;
}
private void SetBodyType(string newBodyType)
{
Profile = Profile?.WithBodyType(newBodyType);
IsDirty = true;
_needUpdatePreview = true;
}
//WD EDIT END
private void UpdateJobPriorities()
@@ -1337,7 +1384,7 @@ namespace Content.Client.Preferences.UI
Options.OnItemSelected += args => Options.Select(args.Id);
_requirementsLabel = new Label()
_requirementsLabel = new Label
{
Text = Loc.GetString("role-timer-locked"),
Visible = true,
@@ -1345,7 +1392,7 @@ namespace Content.Client.Preferences.UI
StyleClasses = {StyleBase.StyleClassLabelSubText},
};
_lockStripe = new StripeBack()
_lockStripe = new StripeBack
{
Visible = false,
HorizontalExpand = true,
@@ -1369,7 +1416,7 @@ namespace Content.Client.Preferences.UI
Options.AddItem(Loc.GetString(text), value);
}
var titleLabel = new Label()
var titleLabel = new Label
{
Margin = new Thickness(5f, 0, 5f, 0),
Text = title,

View File

@@ -11,7 +11,6 @@ using Robust.Shared.Enums;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.UnitTesting;
namespace Content.IntegrationTests.Tests.Preferences
@@ -49,6 +48,7 @@ namespace Content.IntegrationTests.Tests.Preferences
21,
Sex.Male,
Gender.Epicene,
"Normal",
new HumanoidCharacterAppearance(
"Afro",
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")
.HasColumnName("backpack");
b.Property<string>("BodyType")
.IsRequired()
.HasColumnType("text")
.HasColumnName("body_type");
b.Property<string>("BorgName")
.IsRequired()
.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")
.HasColumnName("backpack");
b.Property<string>("BodyType")
.IsRequired()
.HasColumnType("TEXT")
.HasColumnName("body_type");
b.Property<string>("BorgName")
.IsRequired()
.HasColumnType("TEXT")

View File

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

View File

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

View File

@@ -29,7 +29,7 @@ public sealed partial class HumanoidAppearanceSystem
{
Text = "Modify markings",
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 = () =>
{
_uiSystem.TryOpen(uid, HumanoidMarkingModifierKey.Key, actor.PlayerSession);
@@ -37,6 +37,7 @@ public sealed partial class HumanoidAppearanceSystem
uid,
HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.BodyType,
component.Sex,
component.SkinColor,
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)
{
if (message.Session is not { } player
@@ -63,7 +66,7 @@ public sealed partial class HumanoidAppearanceSystem
component.CustomBaseLayers[message.Layer] = message.Info.Value;
}
Dirty(component);
Dirty(uid, component);
if (message.ResendState)
{
@@ -71,14 +74,17 @@ public sealed partial class HumanoidAppearanceSystem
uid,
HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.Sex,
component.SkinColor,
component.CustomBaseLayers
));
component.BodyType,
component.Sex,
component.SkinColor,
component.CustomBaseLayers
));
}
}
private void OnMarkingsSet(EntityUid uid, HumanoidAppearanceComponent component,
private void OnMarkingsSet(
EntityUid uid,
HumanoidAppearanceComponent component,
HumanoidMarkingModifierMarkingSetMessage message)
{
if (message.Session is not { } player
@@ -88,7 +94,7 @@ public sealed partial class HumanoidAppearanceSystem
}
component.MarkingSet = message.MarkingSet;
Dirty(component);
Dirty(uid, component);
if (message.ResendState)
{
@@ -96,11 +102,11 @@ public sealed partial class HumanoidAppearanceSystem
uid,
HumanoidMarkingModifierKey.Key,
new HumanoidMarkingModifierState(component.MarkingSet, component.Species,
component.Sex,
component.SkinColor,
component.CustomBaseLayers
));
component.BodyType,
component.Sex,
component.SkinColor,
component.CustomBaseLayers
));
}
}
}

View File

@@ -1,4 +1,3 @@
using System.Linq;
using Content.Shared.Examine;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
@@ -27,11 +26,12 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
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 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>
@@ -40,7 +40,10 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="uid">The mob's entity UID.</param>
/// <param name="profile">The character profile to load.</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))
{
@@ -51,6 +54,8 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
SetSex(uid, profile.Sex, false, humanoid);
humanoid.EyeColor = profile.Appearance.EyeColor;
SetBodyType(uid, profile.BodyType, false, humanoid);
SetSkinColor(uid, profile.Appearance.SkinColor, false);
humanoid.MarkingSet.Clear();
@@ -74,10 +79,15 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
// 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
var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha, _prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(hairAlpha) : profile.Appearance.HairColor;
var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, out var facialHairAlpha, _prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor;
var hairColor = _markingManager.MustMatchSkin(profile.BodyType, HumanoidVisualLayers.Hair, out var hairAlpha,
_prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(hairAlpha)
: 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) &&
_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) &&
_markingManager.CanBeApplied(profile.Species,profile.Sex, facialHairPrototype, _prototypeManager))
_markingManager.CanBeApplied(profile.Species, profile.Sex, facialHairPrototype, _prototypeManager))
{
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
foreach (var (marking, prototype) in markingFColored)
@@ -102,6 +114,7 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
profile.Appearance.EyeColor,
humanoid.MarkingSet
);
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="sourceHumanoid">Source 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)
{
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);
targetHumanoid.CustomBaseLayers = new(sourceHumanoid.CustomBaseLayers);
targetHumanoid.MarkingSet = new(sourceHumanoid.MarkingSet);
targetHumanoid.BodyType = sourceHumanoid.BodyType;
SetTTSVoice(target, sourceHumanoid.Voice, targetHumanoid);
targetHumanoid.Gender = sourceHumanoid.Gender;
if (TryComp<GrammarComponent>(target, out var grammar))
@@ -153,6 +171,32 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
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>
/// Adds a marking to this humanoid.
/// </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="forced">If this marking was forced (ignores marking points)</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)
|| !_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="forced">If this marking was forced (ignores marking points)</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)
|| !_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="sync">Whether to immediately sync this to the humanoid</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)
|| !_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="index">Index of the marking</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
|| !Resolve(uid, ref humanoid)
@@ -261,7 +325,12 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// <param name="index">Index of the marking</param>
/// <param name="markingId">The marking ID to use</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
|| !_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="colors">The marking colors to use</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)
{
if (index < 0
@@ -314,37 +387,24 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
/// </summary>
public string GetSpeciesRepresentation(string speciesId)
{
if (_prototypeManager.TryIndex<SpeciesPrototype>(speciesId, out var species))
{
return Loc.GetString(species.Name);
}
else
{
return Loc.GetString("humanoid-appearance-component-unknown-species");
}
return Loc.GetString(_prototypeManager.TryIndex<SpeciesPrototype>(speciesId, out var species)
? species.Name
: "humanoid-appearance-component-unknown-species");
}
public string GetAgeRepresentation(string species, int age)
{
_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 Loc.GetString("identity-age-young");
return age < speciesPrototype.YoungAge
? Loc.GetString("identity-age-young")
: Loc.GetString(age < speciesPrototype.OldAge ? "identity-age-middle-aged" : "identity-age-old");
}
if (age < speciesPrototype.YoungAge)
{
return Loc.GetString("identity-age-young");
}
if (age < speciesPrototype.OldAge)
{
return Loc.GetString("identity-age-middle-aged");
}
return Loc.GetString("identity-age-old");
Logger.Error("Tried to get age representation of species that couldn't be indexed: " + species);
return Loc.GetString("identity-age-young");
}
private void EnsureDefaultMarkings(EntityUid uid, HumanoidAppearanceComponent? humanoid)
@@ -353,6 +413,7 @@ public sealed partial class HumanoidAppearanceSystem : SharedHumanoidAppearanceS
{
return;
}
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._White.Sponsors;
using Content.Shared.CCVar;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences;
using Content.Shared.Roles;
@@ -16,7 +17,6 @@ using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Server.Preferences.Managers
{
/// <summary>
@@ -90,6 +90,7 @@ namespace Content.Server.Preferences.Managers
{
Logger.WarningS("prefs",
$"User {userId} sent a {nameof(MsgUpdateCharacter)} with a null profile in slot {slot}.");
return;
}
@@ -107,7 +108,9 @@ namespace Content.Server.Preferences.Managers
var curPrefs = prefsData.Prefs!;
// 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;
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);
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))
{
@@ -193,7 +197,7 @@ namespace Content.Server.Preferences.Managers
{
PrefsLoaded = true,
Prefs = new PlayerPreferences(
new[] {new KeyValuePair<int, ICharacterProfile>(0, HumanoidCharacterProfile.Random())},
new[] { new KeyValuePair<int, ICharacterProfile>(0, HumanoidCharacterProfile.Random()) },
0, Color.Transparent)
};
@@ -214,8 +218,13 @@ namespace Content.Server.Preferences.Managers
// WD-EDIT
foreach (var (_, profile) in prefs.Characters)
{
var allowedMarkings = _sponsors.TryGetInfo(session.UserId, out var sponsor) ? sponsor.AllowedMarkings : new string[]{};
bool isAdminSpecie = _adminManager.HasAdminFlag(session, Shared.Administration.AdminFlags.AdminSpecies);
var allowedMarkings = _sponsors.TryGetInfo(session.UserId, out var sponsor)
? sponsor.AllowedMarkings
: new string[] { };
bool isAdminSpecie =
_adminManager.HasAdminFlag(session, Shared.Administration.AdminFlags.AdminSpecies);
profile.EnsureValid(allowedMarkings, isAdminSpecie);
}
// WD-EDIT
@@ -229,6 +238,7 @@ namespace Content.Server.Preferences.Managers
{
MaxCharacterSlots = GetMaxUserCharacterSlots(session.UserId)
};
_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="playerPreferences">The user preferences if true, otherwise null</param>
/// <returns>If preferences are not null</returns>
public bool TryGetCachedPreferences(NetUserId userId,
public bool TryGetCachedPreferences(
NetUserId userId,
[NotNullWhen(true)] out PlayerPreferences? playerPreferences)
{
if (_cachedPlayerPrefs.TryGetValue(userId, out var prefs))
@@ -309,21 +320,27 @@ namespace Content.Server.Preferences.Managers
case HumanoidCharacterProfile hp:
{
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
.WithJobPriorities(
hp.JobPriorities.Where(job =>
_protos.HasIndex<JobPrototype>(job.Key)))
.WithAntagPreferences(
hp.AntagPreferences.Where(antag =>
_protos.HasIndex<AntagPrototype>(antag)))
.WithSpecies(selectedSpecies);
.WithJobPriorities(hp.JobPriorities.Where(job => _protos.HasIndex<JobPrototype>(job.Key)))
.WithAntagPreferences(hp.AntagPreferences.Where(antag =>
_protos.HasIndex<AntagPrototype>(antag)))
.WithSpecies(selectedSpecies.ID)
.WithBodyType(selectedBodyType.ID);
break;
}
default:

View File

@@ -70,10 +70,16 @@ public sealed partial class HumanoidAppearanceComponent : Component
[DataField, AutoNetworkedField]
public Sex Sex = Sex.Male;
/// <summary>
/// Current body type.
/// </summary>
[DataField("bodyType", customTypeSerializer: typeof(PrototypeIdSerializer<BodyTypePrototype>)), AutoNetworkedField]
public string BodyType = SharedHumanoidAppearanceSystem.DefaultBodyType;
[DataField, AutoNetworkedField]
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;
/// <summary>

View File

@@ -11,7 +11,8 @@ namespace Content.Shared.Humanoid
[Serializable, NetSerializable]
public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance
{
public HumanoidCharacterAppearance(string hairStyleId,
public HumanoidCharacterAppearance(
string hairStyleId,
Color hairColor,
string facialHairStyleId,
Color facialHairColor,
@@ -91,20 +92,27 @@ namespace Content.Shared.Humanoid
Color.Black,
Color.Black,
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)
{
var speciesPrototype = IoCManager.Resolve<IPrototypeManager>().Index<SpeciesPrototype>(species);
var skinColor = speciesPrototype.SkinColoration switch
{
HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone),
HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone,
HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone,
HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone),
_ => Humanoid.SkinColor.ValidHumanSkinTone
_ => Humanoid.SkinColor.ValidHumanSkinTone
};
return new(
@@ -114,7 +122,7 @@ namespace Content.Shared.Humanoid
Color.Black,
Color.Black,
skinColor,
new ()
new()
);
}
@@ -132,7 +140,8 @@ namespace Content.Shared.Humanoid
var random = IoCManager.Resolve<IRobustRandom>();
var markingManager = IoCManager.Resolve<MarkingManager>();
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
? random.Pick(hairStyles)
@@ -175,7 +184,8 @@ namespace Content.Shared.Humanoid
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)
{
@@ -188,7 +198,11 @@ namespace Content.Shared.Humanoid
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 facialHairStyleId = appearance.FacialHairStyleId;
@@ -250,7 +264,7 @@ namespace Content.Shared.Humanoid
skinColor = Humanoid.SkinColor.ValidSkinTone(speciesProto.SkinColoration, skinColor);
}
markingSet.EnsureSpecies(species, skinColor, markingManager);
markingSet.EnsureSpecies(species, bodyType, skinColor, markingManager);
// WD-EDIT
markingSet.FilterSponsor(sponsorMarkings, markingManager);
@@ -270,19 +284,23 @@ namespace Content.Shared.Humanoid
{
if (maybeOther is not HumanoidCharacterAppearance other)
return false;
if (HairStyleId != other.HairStyleId)
return false;
if (!HairColor.Equals(other.HairColor))
return false;
if (FacialHairStyleId != other.FacialHairStyleId)
return false;
if (!FacialHairColor.Equals(other.FacialHairColor))
return false;
if (!EyeColor.Equals(other.EyeColor))
return false;
if (!SkinColor.Equals(other.SkinColor))
return false;
return Markings.SequenceEqual(other.Markings);
return SkinColor.Equals(other.SkinColor) && 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
{

View File

@@ -1,4 +1,3 @@
using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
namespace Content.Shared.Humanoid
@@ -10,14 +9,14 @@ namespace Content.Shared.Humanoid
return layer switch
{
HumanoidVisualLayers.Chest => true,
HumanoidVisualLayers.Head => true,
_ => false
HumanoidVisualLayers.Head => true,
_ => false
};
}
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}{sex}";
@@ -42,26 +41,32 @@ namespace Content.Shared.Humanoid
yield return HumanoidVisualLayers.Hair;
yield return HumanoidVisualLayers.FacialHair;
yield return HumanoidVisualLayers.Snout;
break;
case HumanoidVisualLayers.LArm:
yield return HumanoidVisualLayers.LArm;
yield return HumanoidVisualLayers.LHand;
break;
case HumanoidVisualLayers.RArm:
yield return HumanoidVisualLayers.RArm;
yield return HumanoidVisualLayers.RHand;
break;
case HumanoidVisualLayers.LLeg:
yield return HumanoidVisualLayers.LLeg;
yield return HumanoidVisualLayers.LFoot;
break;
case HumanoidVisualLayers.RLeg:
yield return HumanoidVisualLayers.RLeg;
yield return HumanoidVisualLayers.RFoot;
break;
case HumanoidVisualLayers.Chest:
yield return HumanoidVisualLayers.Chest;
yield return HumanoidVisualLayers.Tail;
break;
default:
yield break;

View File

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

View File

@@ -51,7 +51,8 @@ public sealed partial class MarkingSet
public Dictionary<MarkingCategories, MarkingPoints> Points = new();
public MarkingSet()
{}
{
}
/// <summary>
/// Construct a MarkingSet using a list of markings, and a points
@@ -61,7 +62,11 @@ public sealed partial class MarkingSet
/// </summary>
/// <param name="markings">The lists of markings to use.</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);
@@ -108,7 +113,10 @@ public sealed partial class MarkingSet
/// Construct a MarkingSet only with a points dictionary.
/// </summary>
/// <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);
@@ -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.
/// </summary>
/// <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="markingManager">Marking 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 prototypeManager);
var toRemove = new List<(MarkingCategories category, string id)>();
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)
{
@@ -182,17 +197,17 @@ public sealed partial class MarkingSet
}
// 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) &&
markingManager.MustMatchSkin(species, prototype.BodyPart, out var alpha, prototypeManager))
{
marking.SetColor(skinColor.Value.WithAlpha(alpha));
}
marking.SetColor(skinColor.Value.WithAlpha(alpha));
}
}
}
@@ -265,7 +280,10 @@ public sealed partial class MarkingSet
}
// 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 prototypeManager);
@@ -319,11 +337,12 @@ public sealed partial class MarkingSet
if (markingManager.Markings.TryGetValue(points.DefaultMarkings[index], out var prototype))
{
var colors = MarkingColoring.GetMarkingLayerColors(
prototype,
skinColor,
eyeColor,
this
);
prototype,
skinColor,
eyeColor,
this
);
var marking = new Marking(points.DefaultMarkings[index], colors);
AddBack(category, marking);
@@ -398,7 +417,6 @@ public sealed partial class MarkingSet
Markings[category] = markings;
}
markings.Add(marking);
}
@@ -854,7 +872,8 @@ public sealed class MarkingsEnumerator : IEnumerator<Marking>
}
public void Dispose()
{}
{
}
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;
/// <summary>
/*/// <summary>
/// Base sprites for a species (e.g., what replaces the empty tagged layer,
/// or settings per layer)
/// </summary>
@@ -21,7 +21,7 @@ public sealed partial class HumanoidSpeciesBaseSpritesPrototype : IPrototype
/// </summary>
[DataField("sprites", required: true)]
public Dictionary<HumanoidVisualLayers, string> Sprites = new();
}
}*/
/// <summary>
/// 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.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Shared.Humanoid.Prototypes;
@@ -18,6 +19,9 @@ public sealed partial class SpeciesPrototype : IPrototype
[DataField("name", required: true)]
public string Name { get; private set; } = default!;
[DataField("bodyTypes", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<BodyTypePrototype>))]
public List<string> BodyTypes { get; } = default!;
/// <summary>
/// Descriptor. Unused...? This is intended
/// 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 accessories.
[DataField("sprites")]
public string SpriteSet { get; private set; } = default!;
// [DataField("sprites")]
// public string SpriteSet { get; private set; } = default!;
/// <summary>
/// Default skin tone for this species. This applies for non-human skin tones.
@@ -66,13 +70,13 @@ public sealed partial class SpeciesPrototype : IPrototype
/// <summary>
/// Humanoid species variant used by this entity.
/// </summary>
[DataField("prototype", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
[DataField("prototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Prototype { get; private set; } = default!;
/// <summary>
/// Prototype used by the species for the dress-up doll in various menus.
/// </summary>
[DataField("dollPrototype", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
[DataField("dollPrototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string DollPrototype { get; private set; } = default!;
/// <summary>

View File

@@ -1,5 +1,4 @@
using System.Linq;
using Content.Shared.Decals;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences;
@@ -26,12 +25,15 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
[ValidatePrototypeId<SpeciesPrototype>]
public const string DefaultSpecies = "Human";
public const string DefaultBodyType = "HumanNormal";
public const string DefaultVoice = "Eugene";
public static readonly Dictionary<Sex, string> DefaultSexVoice = new()
{
{Sex.Male, "Eugene"},
{Sex.Female, "Kseniya"},
{Sex.Unsexed, "Xenia"},
{ Sex.Male, "Eugene" },
{ Sex.Female, "Kseniya" },
{ Sex.Unsexed, "Xenia" },
};
public override void Initialize()
@@ -69,7 +71,8 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
/// <param name="uid">Humanoid mob's UID</param>
/// <param name="layer">Layer to toggle visibility for</param>
/// <param name="humanoid">Humanoid component of the entity</param>
public void SetLayerVisibility(EntityUid uid,
public void SetLayerVisibility(
EntityUid uid,
HumanoidVisualLayers layer,
bool visible,
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="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>
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)
{
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="sync">Whether to immediately synchronize this to the humanoid mob, or not.</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))
{
@@ -149,12 +160,14 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
}
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();
humanoid.MarkingSet = new(oldMarkings, prototype.MarkingPoints, _markingManager, _prototypeManager);
humanoid.MarkingSet = new MarkingSet(oldMarkings, prototype.MarkingPoints, _markingManager, _prototypeManager);
if (sync)
Dirty(humanoid);
{
Dirty(uid, humanoid);
}
}
/// <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="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>
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))
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="sync">Whether to synchronize this to the humanoid mob, or not.</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)
{
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="layer">The layer to target on this humanoid mob.</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))
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>
/// Loads a humanoid character profile directly onto this humanoid mob.
/// </summary>
/// <param name="uid">The mob's entity UID.</param>
/// <param name="profile">The character profile to load.</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))
{
@@ -295,10 +336,15 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
// 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
var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha, _prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(hairAlpha) : profile.Appearance.HairColor;
var facialHairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.FacialHair, out var facialHairAlpha, _prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(facialHairAlpha) : profile.Appearance.FacialHairColor;
var hairColor = _markingManager.MustMatchSkin(profile.Species, HumanoidVisualLayers.Hair, out var hairAlpha,
_prototypeManager)
? profile.Appearance.SkinColor.WithAlpha(hairAlpha)
: 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) &&
_markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _prototypeManager))
@@ -312,7 +358,9 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
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
foreach (var (marking, prototype) in markingFColored)
@@ -323,6 +371,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
profile.Appearance.EyeColor,
humanoid.MarkingSet
);
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="forced">If this marking was forced (ignores marking points)</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)
|| !_markingManager.Markings.TryGetValue(marking, out var prototype))
@@ -378,6 +433,7 @@ public abstract class SharedHumanoidAppearanceSystem : EntitySystem
{
return;
}
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="forced">If this marking was forced (ignores marking points)</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)
|| !_markingManager.Markings.TryGetValue(marking, out var prototype))

View File

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

View File

@@ -1,11 +1,9 @@
using System.Linq;
using System.Globalization;
using System.Text.RegularExpressions;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Random.Helpers;
using Content.Shared.Roles;
using Content.Shared.Traits;
using Content.Shared._White.TTS;
@@ -15,8 +13,6 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Content.Shared.Administration.Managers;
using Content.Shared.Administration;
namespace Content.Shared.Preferences
{
@@ -45,6 +41,7 @@ namespace Content.Shared.Preferences
Sex sex,
string voice,
Gender gender,
string bodyType,
HumanoidCharacterAppearance appearance,
ClothingPreference clothing,
BackpackPreference backpack,
@@ -64,6 +61,7 @@ namespace Content.Shared.Preferences
Age = age;
Sex = sex;
Gender = gender;
BodyType = bodyType;
Appearance = appearance;
Clothing = clothing;
Backpack = backpack;
@@ -80,14 +78,17 @@ namespace Content.Shared.Preferences
Dictionary<string, JobPriority> jobPriorities,
List<string> antagPreferences,
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)
{
}
/// <summary>Copy constructor</summary>
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,
Sex sex,
Gender gender,
string bodyType,
HumanoidCharacterAppearance appearance,
ClothingPreference clothing,
BackpackPreference backpack,
@@ -110,7 +112,8 @@ namespace Content.Shared.Preferences
PreferenceUnavailableMode preferenceUnavailable,
IReadOnlyList<string> antagPreferences,
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))
{
}
@@ -131,13 +134,14 @@ namespace Content.Shared.Preferences
18,
Sex.Male,
Gender.Male,
SharedHumanoidAppearanceSystem.DefaultBodyType,
new HumanoidCharacterAppearance(),
ClothingPreference.Jumpsuit,
BackpackPreference.Backpack,
SpawnPriorityPreference.None,
new Dictionary<string, JobPriority>
{
{SharedGameTicker.FallbackOverflowJob, JobPriority.High}
{ SharedGameTicker.FallbackOverflowJob, JobPriority.High }
},
PreferenceUnavailableMode.SpawnAsOverflow,
new List<string>(),
@@ -150,7 +154,8 @@ namespace Content.Shared.Preferences
/// </summary>
/// <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>
public static HumanoidCharacterProfile DefaultWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies)
public static HumanoidCharacterProfile DefaultWithSpecies(
string species = SharedHumanoidAppearanceSystem.DefaultSpecies)
{
return new(
"John Doe",
@@ -163,13 +168,14 @@ namespace Content.Shared.Preferences
18,
Sex.Male,
Gender.Male,
SharedHumanoidAppearanceSystem.DefaultBodyType,
HumanoidCharacterAppearance.DefaultWithSpecies(species),
ClothingPreference.Jumpsuit,
BackpackPreference.Backpack,
SpawnPriorityPreference.None,
new Dictionary<string, JobPriority>
{
{SharedGameTicker.FallbackOverflowJob, JobPriority.High}
{ SharedGameTicker.FallbackOverflowJob, JobPriority.High }
},
PreferenceUnavailableMode.SpawnAsOverflow,
new List<string>(),
@@ -191,17 +197,21 @@ namespace Content.Shared.Preferences
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 random = IoCManager.Resolve<IRobustRandom>();
var sex = Sex.Unsexed;
var age = 18;
var bodyType = SharedHumanoidAppearanceSystem.DefaultBodyType;
if (prototypeManager.TryIndex<SpeciesPrototype>(species, out var speciesPrototype))
{
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
@@ -226,18 +236,25 @@ namespace Content.Shared.Preferences
var mimeName = GetMimeName();
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>
{
{SharedGameTicker.FallbackOverflowJob, JobPriority.High},
{ SharedGameTicker.FallbackOverflowJob, JobPriority.High },
}, PreferenceUnavailableMode.StayInLobby, new List<string>(), new List<string>());
}
public string Name { get; private set; }
public string ClownName { get; private set; }
public string MimeName { get; private set; }
public string BorgName { get; private set; }
public string FlavorText { get; private set; }
public string Species { get; private set; }
public string Voice { get; private set; }
@@ -251,24 +268,38 @@ namespace Content.Shared.Preferences
[DataField("gender")]
public Gender Gender { get; private set; }
[DataField]
public string BodyType { get; private set; }
public ICharacterAppearance CharacterAppearance => Appearance;
[DataField("appearance")]
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)
{
return new(this) { Voice = voice };
}
public HumanoidCharacterProfile WithBodyType(string bodyType)
{
return new(this) { BodyType = bodyType };
}
public HumanoidCharacterProfile WithName(string name)
{
return new(this) { Name = name };
@@ -278,10 +309,12 @@ namespace Content.Shared.Preferences
{
return new(this) { ClownName = name };
}
public HumanoidCharacterProfile WithMimeName(string name)
{
return new(this) { MimeName = name };
}
public HumanoidCharacterProfile WithBorgName(string name)
{
return new(this) { BorgName = name };
@@ -312,7 +345,6 @@ namespace Content.Shared.Preferences
return new(this) { Species = species };
}
public HumanoidCharacterProfile WithCharacterAppearance(HumanoidCharacterAppearance appearance)
{
return new(this) { Appearance = appearance };
@@ -322,14 +354,17 @@ namespace Content.Shared.Preferences
{
return new(this) { Clothing = clothing };
}
public HumanoidCharacterProfile WithBackpackPreference(BackpackPreference backpack)
{
return new(this) { Backpack = backpack };
}
public HumanoidCharacterProfile WithSpawnPriorityPreference(SpawnPriorityPreference spawnPriority)
{
return new(this) { SpawnPriority = spawnPriority };
}
public HumanoidCharacterProfile WithJobPriorities(IEnumerable<KeyValuePair<string, JobPriority>> jobPriorities)
{
return new(this, new Dictionary<string, JobPriority>(jobPriorities), _antagPreferences, _traitPreferences);
@@ -346,6 +381,7 @@ namespace Content.Shared.Preferences
{
dictionary[jobId] = priority;
}
return new(this, dictionary, _antagPreferences, _traitPreferences);
}
@@ -376,6 +412,7 @@ namespace Content.Shared.Preferences
list.Remove(antagId);
}
}
return new(this, _jobPriorities, list, _traitPreferences);
}
@@ -398,6 +435,7 @@ namespace Content.Shared.Preferences
list.Remove(traitId);
}
}
return new(this, _jobPriorities, _antagPreferences, list);
}
@@ -411,21 +449,54 @@ namespace Content.Shared.Preferences
public bool MemberwiseEquals(ICharacterProfile maybeOther)
{
if (maybeOther is not HumanoidCharacterProfile other) return false;
if (Name != other.Name) return false;
if (ClownName != other.ClownName) return false;
if (MimeName != other.MimeName) return false;
if (BorgName != other.BorgName) return false;
if (Age != other.Age) return false;
if (Sex != other.Sex) return false;
if (Gender != other.Gender) 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;
if (maybeOther is not HumanoidCharacterProfile other)
return false;
if (Name != other.Name)
return false;
if (ClownName != other.ClownName)
return false;
if (MimeName != other.MimeName)
return false;
if (BorgName != other.BorgName)
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);
}
@@ -448,10 +519,10 @@ namespace Content.Shared.Preferences
var sex = Sex switch
{
Sex.Male => Sex.Male,
Sex.Female => Sex.Female,
Sex.Male => Sex.Male,
Sex.Female => Sex.Female,
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
@@ -462,16 +533,24 @@ namespace Content.Shared.Preferences
{
sex = speciesPrototype.Sexes[0];
}
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
{
Gender.Epicene => Gender.Epicene,
Gender.Female => Gender.Female,
Gender.Male => Gender.Male,
Gender.Neuter => Gender.Neuter,
_ => Gender.Epicene // Invalid enum values.
Gender.Female => Gender.Female,
Gender.Male => Gender.Male,
Gender.Neuter => Gender.Neuter,
_ => Gender.Epicene // Invalid enum values.
};
string name;
@@ -490,6 +569,7 @@ namespace Content.Shared.Preferences
{
name = Name;
}
if (string.IsNullOrEmpty(ClownName))
{
clownName = GetClownName();
@@ -502,6 +582,7 @@ namespace Content.Shared.Preferences
{
clownName = ClownName;
}
if (string.IsNullOrEmpty(MimeName))
{
mimeName = GetMimeName();
@@ -514,6 +595,7 @@ namespace Content.Shared.Preferences
{
mimeName = MimeName;
}
if (string.IsNullOrEmpty(BorgName))
{
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
name = Regex.Replace(name,
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper());
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper());
clownName = Regex.Replace(clownName,
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper());
mimeName = Regex.Replace(mimeName,
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper());
borgName = Regex.Replace(borgName,
@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
m => m.Groups["word"].Value.ToUpper());
@@ -577,7 +662,7 @@ namespace Content.Shared.Preferences
}
// WD-EDIT
var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, sponsorMarkings);
var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, BodyType, sponsorMarkings);
// WD-EDIT
var prefsUnavailableMode = PreferenceUnavailable switch
@@ -589,35 +674,35 @@ namespace Content.Shared.Preferences
var clothing = Clothing switch
{
ClothingPreference.Jumpsuit => ClothingPreference.Jumpsuit,
ClothingPreference.Jumpsuit => ClothingPreference.Jumpsuit,
ClothingPreference.Jumpskirt => ClothingPreference.Jumpskirt,
_ => ClothingPreference.Jumpsuit // Invalid enum values.
_ => ClothingPreference.Jumpsuit // Invalid enum values.
};
var backpack = Backpack switch
{
BackpackPreference.Backpack => BackpackPreference.Backpack,
BackpackPreference.Satchel => BackpackPreference.Satchel,
BackpackPreference.Backpack => BackpackPreference.Backpack,
BackpackPreference.Satchel => BackpackPreference.Satchel,
BackpackPreference.Duffelbag => BackpackPreference.Duffelbag,
_ => BackpackPreference.Backpack // Invalid enum values.
_ => BackpackPreference.Backpack // Invalid enum values.
};
var spawnPriority = SpawnPriority switch
{
SpawnPriorityPreference.None => SpawnPriorityPreference.None,
SpawnPriorityPreference.Arrivals => SpawnPriorityPreference.Arrivals,
SpawnPriorityPreference.None => SpawnPriorityPreference.None,
SpawnPriorityPreference.Arrivals => SpawnPriorityPreference.Arrivals,
SpawnPriorityPreference.Cryosleep => SpawnPriorityPreference.Cryosleep,
_ => SpawnPriorityPreference.None // Invalid enum values.
_ => SpawnPriorityPreference.None // Invalid enum values.
};
var priorities = new Dictionary<string, JobPriority>(JobPriorities
.Where(p => prototypeManager.HasIndex<JobPrototype>(p.Key) && p.Value switch
{
JobPriority.Never => false, // Drop never since that's assumed default.
JobPriority.Low => true,
JobPriority.Never => false, // Drop never since that's assumed default.
JobPriority.Low => true,
JobPriority.Medium => true,
JobPriority.High => true,
_ => false
JobPriority.High => true,
_ => false
}));
var antags = AntagPreferences
@@ -625,8 +710,8 @@ namespace Content.Shared.Preferences
.ToList();
var traits = TraitPreferences
.Where(prototypeManager.HasIndex<TraitPrototype>)
.ToList();
.Where(prototypeManager.HasIndex<TraitPrototype>)
.ToList();
Name = name;
ClownName = clownName;

View File

@@ -37,15 +37,6 @@ marking-HumanHairBusiness3 = Business Hair 3
marking-HumanHairBusiness4 = Business Hair 4
marking-HumanHairBuzzcut = Buzzcut
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-HumanHairCombover = Combover
marking-HumanHairCornrows = Cornrows

View File

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

View File

@@ -271,69 +271,6 @@
sprites:
- sprite: Mobs/Customization/human_hair.rsi
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
id: HumanHairCoffeehouse
bodyPart: Hair

View File

@@ -3,7 +3,8 @@
name: species-name-arachnid
roundStart: true
prototype: MobArachnid
sprites: MobArachnidSprites
bodyTypes:
- ArachnidNormal
defaultSkinTone: "#385878"
markingLimits: MobArachnidMarkingLimits
dollPrototype: MobArachnidDummy
@@ -15,25 +16,6 @@
sexes:
- 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
id: MobArachnidMarkingLimits
onlyWhitelisted: true

View File

@@ -3,7 +3,8 @@
name: species-name-diona
roundStart: true
prototype: MobDiona
sprites: MobDionaSprites
bodyTypes:
- DionaNormal
defaultSkinTone: "#cdb369"
markingLimits: MobDionaMarkingLimits
dollPrototype: MobDionaDummy
@@ -14,23 +15,6 @@
femaleLastNames: DionaLast
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
id: MobDionaMarkingLimits
onlyWhitelisted: true

View File

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

View File

@@ -3,29 +3,13 @@
name: species-name-human
roundStart: false
prototype: MobGingerbread
sprites: MobGingerbreadSprites
bodyTypes:
- GingerbreadNormal
markingLimits: MobHumanMarkingLimits
dollPrototype: MobGingerbreadDummy
skinColoration: HumanToned
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
id: MobGingerbreadEyes
baseSprite:

View File

@@ -3,7 +3,9 @@
name: species-name-human
roundStart: true
prototype: MobHuman
sprites: MobHumanSprites
bodyTypes:
- HumanNormal
- HumanSlim
markingLimits: MobHumanMarkingLimits
dollPrototype: MobHumanDummy
skinColoration: HumanToned
@@ -14,24 +16,6 @@
# be defined as a 'custom base layer'
# in either the mob's starting marking prototype,
# 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
id: MobHumanMarkingLimits
@@ -71,17 +55,12 @@
id: MobHumanoidMarkingMatchSkin
markingsMatchSkin: true
# Normal body type sprites
- type: humanoidBaseSprite
id: MobHumanHead
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: head_m
- type: humanoidBaseSprite
id: MobHumanHeadMale
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: head_m
state: head
- type: humanoidBaseSprite
id: MobHumanHeadFemale
@@ -93,13 +72,7 @@
id: MobHumanTorso
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: torso_m
- type: humanoidBaseSprite
id: MobHumanTorsoMale
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
state: torso_m
state: torso
- type: humanoidBaseSprite
id: MobHumanTorsoFemale
@@ -154,3 +127,77 @@
baseSprite:
sprite: Mobs/Species/Human/parts.rsi
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
roundStart: true
prototype: MobMoth
sprites: MobMothSprites
bodyTypes:
- MothNormal
defaultSkinTone: "#ffda93"
markingLimits: MobMothMarkingLimits
dollPrototype: MobMothDummy
@@ -12,25 +13,6 @@
femaleFirstNames: names_moth_first_female
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
id: MobMothEyes
baseSprite:

View File

@@ -3,7 +3,8 @@
name: species-name-reptilian
roundStart: true
prototype: MobReptilian
sprites: MobReptilianSprites
bodyTypes:
- ReptilianNormal
defaultSkinTone: "#34a223"
markingLimits: MobReptilianMarkingLimits
dollPrototype: MobReptilianDummy
@@ -12,24 +13,6 @@
femaleFirstNames: names_reptilian_female
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
id: MobReptilianMarkingLimits

View File

@@ -3,7 +3,8 @@
name: species-name-skeleton
roundStart: false
prototype: MobSkeletonPerson
sprites: MobSkeletonSprites
bodyTypes:
- SkeletonNormal
defaultSkinTone: "#fff9e2"
markingLimits: MobHumanMarkingLimits
maleFirstNames: skeletonNamesFirst
@@ -11,20 +12,6 @@
dollPrototype: MobSkeletonPersonDummy
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
id: MobSkeletonHead
baseSprite:

View File

@@ -3,29 +3,13 @@
name: species-name-slime
roundStart: true
prototype: MobSlimePerson
sprites: MobSlimeSprites
bodyTypes:
- SlimeNormal
defaultSkinTone: "#b8b8b8"
markingLimits: MobSlimeMarkingLimits
dollPrototype: MobSlimePersonDummy
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
id: MobSlimeMarkingLimits
points:

View File

@@ -3,7 +3,8 @@
name: Terminator
roundStart: false
prototype: MobTerminatorEndoskeleton
sprites: MobTerminatorSprites
bodyTypes:
- TerminatorNormal
defaultSkinTone: "#fff9e2"
markingLimits: MobHumanMarkingLimits
maleFirstNames: skeletonNamesFirst
@@ -11,19 +12,6 @@
dollPrototype: MobSkeletonPersonDummy
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
id: MobTerminatorHead

View File

@@ -3,7 +3,8 @@
name: species-name-vox
roundStart: false # sad...
prototype: MobVox
sprites: MobVoxSprites
bodyTypes:
- VoxNormal
markingLimits: MobVoxMarkingLimits
dollPrototype: MobVoxDummy
skinColoration: Hues
@@ -14,23 +15,6 @@
- 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
id: MobVoxMarkingLimits
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",
"directions": 4
},
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{
"name": "equipped-HAND-kangaroo",
"directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -14,6 +14,10 @@
"name": "equipped-HAND",
"directions": 4
},
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{
"name": "inhand-left",
"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",
"directions": 4
},
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{
"name": "inhand-left",
"directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -17,10 +17,18 @@
"name": "equipped-HAND",
"directions": 4
},
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{
"name": "on-equipped-HAND",
"directions": 4
},
{
"name": "on-equipped-HAND-body-slim",
"directions": 4
},
{
"name": "inhand-left",
"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",
"directions": 4
},
{
"name": "equipped-HAND-body-slim",
"directions": 4
},
{
"name": "inhand-left",
"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",
"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",
"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",
"directions": 4
},
{
"name": "equipped-OUTERCLOTHING-body-slim",
"directions": 4
},
{
"name": "inhand-left",
"directions": 4

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

View File

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

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