Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Body Types #180

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
  •  
  •  
  •  
51 changes: 43 additions & 8 deletions Content.Client/Clothing/ClientClothingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Numerics;
using Content.Client.DisplacementMap;
using Content.Client.Inventory;
using Content.Shared._White.Humanoid.Prototypes;
using Content.Shared.Clothing;
using Content.Shared.Clothing.Components;
using Content.Shared.Clothing.EntitySystems;
Expand All @@ -14,6 +15,7 @@
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Serialization.TypeSerializers.Implementations;
using Robust.Shared.Utility;
Expand Down Expand Up @@ -54,6 +56,8 @@ public sealed class ClientClothingSystem : ClothingSystem
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly DisplacementMapSystem _displacement = default!;

[Dependency] private readonly IPrototypeManager _prototype = default!; // WD EDIT

public override void Initialize()
{
base.Initialize();
Expand Down Expand Up @@ -92,6 +96,15 @@ private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVis

List<PrototypeLayerData>? layers = null;

// WD EDIT START
// body type specific
if (TryComp(args.Equipee, out HumanoidAppearanceComponent? humanoid))
{
var bodyTypeName = _prototype.Index<BodyTypePrototype>(humanoid.BodyType).Name;
item.ClothingVisuals.TryGetValue($"{args.Slot}-{bodyTypeName}", out layers);
}
// WD EDIT END

// first attempt to get species specific data.
if (inventory.SpeciesId != null)
item.ClothingVisuals.TryGetValue($"{args.Slot}-{inventory.SpeciesId}", out layers);
Expand All @@ -100,7 +113,7 @@ private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVis
if (layers == null && !item.ClothingVisuals.TryGetValue(args.Slot, out layers))
{
// 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, args.Equipee, out layers)) // WD EDIT
return;
}

Expand All @@ -127,7 +140,7 @@ private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVis
/// 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,
[NotNullWhen(true)] out List<PrototypeLayerData>? layers)
EntityUid target, [NotNullWhen(true)] out List<PrototypeLayerData>? layers) // WD EDIT
{
layers = null;

Expand All @@ -154,6 +167,16 @@ private bool TryGetDefaultVisuals(EntityUid uid, ClothingComponent clothing, str
if (clothing.EquippedState != null)
state = $"{clothing.EquippedState}";

// WD EDIT START
// body type specific
if (TryComp(target, out HumanoidAppearanceComponent? humanoid))
{
var bodyTypeName = _prototype.Index<BodyTypePrototype>(humanoid.BodyType).Name;
if (rsi.TryGetState($"{state}-{bodyTypeName}", out _))
state = $"{state}-{bodyTypeName}";
}
// WD EDIT END

// species specific
if (speciesId != null && rsi.TryGetState($"{state}-{speciesId}", out _))
{
Expand Down Expand Up @@ -263,21 +286,32 @@ private void RenderEquipment(EntityUid equipee, EntityUid equipment, string slot
// Select displacement maps
var displacementData = inventory.Displacements.GetValueOrDefault(slot); //Default unsexed map

var equipeeSex = CompOrNull<HumanoidAppearanceComponent>(equipee)?.Sex;
if (equipeeSex != null)
// WD EDIT START
string? bodyTypeName = null;
if (TryComp(equipee, out HumanoidAppearanceComponent? humanoid))
{
switch (equipeeSex)
bodyTypeName = _prototype.Index(humanoid.BodyType).Name;
switch (humanoid.Sex)
{
case Sex.Male:
if (inventory.MaleDisplacements.Count > 0)
displacementData = inventory.MaleDisplacements.GetValueOrDefault(slot);
{
displacementData = inventory.MaleDisplacements.GetValueOrDefault($"{slot}-{bodyTypeName}")
?? inventory.MaleDisplacements.GetValueOrDefault(slot);
}

break;
case Sex.Female:
if (inventory.FemaleDisplacements.Count > 0)
displacementData = inventory.FemaleDisplacements.GetValueOrDefault(slot);
{
displacementData = inventory.FemaleDisplacements.GetValueOrDefault($"{slot}-{bodyTypeName}")
?? inventory.FemaleDisplacements.GetValueOrDefault(slot);
}

break;
}
}
// WD EDIT END

// add the new layers
foreach (var (key, layerData) in ev.Layers)
Expand Down Expand Up @@ -319,7 +353,8 @@ private void RenderEquipment(EntityUid equipee, EntityUid equipment, string slot
if (displacementData is not null)
{
//Checking that the state is not tied to the current race. In this case we don't need to use the displacement maps.
if (layerData.State is not null && inventory.SpeciesId is not null && layerData.State.EndsWith(inventory.SpeciesId))
if (layerData.State is not null && (inventory.SpeciesId is not null && layerData.State.EndsWith(inventory.SpeciesId)
|| bodyTypeName is not null && layerData.State.EndsWith(bodyTypeName)))
continue;

if (_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers))
Expand Down
8 changes: 5 additions & 3 deletions Content.Client/Humanoid/HumanoidAppearanceSystem.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System.Numerics;
using Content.Shared._White.Humanoid.Prototypes;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid.Prototypes;
using Content.Shared.Preferences;
using Robust.Client.GameObjects;
using Robust.Shared.Physics;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;

Expand Down Expand Up @@ -52,9 +54,8 @@ private void UpdateLayers(HumanoidAppearanceComponent component, SpriteComponent
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); // WD EDIT
foreach (var (key, id) in bodyTypeProto.Sprites) // WD EDIT
{
oldLayers.Remove(key);
if (!component.CustomBaseLayers.ContainsKey(key))
Expand Down Expand Up @@ -206,6 +207,7 @@ public override void LoadProfile(EntityUid uid, HumanoidCharacterProfile? profil
humanoid.Sex = profile.Sex;
humanoid.Gender = profile.Gender;
humanoid.Age = profile.Age;
humanoid.BodyType = profile.BodyType; // WD EDIT
humanoid.Species = profile.Species;
humanoid.SkinColor = profile.Appearance.SkinColor;
humanoid.EyeColor = profile.Appearance.EyeColor;
Expand Down
8 changes: 8 additions & 0 deletions Content.Client/Lobby/UI/HumanoidProfileEditor.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@
<Control HorizontalExpand="True"/>
<LineEdit Name="CCustomSpecieNameEdit" MinSize="270 0" HorizontalAlignment="Right" />
</BoxContainer>
<!--WD EDIT START-->
<!-- Body Type -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-body-type-label'}"/>
<Control HorizontalExpand="True"/>
<OptionButton Name="CBodyTypesButton" HorizontalAlignment="Right" />
</BoxContainer>
<!--WD EDIT END-->
<!-- Age -->
<BoxContainer HorizontalExpand="True">
<Label Text="{Loc 'humanoid-profile-editor-age-label'}" />
Expand Down
50 changes: 50 additions & 0 deletions Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Content.Client.Players.PlayTimeTracking;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Shared._White.Humanoid.Prototypes;
using Content.Shared.CCVar;
using Content.Shared.Clothing.Components;
using Content.Shared.Clothing.Loadouts.Prototypes;
Expand Down Expand Up @@ -71,6 +72,7 @@ public sealed partial class HumanoidProfileEditor : BoxContainer
public JobPrototype? JobOverride;

private List<SpeciesPrototype> _species = new();
private List<BodyTypePrototype> _bodyTypes = new(); // WD EDIT
private List<(string, RequirementsSelector)> _jobPriorities = new();
private readonly Dictionary<string, BoxContainer> _jobCategories;

Expand Down Expand Up @@ -155,6 +157,16 @@ public HumanoidProfileEditor(

InitializeVoice();

#endregion

#region BodyType

CBodyTypesButton.OnItemSelected += args =>
{
CBodyTypesButton.SelectId(args.Id);
SetBodyType(_bodyTypes[args.Id].ID);
};

#endregion
// WD EDIT END

Expand Down Expand Up @@ -647,6 +659,7 @@ public void SetProfile(HumanoidCharacterProfile? profile, int? slot)
UpdateNameEdit();
UpdateSexControls();
UpdateTTSVoicesControls(); // WD EDIT
UpdateBodyTypes(); // WD EDIT
UpdateGenderControls();
UpdateSkinColor();
UpdateSpawnPriorityControls();
Expand Down Expand Up @@ -1127,6 +1140,7 @@ private void SetSex(Sex newSex)
UpdateGenderControls();
Markings.SetSex(newSex);
UpdateTTSVoicesControls(); // WD EDIT
UpdateBodyTypes(); // WD EDIT
ReloadProfilePreview();
SetDirty();
}
Expand All @@ -1137,6 +1151,13 @@ private void SetVoice(string newVoice)
Profile = Profile?.WithVoice(newVoice);
IsDirty = true;
}

private void SetBodyType(string newBodyType)
{
Profile = Profile?.WithBodyType(newBodyType);
ReloadPreview();
IsDirty = true;
}
// WD EDIT END

private void SetGender(Gender newGender)
Expand All @@ -1157,6 +1178,7 @@ private void SetSpecies(string newSpecies)
UpdateHeightWidthSliders();
UpdateWeight();
UpdateSpeciesGuidebookIcon();
UpdateBodyTypes(); // WD EDIT
IsDirty = true;
ReloadProfilePreview();
}
Expand Down Expand Up @@ -1229,6 +1251,34 @@ private void UpdateAgeEdit()
AgeEdit.Text = Profile?.Age.ToString() ?? "";
}

// WD EDIT START
private void UpdateBodyTypes()
{
if (Profile is null)
return;

CBodyTypesButton.Clear();
var species = _prototypeManager.Index<SpeciesPrototype>(Profile.Species);
var sex = Profile.Sex;
_bodyTypes = species.BodyTypes.Select(protoId => _prototypeManager.Index<BodyTypePrototype>(protoId))
.Where(proto => !proto.SexRestrictions.Contains(sex.ToString()))
.ToList();

for (var i = 0; i < _bodyTypes.Count; i++)
CBodyTypesButton.AddItem(Loc.GetString(_bodyTypes[i].Name), i);

// If current body type is not valid.
if (!_bodyTypes.Select(proto => proto.ID).Contains(Profile.BodyType))
{
// Then replace it with a first valid body type.
SetBodyType(_bodyTypes.First().ID);
}

CBodyTypesButton.Select(_bodyTypes.FindIndex(x => x.ID == Profile.BodyType));
IsDirty = true;
}
// WD EDIT END

/// Updates selected job priorities to the profile's
private void UpdateJobPriorities()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ private static HumanoidCharacterProfile CharlieCharlieson()
Customspeciename = "",
Age = 21,
Voice = "Aidar", // WD EDIT
BodyType = "Normal", // WD EDIT
Appearance = new(
"Afro",
Color.Aqua,
Expand Down
Loading
Loading