SKREEEEEE (#3706)
* Import bird sprites and define basic mob. * SKREEEEEEEEE * Move hair styles to new sprite accessory prototypes. Basic stuff, no multi-species stuff yet. * Vox hair styles and clothes * Make HumanoidCharacterProfile.Default() a static default to fix tests. Usages that wanted the previous random behavior now call Random(). * Remove names from hair style prototypes. (They're in localization files) * Update Content.Shared/Actions/ActionType.cs (sk)reeee github Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5ed935f30a
commit
0ac4c0e85c
@@ -61,7 +61,7 @@ namespace Content.Client.GameObjects.Components.Clothing
|
||||
set => _femaleMask = value;
|
||||
}
|
||||
|
||||
public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EquipmentSlotDefines.SlotFlags slot)
|
||||
public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EquipmentSlotDefines.SlotFlags slot, string? speciesId=null)
|
||||
{
|
||||
if (RsiPath == null)
|
||||
{
|
||||
@@ -77,6 +77,15 @@ namespace Content.Client.GameObjects.Components.Clothing
|
||||
|
||||
var prefix = ClothingEquippedPrefix ?? EquippedPrefix;
|
||||
var stateId = prefix != null ? $"{prefix}-equipped-{slot}" : $"equipped-{slot}";
|
||||
if (speciesId != null)
|
||||
{
|
||||
var speciesState = $"{stateId}-{speciesId}";
|
||||
if (rsi.TryGetState(speciesState, out _))
|
||||
{
|
||||
return (rsi, speciesState);
|
||||
}
|
||||
}
|
||||
|
||||
if (rsi.TryGetState(stateId, out _))
|
||||
{
|
||||
return (rsi, stateId);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Client.GameObjects.Components.Clothing;
|
||||
using Content.Client.GameObjects.Components.Items;
|
||||
using Content.Shared.GameObjects.Components.Inventory;
|
||||
using Content.Shared.GameObjects.Components.Movement;
|
||||
using Content.Shared.GameObjects.EntitySystems.EffectBlocker;
|
||||
@@ -10,6 +9,7 @@ using Content.Shared.Preferences.Appearance;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
|
||||
using static Content.Shared.GameObjects.Components.Inventory.SharedInventoryComponent.ClientInventoryMessage;
|
||||
@@ -34,6 +34,9 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
|
||||
private bool _playerAttached = false;
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("speciesId")] public string? SpeciesId { get; set; }
|
||||
|
||||
public override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
@@ -182,7 +185,7 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
if (entity.TryGetComponent(out ClothingComponent? clothing))
|
||||
{
|
||||
var flag = SlotMasks[slot];
|
||||
var data = clothing.GetEquippedStateInfo(flag);
|
||||
var data = clothing.GetEquippedStateInfo(flag, SpeciesId);
|
||||
if (data != null)
|
||||
{
|
||||
var (rsi, state) = data.Value;
|
||||
@@ -190,7 +193,7 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory
|
||||
_sprite.LayerSetState(slot, state, rsi);
|
||||
_sprite.LayerSetAutoAnimated(slot, true);
|
||||
|
||||
if (slot == Slots.INNERCLOTHING)
|
||||
if (slot == Slots.INNERCLOTHING && _sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _))
|
||||
{
|
||||
_sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothing.FemaleMask switch
|
||||
{
|
||||
|
||||
@@ -4,15 +4,15 @@ using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Shared.Preferences.Appearance;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using static Content.Shared.GameObjects.Components.SharedMagicMirrorComponent;
|
||||
using static Content.Client.StaticIoC;
|
||||
|
||||
namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
@@ -97,7 +97,7 @@ namespace Content.Client.GameObjects.Components
|
||||
{
|
||||
_slider = new Slider
|
||||
{
|
||||
StyleClasses = { styleClass },
|
||||
StyleClasses = {styleClass},
|
||||
HorizontalExpand = true,
|
||||
VerticalAlignment = VAlignment.Center,
|
||||
MaxValue = byte.MaxValue
|
||||
@@ -110,10 +110,10 @@ namespace Content.Client.GameObjects.Components
|
||||
AddChild(new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
_slider,
|
||||
_textBox
|
||||
}
|
||||
{
|
||||
_slider,
|
||||
_textBox
|
||||
}
|
||||
});
|
||||
|
||||
_slider.OnValueChanged += _ =>
|
||||
@@ -151,47 +151,42 @@ namespace Content.Client.GameObjects.Components
|
||||
}
|
||||
}
|
||||
|
||||
public class FacialHairStylePicker : HairStylePicker
|
||||
public sealed class HairStylePicker : Control
|
||||
{
|
||||
public override void Populate()
|
||||
{
|
||||
var humanFacialHairRSIPath = SharedSpriteComponent.TextureRoot / "Mobs/Customization/human_facial_hair.rsi";
|
||||
var humanFacialHairRSI = ResC.GetResource<RSIResource>(humanFacialHairRSIPath).RSI;
|
||||
[Dependency] private readonly SpriteAccessoryManager _spriteAccessoryManager = default!;
|
||||
|
||||
var styles = HairStyles.FacialHairStylesMap.ToList();
|
||||
styles.Sort(HairStyles.FacialHairStyleComparer);
|
||||
|
||||
foreach (var (styleName, styleState) in HairStyles.FacialHairStylesMap)
|
||||
{
|
||||
Items.AddItem(styleName, humanFacialHairRSI[styleState].Frame0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HairStylePicker : Control
|
||||
{
|
||||
public event Action<Color>? OnHairColorPicked;
|
||||
public event Action<string>? OnHairStylePicked;
|
||||
|
||||
protected readonly ItemList Items;
|
||||
private readonly ItemList _items;
|
||||
|
||||
private readonly Control _colorContainer;
|
||||
private readonly ColorSlider _colorSliderR;
|
||||
private readonly ColorSlider _colorSliderG;
|
||||
private readonly ColorSlider _colorSliderB;
|
||||
|
||||
private Color _lastColor;
|
||||
private SpriteAccessoryCategories _categories;
|
||||
|
||||
public void SetData(Color color, string styleName)
|
||||
public void SetData(Color color, string styleId, SpriteAccessoryCategories categories, bool canColor)
|
||||
{
|
||||
if (_categories != categories)
|
||||
{
|
||||
_categories = categories;
|
||||
Populate();
|
||||
}
|
||||
|
||||
_colorContainer.Visible = canColor;
|
||||
_lastColor = color;
|
||||
|
||||
_colorSliderR.ColorValue = color.RByte;
|
||||
_colorSliderG.ColorValue = color.GByte;
|
||||
_colorSliderB.ColorValue = color.BByte;
|
||||
|
||||
foreach (var item in Items)
|
||||
foreach (var item in _items)
|
||||
{
|
||||
item.Selected = item.Text == styleName;
|
||||
var prototype = (SpriteAccessoryPrototype) item.Metadata!;
|
||||
item.Selected = prototype.ID == styleId;
|
||||
}
|
||||
|
||||
UpdateStylePickerColor();
|
||||
@@ -199,7 +194,7 @@ namespace Content.Client.GameObjects.Components
|
||||
|
||||
private void UpdateStylePickerColor()
|
||||
{
|
||||
foreach (var item in Items)
|
||||
foreach (var item in _items)
|
||||
{
|
||||
item.IconModulate = _lastColor;
|
||||
}
|
||||
@@ -207,25 +202,29 @@ namespace Content.Client.GameObjects.Components
|
||||
|
||||
public HairStylePicker()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
var vBox = new VBoxContainer();
|
||||
AddChild(vBox);
|
||||
|
||||
vBox.AddChild(_colorSliderR = new ColorSlider(StyleNano.StyleClassSliderRed));
|
||||
vBox.AddChild(_colorSliderG = new ColorSlider(StyleNano.StyleClassSliderGreen));
|
||||
vBox.AddChild(_colorSliderB = new ColorSlider(StyleNano.StyleClassSliderBlue));
|
||||
_colorContainer = new VBoxContainer();
|
||||
vBox.AddChild(_colorContainer);
|
||||
_colorContainer.AddChild(_colorSliderR = new ColorSlider(StyleNano.StyleClassSliderRed));
|
||||
_colorContainer.AddChild(_colorSliderG = new ColorSlider(StyleNano.StyleClassSliderGreen));
|
||||
_colorContainer.AddChild(_colorSliderB = new ColorSlider(StyleNano.StyleClassSliderBlue));
|
||||
|
||||
Action colorValueChanged = ColorValueChanged;
|
||||
_colorSliderR.OnValueChanged += colorValueChanged;
|
||||
_colorSliderG.OnValueChanged += colorValueChanged;
|
||||
_colorSliderB.OnValueChanged += colorValueChanged;
|
||||
|
||||
Items = new ItemList
|
||||
_items = new ItemList
|
||||
{
|
||||
VerticalExpand = true,
|
||||
MinSize = (300, 250)
|
||||
};
|
||||
vBox.AddChild(Items);
|
||||
Items.OnItemSelected += ItemSelected;
|
||||
vBox.AddChild(_items);
|
||||
_items.OnItemSelected += ItemSelected;
|
||||
}
|
||||
|
||||
private void ColorValueChanged()
|
||||
@@ -241,27 +240,28 @@ namespace Content.Client.GameObjects.Components
|
||||
UpdateStylePickerColor();
|
||||
}
|
||||
|
||||
public virtual void Populate()
|
||||
public void Populate()
|
||||
{
|
||||
var humanHairRSIPath = SharedSpriteComponent.TextureRoot / "Mobs/Customization/human_hair.rsi";
|
||||
var humanHairRSI = ResC.GetResource<RSIResource>(humanHairRSIPath).RSI;
|
||||
var styles = _spriteAccessoryManager
|
||||
.AccessoriesForCategory(_categories)
|
||||
.ToList();
|
||||
styles.Sort(HairStyles.SpriteAccessoryComparer);
|
||||
|
||||
var styles = HairStyles.HairStylesMap.ToList();
|
||||
styles.Sort(HairStyles.HairStyleComparer);
|
||||
|
||||
foreach (var (styleName, styleState) in styles)
|
||||
foreach (var style in styles)
|
||||
{
|
||||
Items.AddItem(styleName, humanHairRSI[styleState].Frame0);
|
||||
var item = _items.AddItem(style.Name, style.Sprite.Frame0());
|
||||
item.Metadata = style;
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemSelected(ItemList.ItemListSelectedEventArgs args)
|
||||
{
|
||||
var hairColor = Items[args.ItemIndex].Text;
|
||||
var prototype = (SpriteAccessoryPrototype?) _items[args.ItemIndex].Metadata;
|
||||
var style = prototype?.ID;
|
||||
|
||||
if (hairColor != null)
|
||||
if (style != null)
|
||||
{
|
||||
OnHairStylePicked?.Invoke(hairColor);
|
||||
OnHairStylePicked?.Invoke(style);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ namespace Content.Client.GameObjects.Components
|
||||
public class MagicMirrorWindow : SS14Window
|
||||
{
|
||||
private readonly HairStylePicker _hairStylePicker;
|
||||
private readonly FacialHairStylePicker _facialHairStylePicker;
|
||||
private readonly HairStylePicker _facialHairStylePicker;
|
||||
private readonly EyeColorPicker _eyeColorPicker;
|
||||
|
||||
public MagicMirrorWindow(MagicMirrorBoundUserInterface owner)
|
||||
@@ -330,12 +330,10 @@ namespace Content.Client.GameObjects.Components
|
||||
Title = Loc.GetString("Magic Mirror");
|
||||
|
||||
_hairStylePicker = new HairStylePicker {HorizontalExpand = true};
|
||||
_hairStylePicker.Populate();
|
||||
_hairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, false);
|
||||
_hairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, false);
|
||||
|
||||
_facialHairStylePicker = new FacialHairStylePicker {HorizontalExpand = true};
|
||||
_facialHairStylePicker.Populate();
|
||||
_facialHairStylePicker = new HairStylePicker {HorizontalExpand = true};
|
||||
_facialHairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, true);
|
||||
_facialHairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, true);
|
||||
|
||||
@@ -363,8 +361,8 @@ namespace Content.Client.GameObjects.Components
|
||||
|
||||
public void SetInitialData(MagicMirrorInitialDataMessage initialData)
|
||||
{
|
||||
_facialHairStylePicker.SetData(initialData.FacialHairColor, initialData.FacialHairName);
|
||||
_hairStylePicker.SetData(initialData.HairColor, initialData.HairName);
|
||||
_facialHairStylePicker.SetData(initialData.FacialHairColor, initialData.FacialHairId, initialData.CategoriesFacialHair, initialData.CanColorFacialHair);
|
||||
_hairStylePicker.SetData(initialData.HairColor, initialData.HairId, initialData.CategoriesHair, initialData.CanColorHair);
|
||||
_eyeColorPicker.SetData(initialData.EyeColor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,18 @@ using Content.Shared.Preferences;
|
||||
using Content.Shared.Preferences.Appearance;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Mobs
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class HumanoidAppearanceComponent : SharedHumanoidAppearanceComponent, IBodyPartAdded, IBodyPartRemoved
|
||||
{
|
||||
[Dependency] private readonly SpriteAccessoryManager _accessoryManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public override HumanoidCharacterAppearance Appearance
|
||||
{
|
||||
get => base.Appearance;
|
||||
@@ -60,15 +66,18 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
}
|
||||
}
|
||||
|
||||
sprite.LayerSetColor(HumanoidVisualLayers.Hair, Appearance.HairColor);
|
||||
sprite.LayerSetColor(HumanoidVisualLayers.FacialHair, Appearance.FacialHairColor);
|
||||
sprite.LayerSetColor(HumanoidVisualLayers.Hair,
|
||||
CanColorHair ? Appearance.HairColor : Color.White);
|
||||
sprite.LayerSetColor(HumanoidVisualLayers.FacialHair,
|
||||
CanColorFacialHair ? Appearance.FacialHairColor : Color.White);
|
||||
|
||||
sprite.LayerSetColor(HumanoidVisualLayers.Eyes, Appearance.EyeColor);
|
||||
|
||||
sprite.LayerSetState(HumanoidVisualLayers.Chest, Sex == Sex.Male ? "torso_m" : "torso_f");
|
||||
sprite.LayerSetState(HumanoidVisualLayers.Head, Sex == Sex.Male ? "head_m" : "head_f");
|
||||
|
||||
sprite.LayerSetVisible(HumanoidVisualLayers.StencilMask, Sex == Sex.Female);
|
||||
if (sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _))
|
||||
sprite.LayerSetVisible(HumanoidVisualLayers.StencilMask, Sex == Sex.Female);
|
||||
|
||||
if (Owner.TryGetComponent<CuffableComponent>(out var cuffed))
|
||||
{
|
||||
@@ -79,17 +88,25 @@ namespace Content.Client.GameObjects.Components.Mobs
|
||||
sprite.LayerSetVisible(HumanoidVisualLayers.Handcuffs, false);
|
||||
}
|
||||
|
||||
var hairStyle = Appearance.HairStyleName;
|
||||
if (string.IsNullOrWhiteSpace(hairStyle) || !HairStyles.HairStylesMap.ContainsKey(hairStyle))
|
||||
var hairStyle = Appearance.HairStyleId;
|
||||
if (string.IsNullOrWhiteSpace(hairStyle) ||
|
||||
!_accessoryManager.IsValidAccessoryInCategory(hairStyle, CategoriesHair))
|
||||
{
|
||||
hairStyle = HairStyles.DefaultHairStyle;
|
||||
sprite.LayerSetState(HumanoidVisualLayers.Hair,
|
||||
HairStyles.HairStylesMap[hairStyle]);
|
||||
}
|
||||
|
||||
var facialHairStyle = Appearance.FacialHairStyleName;
|
||||
if (string.IsNullOrWhiteSpace(facialHairStyle) || !HairStyles.FacialHairStylesMap.ContainsKey(facialHairStyle))
|
||||
var facialHairStyle = Appearance.FacialHairStyleId;
|
||||
if (string.IsNullOrWhiteSpace(facialHairStyle) ||
|
||||
!_accessoryManager.IsValidAccessoryInCategory(facialHairStyle, CategoriesFacialHair))
|
||||
{
|
||||
facialHairStyle = HairStyles.DefaultFacialHairStyle;
|
||||
sprite.LayerSetState(HumanoidVisualLayers.FacialHair,
|
||||
HairStyles.FacialHairStylesMap[facialHairStyle]);
|
||||
}
|
||||
|
||||
var hairPrototype = _prototypeManager.Index<SpriteAccessoryPrototype>(hairStyle);
|
||||
var facialHairPrototype = _prototypeManager.Index<SpriteAccessoryPrototype>(facialHairStyle);
|
||||
|
||||
sprite.LayerSetSprite(HumanoidVisualLayers.Hair, hairPrototype.Sprite);
|
||||
sprite.LayerSetSprite(HumanoidVisualLayers.FacialHair, facialHairPrototype.Sprite);
|
||||
}
|
||||
|
||||
public void BodyPartAdded(BodyPartAddedEventArgs args)
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace Content.Client.UserInterface
|
||||
};
|
||||
_createNewCharacterButton.OnPressed += args =>
|
||||
{
|
||||
preferencesManager.CreateCharacter(HumanoidCharacterProfile.Default());
|
||||
preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random());
|
||||
UpdateUI();
|
||||
args.Event.Handle();
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ using Content.Client.Interfaces;
|
||||
using Content.Client.UserInterface.Stylesheets;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Preferences.Appearance;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
@@ -46,7 +47,7 @@ namespace Content.Client.UserInterface
|
||||
private readonly OptionButton _clothingButton;
|
||||
private readonly OptionButton _backpackButton;
|
||||
private readonly HairStylePicker _hairPicker;
|
||||
private readonly FacialHairStylePicker _facialHairPicker;
|
||||
private readonly HairStylePicker _facialHairPicker;
|
||||
private readonly EyeColorPicker _eyesPicker;
|
||||
|
||||
private readonly List<JobPrioritySelector> _jobPriorities;
|
||||
@@ -281,7 +282,7 @@ namespace Content.Client.UserInterface
|
||||
IsDirty = true;
|
||||
};
|
||||
|
||||
_facialHairPicker = new FacialHairStylePicker();
|
||||
_facialHairPicker = new HairStylePicker();
|
||||
_facialHairPicker.Populate();
|
||||
|
||||
_facialHairPicker.OnHairStylePicked += newStyle =>
|
||||
@@ -794,10 +795,14 @@ namespace Content.Client.UserInterface
|
||||
|
||||
_hairPicker.SetData(
|
||||
Profile.Appearance.HairColor,
|
||||
Profile.Appearance.HairStyleName);
|
||||
Profile.Appearance.HairStyleId,
|
||||
SpriteAccessoryCategories.HumanHair,
|
||||
true);
|
||||
_facialHairPicker.SetData(
|
||||
Profile.Appearance.FacialHairColor,
|
||||
Profile.Appearance.FacialHairStyleName);
|
||||
Profile.Appearance.FacialHairStyleId,
|
||||
SpriteAccessoryCategories.HumanFacialHair,
|
||||
false);
|
||||
}
|
||||
|
||||
private void UpdateEyePickers()
|
||||
|
||||
Reference in New Issue
Block a user