From 343f183b3208f496d98a35740b9120344a7fd8b1 Mon Sep 17 00:00:00 2001 From: RemberBL Date: Sun, 7 Mar 2021 20:48:24 +0100 Subject: [PATCH] Character eye customization, scroll bar in appearance tab character setup. Fixes #2946 (#3403) * A lot of unfinished work, trying to figure stuff out but it ain't really working * The eye colors finally work on the sprite! * Big refactor for HumanoidProfileEditor, crashes upon making a lobby * Fixed Lobby crashing * Moves the eye selection box to a new tab, which fixes selection the box from going off-screen and not expanding the bars * uncommented something I shouldn't have commented out * Moved eye colors back to the appearance tab, still some ui glitches * Made it possible to scroll in the appearance tab * Added "Eye color:" label * Migrating some deprecated functions into their replacements * Merged two private sealed classes into one public class, removing duplication --- .../MagicMirrorBoundUserInterface.cs | 217 ++++-- .../Mobs/HumanoidAppearanceComponent.cs | 4 +- .../HumanoidProfileEditor.Random.cs | 3 +- .../UserInterface/HumanoidProfileEditor.cs | 659 +++++++++--------- .../Components/MagicMirrorComponent.cs | 12 +- .../Components/SharedMagicMirrorComponent.cs | 15 +- 6 files changed, 510 insertions(+), 400 deletions(-) diff --git a/Content.Client/GameObjects/Components/MagicMirrorBoundUserInterface.cs b/Content.Client/GameObjects/Components/MagicMirrorBoundUserInterface.cs index 3a8100af1f..67205ea9f4 100644 --- a/Content.Client/GameObjects/Components/MagicMirrorBoundUserInterface.cs +++ b/Content.Client/GameObjects/Components/MagicMirrorBoundUserInterface.cs @@ -55,6 +55,11 @@ namespace Content.Client.GameObjects.Components isFacialHair)); } + internal void EyeColorSelected(Color color) + { + SendMessage(new EyeColorSelectedMessage((color.RByte, color.GByte, color.BByte))); + } + protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -66,6 +71,86 @@ namespace Content.Client.GameObjects.Components } } + public class ColorSlider : Control + { + private readonly Slider _slider; + private readonly LineEdit _textBox; + private byte _colorValue; + private bool _ignoreEvents; + + public event Action OnValueChanged; + + public byte ColorValue + { + get => _colorValue; + set + { + _ignoreEvents = true; + _colorValue = value; + _slider.Value = value; + _textBox.Text = value.ToString(); + _ignoreEvents = false; + } + } + + public ColorSlider(string styleClass) + { + _slider = new Slider + { + StyleClasses = { styleClass }, + HorizontalExpand = true, + VerticalAlignment = VAlignment.Center, + MaxValue = byte.MaxValue + }; + _textBox = new LineEdit + { + MinSize = (50, 0) + }; + + AddChild(new HBoxContainer + { + Children = + { + _slider, + _textBox + } + }); + + _slider.OnValueChanged += _ => + { + if (_ignoreEvents) + { + return; + } + + _colorValue = (byte) _slider.Value; + _textBox.Text = _colorValue.ToString(); + + OnValueChanged?.Invoke(); + }; + + _textBox.OnTextChanged += ev => + { + if (_ignoreEvents) + { + return; + } + + if (int.TryParse(ev.Text, out var result)) + { + result = MathHelper.Clamp(result, 0, byte.MaxValue); + + _ignoreEvents = true; + _colorValue = (byte) result; + _slider.Value = result; + _ignoreEvents = false; + + OnValueChanged?.Invoke(); + } + }; + } + } + public class FacialHairStylePicker : HairStylePicker { public override void Populate() @@ -175,91 +260,64 @@ namespace Content.Client.GameObjects.Components OnHairStylePicked?.Invoke(Items[args.ItemIndex].Text); } - private sealed class ColorSlider : Control + // ColorSlider + } + + public class EyeColorPicker : Control + { + public event Action OnEyeColorPicked; + + private readonly ColorSlider _colorSliderR; + private readonly ColorSlider _colorSliderG; + private readonly ColorSlider _colorSliderB; + + private Color _lastColor; + + public void SetData(Color color) { - private readonly Slider _slider; - private readonly LineEdit _textBox; - private byte _colorValue; - private bool _ignoreEvents; + _lastColor = color; - public event Action OnValueChanged; - - public byte ColorValue - { - get => _colorValue; - set - { - _ignoreEvents = true; - _colorValue = value; - _slider.Value = value; - _textBox.Text = value.ToString(); - _ignoreEvents = false; - } - } - - public ColorSlider(string styleClass) - { - _slider = new Slider - { - StyleClasses = {styleClass}, - HorizontalExpand = true, - VerticalAlignment = VAlignment.Center, - MaxValue = byte.MaxValue - }; - _textBox = new LineEdit - { - MinSize = (50, 0) - }; - - AddChild(new HBoxContainer - { - Children = - { - _slider, - _textBox - } - }); - - _slider.OnValueChanged += _ => - { - if (_ignoreEvents) - { - return; - } - - _colorValue = (byte) _slider.Value; - _textBox.Text = _colorValue.ToString(); - - OnValueChanged?.Invoke(); - }; - - _textBox.OnTextChanged += ev => - { - if (_ignoreEvents) - { - return; - } - - if (int.TryParse(ev.Text, out var result)) - { - result = MathHelper.Clamp(result, 0, byte.MaxValue); - - _ignoreEvents = true; - _colorValue = (byte) result; - _slider.Value = result; - _ignoreEvents = false; - - OnValueChanged?.Invoke(); - } - }; - } + _colorSliderR.ColorValue = color.RByte; + _colorSliderG.ColorValue = color.GByte; + _colorSliderB.ColorValue = color.BByte; } + + public EyeColorPicker() + { + 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)); + + Action colorValueChanged = ColorValueChanged; + _colorSliderR.OnValueChanged += colorValueChanged; + _colorSliderG.OnValueChanged += colorValueChanged; + _colorSliderB.OnValueChanged += colorValueChanged; + } + + private void ColorValueChanged() + { + var newColor = new Color( + _colorSliderR.ColorValue, + _colorSliderG.ColorValue, + _colorSliderB.ColorValue + ); + + OnEyeColorPicked?.Invoke(newColor); + + _lastColor = newColor; + } + + // ColorSlider } public class MagicMirrorWindow : SS14Window { private readonly HairStylePicker _hairStylePicker; private readonly FacialHairStylePicker _facialHairStylePicker; + private readonly EyeColorPicker _eyeColorPicker; public MagicMirrorWindow(MagicMirrorBoundUserInterface owner) { @@ -276,10 +334,13 @@ namespace Content.Client.GameObjects.Components _facialHairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, true); _facialHairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, true); + _eyeColorPicker = new EyeColorPicker {SizeFlagsHorizontal = SizeFlags.FillExpand}; + _eyeColorPicker.OnEyeColorPicked += newColor => owner.EyeColorSelected(newColor); + Contents.AddChild(new HBoxContainer { SeparationOverride = 8, - Children = {_hairStylePicker, _facialHairStylePicker} + Children = {_hairStylePicker, _facialHairStylePicker, _eyeColorPicker} }); } @@ -291,6 +352,7 @@ namespace Content.Client.GameObjects.Components { _hairStylePicker.Dispose(); _facialHairStylePicker.Dispose(); + _eyeColorPicker.Dispose(); } } @@ -298,6 +360,7 @@ namespace Content.Client.GameObjects.Components { _facialHairStylePicker.SetData(initialData.FacialHairColor, initialData.FacialHairName); _hairStylePicker.SetData(initialData.HairColor, initialData.HairName); + _eyeColorPicker.SetData(initialData.EyeColor); } } } diff --git a/Content.Client/GameObjects/Components/Mobs/HumanoidAppearanceComponent.cs b/Content.Client/GameObjects/Components/Mobs/HumanoidAppearanceComponent.cs index 1335af3cbf..9abd1a4b49 100644 --- a/Content.Client/GameObjects/Components/Mobs/HumanoidAppearanceComponent.cs +++ b/Content.Client/GameObjects/Components/Mobs/HumanoidAppearanceComponent.cs @@ -1,4 +1,4 @@ -using Content.Client.GameObjects.Components.ActionBlocking; +using Content.Client.GameObjects.Components.ActionBlocking; using Content.Shared.GameObjects.Components.Body; using Content.Shared.GameObjects.Components.Body.Part; using Content.Shared.GameObjects.Components.Mobs; @@ -63,6 +63,8 @@ namespace Content.Client.GameObjects.Components.Mobs sprite.LayerSetColor(HumanoidVisualLayers.Hair, Appearance.HairColor); sprite.LayerSetColor(HumanoidVisualLayers.FacialHair, Appearance.FacialHairColor); + 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"); diff --git a/Content.Client/UserInterface/HumanoidProfileEditor.Random.cs b/Content.Client/UserInterface/HumanoidProfileEditor.Random.cs index 8a3893a55b..ffc5e1d1fe 100644 --- a/Content.Client/UserInterface/HumanoidProfileEditor.Random.cs +++ b/Content.Client/UserInterface/HumanoidProfileEditor.Random.cs @@ -1,4 +1,4 @@ -using Content.Shared.Preferences; +using Content.Shared.Preferences; using Content.Shared.Prototypes; using Content.Shared.Utility; using Robust.Shared.Prototypes; @@ -20,6 +20,7 @@ namespace Content.Client.UserInterface UpdateAgeEdit(); UpdateNameEdit(); UpdateHairPickers(); + UpdateEyePickers(); } private void RandomizeName() diff --git a/Content.Client/UserInterface/HumanoidProfileEditor.cs b/Content.Client/UserInterface/HumanoidProfileEditor.cs index 3895d9748e..1839004116 100644 --- a/Content.Client/UserInterface/HumanoidProfileEditor.cs +++ b/Content.Client/UserInterface/HumanoidProfileEditor.cs @@ -47,6 +47,7 @@ namespace Content.Client.UserInterface private readonly OptionButton _backpackButton; private readonly HairStylePicker _hairPicker; private readonly FacialHairStylePicker _facialHairPicker; + private readonly EyeColorPicker _eyesPicker; private readonly List _jobPriorities; private readonly OptionButton _preferenceUnavailableButton; @@ -90,45 +91,40 @@ namespace Content.Client.UserInterface #region Randomize + var randomizePanel = HighlightedContainer(); + var randomizeEverythingButton = new Button { - var panel = HighlightedContainer(); - var randomizeEverythingButton = new Button - { - Text = Loc.GetString("Randomize everything") - }; - randomizeEverythingButton.OnPressed += args => { RandomizeEverything(); }; - panel.AddChild(randomizeEverythingButton); - leftColumn.AddChild(panel); - } + Text = Loc.GetString("Randomize everything") + }; + randomizeEverythingButton.OnPressed += args => { RandomizeEverything(); }; + randomizePanel.AddChild(randomizeEverythingButton); + leftColumn.AddChild(randomizePanel); #endregion Randomize #region Name + var namePanel = HighlightedContainer(); + var nameHBox = new HBoxContainer { - var panel = HighlightedContainer(); - var hBox = new HBoxContainer - { - VerticalExpand = true - }; - var nameLabel = new Label {Text = Loc.GetString("Name:")}; - _nameEdit = new LineEdit - { - MinSize = (270, 0), - VerticalAlignment = VAlignment.Center - }; - _nameEdit.OnTextChanged += args => { SetName(args.Text); }; - var nameRandomButton = new Button - { - Text = Loc.GetString("Randomize"), - }; - nameRandomButton.OnPressed += _ => RandomizeName(); - hBox.AddChild(nameLabel); - hBox.AddChild(_nameEdit); - hBox.AddChild(nameRandomButton); - panel.AddChild(hBox); - leftColumn.AddChild(panel); - } + VerticalExpand = true + }; + var nameLabel = new Label { Text = Loc.GetString("Name:") }; + _nameEdit = new LineEdit + { + MinSize = (270, 0), + VerticalAlignment = VAlignment.Center + }; + _nameEdit.OnTextChanged += args => { SetName(args.Text); }; + var nameRandomButton = new Button + { + Text = Loc.GetString("Randomize"), + }; + nameRandomButton.OnPressed += args => RandomizeName(); + nameHBox.AddChild(nameLabel); + nameHBox.AddChild(_nameEdit); + nameHBox.AddChild(nameRandomButton); + randomizePanel.AddChild(nameHBox); #endregion Name @@ -137,233 +133,259 @@ namespace Content.Client.UserInterface #region Appearance + var appearanceList = new VBoxContainer(); + + var appearanceVBox = new VBoxContainer { - var appearanceVBox = new VBoxContainer(); - tabContainer.AddChild(appearanceVBox); - tabContainer.SetTabTitle(0, Loc.GetString("Appearance")); - - var sexAndAgeRow = new HBoxContainer + Children = { - SeparationOverride = 10 - }; - - appearanceVBox.AddChild(sexAndAgeRow); - - #region Sex - - { - var panel = HighlightedContainer(); - var hBox = new HBoxContainer(); - var sexLabel = new Label {Text = Loc.GetString("Sex:")}; - - var sexButtonGroup = new ButtonGroup(); - - _sexMaleButton = new Button + new ScrollContainer { - Text = Loc.GetString("Male"), - Group = sexButtonGroup - }; - _sexMaleButton.OnPressed += args => - { - SetSex(Sex.Male); - if (Profile.Gender == Gender.Female) + VerticalExpand = true, + Children = { - SetGender(Gender.Male); - UpdateGenderControls(); + appearanceList } - }; - - _sexFemaleButton = new Button - { - Text = Loc.GetString("Female"), - Group = sexButtonGroup - }; - _sexFemaleButton.OnPressed += args => - { - SetSex(Sex.Female); - if (Profile.Gender == Gender.Male) - { - SetGender(Gender.Female); - UpdateGenderControls(); - } - }; - - hBox.AddChild(sexLabel); - hBox.AddChild(_sexMaleButton); - hBox.AddChild(_sexFemaleButton); - panel.AddChild(hBox); - sexAndAgeRow.AddChild(panel); + } } + }; + tabContainer.AddChild(appearanceVBox); + tabContainer.SetTabTitle(0, Loc.GetString("Appearance")); - #endregion Sex + var sexAndAgeRow = new HBoxContainer + { + SeparationOverride = 10 + }; - #region Age + appearanceList.AddChild(sexAndAgeRow); + #region Sex + + var sexPanel = HighlightedContainer(); + var sexHBox = new HBoxContainer(); + var sexLabel = new Label { Text = Loc.GetString("Sex:") }; + + var sexButtonGroup = new ButtonGroup(); + + _sexMaleButton = new Button + { + Text = Loc.GetString("Male"), + Group = sexButtonGroup + }; + _sexMaleButton.OnPressed += args => + { + SetSex(Sex.Male); + if (Profile.Gender == Gender.Female) { - var panel = HighlightedContainer(); - var hBox = new HBoxContainer(); - var ageLabel = new Label {Text = Loc.GetString("Age:")}; - _ageEdit = new LineEdit {MinSize = (40, 0)}; - _ageEdit.OnTextChanged += args => - { - if (!int.TryParse(args.Text, out var newAge)) - return; - SetAge(newAge); - }; - hBox.AddChild(ageLabel); - hBox.AddChild(_ageEdit); - panel.AddChild(hBox); - sexAndAgeRow.AddChild(panel); + SetGender(Gender.Male); + UpdateGenderControls(); } + }; - #endregion Age - - #region Gender - + _sexFemaleButton = new Button + { + Text = Loc.GetString("Female"), + Group = sexButtonGroup + }; + _sexFemaleButton.OnPressed += args => + { + SetSex(Sex.Female); + if (Profile.Gender == Gender.Male) { - var panel = HighlightedContainer(); - var hBox = new HBoxContainer(); - var genderLabel = new Label {Text = Loc.GetString("Pronouns:")}; - - _genderButton = new OptionButton(); - - _genderButton.AddItem(Loc.GetString("He / Him"), (int) Gender.Male); - _genderButton.AddItem(Loc.GetString("She / Her"), (int) Gender.Female); - _genderButton.AddItem(Loc.GetString("They / Them"), (int) Gender.Epicene); - _genderButton.AddItem(Loc.GetString("It / It"), (int) Gender.Neuter); - - _genderButton.OnItemSelected += args => - { - _genderButton.SelectId(args.Id); - SetGender((Gender) args.Id); - }; - - hBox.AddChild(genderLabel); - hBox.AddChild(_genderButton); - panel.AddChild(hBox); - sexAndAgeRow.AddChild(panel); + SetGender(Gender.Female); + UpdateGenderControls(); } + }; - #endregion Gender + sexHBox.AddChild(sexLabel); + sexHBox.AddChild(_sexMaleButton); + sexHBox.AddChild(_sexFemaleButton); + sexPanel.AddChild(sexHBox); + sexAndAgeRow.AddChild(sexPanel); - #region Hair + #endregion Sex - { - var panel = HighlightedContainer(); - panel.HorizontalAlignment = HAlignment.Left; - var hairHBox = new HBoxContainer(); + #region Age - _hairPicker = new HairStylePicker(); - _hairPicker.Populate(); + var agePanel = HighlightedContainer(); + var ageHBox = new HBoxContainer(); + var ageLabel = new Label { Text = Loc.GetString("Age:") }; + _ageEdit = new LineEdit { MinSize = (40, 0) }; + _ageEdit.OnTextChanged += args => + { + if (!int.TryParse(args.Text, out var newAge)) + return; + SetAge(newAge); + }; + ageHBox.AddChild(ageLabel); + ageHBox.AddChild(_ageEdit); + agePanel.AddChild(ageHBox); + sexAndAgeRow.AddChild(agePanel); - _hairPicker.OnHairStylePicked += newStyle => - { - if (Profile is null) - return; - Profile = Profile.WithCharacterAppearance( - Profile.Appearance.WithHairStyleName(newStyle)); - IsDirty = true; - }; + #endregion Age - _hairPicker.OnHairColorPicked += newColor => - { - if (Profile is null) - return; - Profile = Profile.WithCharacterAppearance( - Profile.Appearance.WithHairColor(newColor)); - IsDirty = true; - }; + #region Gender - _facialHairPicker = new FacialHairStylePicker(); - _facialHairPicker.Populate(); + var genderPanel = HighlightedContainer(); + var genderHBox = new HBoxContainer(); + var genderLabel = new Label { Text = Loc.GetString("Pronouns:") }; - _facialHairPicker.OnHairStylePicked += newStyle => - { - if (Profile is null) - return; - Profile = Profile.WithCharacterAppearance( - Profile.Appearance.WithFacialHairStyleName(newStyle)); - IsDirty = true; - }; + _genderButton = new OptionButton(); - _facialHairPicker.OnHairColorPicked += newColor => - { - if (Profile is null) - return; - Profile = Profile.WithCharacterAppearance( - Profile.Appearance.WithFacialHairColor(newColor)); - IsDirty = true; - }; + _genderButton.AddItem(Loc.GetString("He / Him"), (int) Gender.Male); + _genderButton.AddItem(Loc.GetString("She / Her"), (int) Gender.Female); + _genderButton.AddItem(Loc.GetString("They / Them"), (int) Gender.Epicene); + _genderButton.AddItem(Loc.GetString("It / It"), (int) Gender.Neuter); - hairHBox.AddChild(_hairPicker); - hairHBox.AddChild(_facialHairPicker); + _genderButton.OnItemSelected += args => + { + _genderButton.SelectId(args.Id); + SetGender((Gender) args.Id); + }; - panel.AddChild(hairHBox); - appearanceVBox.AddChild(panel); - } + genderHBox.AddChild(genderLabel); + genderHBox.AddChild(_genderButton); + genderPanel.AddChild(genderHBox); + sexAndAgeRow.AddChild(genderPanel); - #endregion Hair + #endregion Gender - #region Clothing + #region Hair - { - var panel = HighlightedContainer(); - var hBox = new HBoxContainer(); - var clothingLabel = new Label {Text = Loc.GetString("Clothing:")}; + var hairPanel = HighlightedContainer(); + var hairHBox = new HBoxContainer(); - _clothingButton = new OptionButton(); + _hairPicker = new HairStylePicker + { + HorizontalAlignment = HAlignment.Center + }; + _hairPicker.Populate(); - _clothingButton.AddItem(Loc.GetString("Jumpsuit"), (int) ClothingPreference.Jumpsuit); - _clothingButton.AddItem(Loc.GetString("Jumpskirt"), (int) ClothingPreference.Jumpskirt); + _hairPicker.OnHairStylePicked += newStyle => + { + if (Profile is null) + return; + Profile = Profile.WithCharacterAppearance( + Profile.Appearance.WithHairStyleName(newStyle)); + IsDirty = true; + }; - _clothingButton.OnItemSelected += args => - { - _clothingButton.SelectId(args.Id); - SetClothing((ClothingPreference) args.Id); - }; + _hairPicker.OnHairColorPicked += newColor => + { + if (Profile is null) + return; + Profile = Profile.WithCharacterAppearance( + Profile.Appearance.WithHairColor(newColor)); + IsDirty = true; + }; - hBox.AddChild(clothingLabel); - hBox.AddChild(_clothingButton); - panel.AddChild(hBox); - appearanceVBox.AddChild(panel); - } + _facialHairPicker = new FacialHairStylePicker(); + _facialHairPicker.Populate(); - #endregion Clothing + _facialHairPicker.OnHairStylePicked += newStyle => + { + if (Profile is null) + return; + Profile = Profile.WithCharacterAppearance( + Profile.Appearance.WithFacialHairStyleName(newStyle)); + IsDirty = true; + }; - #region Backpack + _facialHairPicker.OnHairColorPicked += newColor => + { + if (Profile is null) + return; + Profile = Profile.WithCharacterAppearance( + Profile.Appearance.WithFacialHairColor(newColor)); + IsDirty = true; + }; - { - var panel = HighlightedContainer(); - var hBox = new HBoxContainer(); - var backpackLabel = new Label {Text = Loc.GetString("Backpack:")}; + hairHBox.AddChild(_hairPicker); + hairHBox.AddChild(_facialHairPicker); - _backpackButton = new OptionButton(); + hairPanel.AddChild(hairHBox); + appearanceList.AddChild(hairPanel); - _backpackButton.AddItem(Loc.GetString("Backpack"), (int) BackpackPreference.Backpack); - _backpackButton.AddItem(Loc.GetString("Satchel"), (int) BackpackPreference.Satchel); - _backpackButton.AddItem(Loc.GetString("Duffelbag"), (int) BackpackPreference.Duffelbag); + #endregion Hair - _backpackButton.OnItemSelected += args => - { - _backpackButton.SelectId(args.Id); - SetBackpack((BackpackPreference) args.Id); - }; + #region Clothing - hBox.AddChild(backpackLabel); - hBox.AddChild(_backpackButton); - panel.AddChild(hBox); - appearanceVBox.AddChild(panel); - } + var clothingPanel = HighlightedContainer(); + var clothingHBox = new HBoxContainer(); + var clothingLabel = new Label { Text = Loc.GetString("Clothing:") }; - #endregion Clothing - } + _clothingButton = new OptionButton(); - #endregion + _clothingButton.AddItem(Loc.GetString("Jumpsuit"), (int) ClothingPreference.Jumpsuit); + _clothingButton.AddItem(Loc.GetString("Jumpskirt"), (int) ClothingPreference.Jumpskirt); + + _clothingButton.OnItemSelected += args => + { + _clothingButton.SelectId(args.Id); + SetClothing((ClothingPreference) args.Id); + }; + + clothingHBox.AddChild(clothingLabel); + clothingHBox.AddChild(_clothingButton); + clothingPanel.AddChild(clothingHBox); + appearanceList.AddChild(clothingPanel); + + #endregion Clothing + + #region Backpack + + var backpackPanel = HighlightedContainer(); + var backpackHBox = new HBoxContainer(); + var backpackLabel = new Label { Text = Loc.GetString("Backpack:") }; + + _backpackButton = new OptionButton(); + + _backpackButton.AddItem(Loc.GetString("Backpack"), (int) BackpackPreference.Backpack); + _backpackButton.AddItem(Loc.GetString("Satchel"), (int) BackpackPreference.Satchel); + _backpackButton.AddItem(Loc.GetString("Duffelbag"), (int) BackpackPreference.Duffelbag); + + _backpackButton.OnItemSelected += args => + { + _backpackButton.SelectId(args.Id); + SetBackpack((BackpackPreference) args.Id); + }; + + backpackHBox.AddChild(backpackLabel); + backpackHBox.AddChild(_backpackButton); + backpackPanel.AddChild(backpackHBox); + appearanceList.AddChild(backpackPanel); + + #endregion Backpack + + #region Eyes + + var eyesPanel = HighlightedContainer(); + var eyesVBox = new VBoxContainer(); + var eyesLabel = new Label { Text = Loc.GetString("Eye color:") }; + + _eyesPicker = new EyeColorPicker(); + + _eyesPicker.OnEyeColorPicked += newColor => + { + if (Profile is null) + return; + Profile = Profile.WithCharacterAppearance( + Profile.Appearance.WithEyeColor(newColor)); + IsDirty = true; + }; + + eyesVBox.AddChild(eyesLabel); + eyesVBox.AddChild(_eyesPicker); + eyesPanel.AddChild(eyesVBox); + appearanceList.AddChild(eyesPanel); + + #endregion Eyes + + #endregion Appearance #region Jobs - { - var jobList = new VBoxContainer(); + var jobList = new VBoxContainer(); var jobVBox = new VBoxContainer { @@ -381,42 +403,42 @@ namespace Content.Client.UserInterface } }; - tabContainer.AddChild(jobVBox); + tabContainer.AddChild(jobVBox); - tabContainer.SetTabTitle(1, Loc.GetString("Jobs")); + tabContainer.SetTabTitle(1, Loc.GetString("Jobs")); - _preferenceUnavailableButton.AddItem( - Loc.GetString("Stay in lobby if preference unavailable."), - (int) PreferenceUnavailableMode.StayInLobby); - _preferenceUnavailableButton.AddItem( - Loc.GetString("Be an {0} if preference unavailable.", - Loc.GetString(SharedGameTicker.OverflowJobName)), - (int) PreferenceUnavailableMode.SpawnAsOverflow); + _preferenceUnavailableButton.AddItem( + Loc.GetString("Stay in lobby if preference unavailable."), + (int) PreferenceUnavailableMode.StayInLobby); + _preferenceUnavailableButton.AddItem( + Loc.GetString("Be an {0} if preference unavailable.", + Loc.GetString(SharedGameTicker.OverflowJobName)), + (int) PreferenceUnavailableMode.SpawnAsOverflow); - _preferenceUnavailableButton.OnItemSelected += args => + _preferenceUnavailableButton.OnItemSelected += args => + { + _preferenceUnavailableButton.SelectId(args.Id); + + Profile = Profile.WithPreferenceUnavailable((PreferenceUnavailableMode) args.Id); + IsDirty = true; + }; + + _jobPriorities = new List(); + _jobCategories = new Dictionary(); + + var firstCategory = true; + + foreach (var job in prototypeManager.EnumeratePrototypes().OrderBy(j => j.Name)) + { + foreach (var department in job.Departments) { - _preferenceUnavailableButton.SelectId(args.Id); - - Profile = Profile.WithPreferenceUnavailable((PreferenceUnavailableMode) args.Id); - IsDirty = true; - }; - - _jobPriorities = new List(); - _jobCategories = new Dictionary(); - - var firstCategory = true; - - foreach (var job in prototypeManager.EnumeratePrototypes().OrderBy(j => j.Name)) - { - foreach (var department in job.Departments) + if (!_jobCategories.TryGetValue(department, out var category)) { - if (!_jobCategories.TryGetValue(department, out var category)) + category = new VBoxContainer { - category = new VBoxContainer - { - Name = department, - ToolTip = Loc.GetString("Jobs in the {0} department", department) - }; + Name = department, + ToolTip = Loc.GetString("Jobs in the {0} department", department) + }; if (firstCategory) { @@ -430,60 +452,58 @@ namespace Content.Client.UserInterface }); } - category.AddChild(new PanelContainer - { - PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#464966")}, - Children = - { - new Label - { - Text = Loc.GetString("{0} jobs", department) - } - } - }); - - _jobCategories[department] = category; - jobList.AddChild(category); - } - - var selector = new JobPrioritySelector(job); - category.AddChild(selector); - _jobPriorities.Add(selector); - - selector.PriorityChanged += priority => + category.AddChild(new PanelContainer { - Profile = Profile.WithJobPriority(job.ID, priority); - IsDirty = true; - - foreach (var jobSelector in _jobPriorities) + PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#464966")}, + Children = { - // Sync other selectors with the same job in case of multiple department jobs - if (jobSelector.Job == selector.Job) + new Label { - jobSelector.Priority = priority; - } - - // Lower any other high priorities to medium. - if (priority == JobPriority.High) - { - if (jobSelector.Job != selector.Job && jobSelector.Priority == JobPriority.High) - { - jobSelector.Priority = JobPriority.Medium; - Profile = Profile.WithJobPriority(jobSelector.Job.ID, JobPriority.Medium); - } + Text = Loc.GetString("{0} jobs", department) } } - }; + }); + + _jobCategories[department] = category; + jobList.AddChild(category); } + + var selector = new JobPrioritySelector(job); + category.AddChild(selector); + _jobPriorities.Add(selector); + + selector.PriorityChanged += priority => + { + Profile = Profile.WithJobPriority(job.ID, priority); + IsDirty = true; + + foreach (var jobSelector in _jobPriorities) + { + // Sync other selectors with the same job in case of multiple department jobs + if (jobSelector.Job == selector.Job) + { + jobSelector.Priority = priority; + } + + // Lower any other high priorities to medium. + if (priority == JobPriority.High) + { + if (jobSelector.Job != selector.Job && jobSelector.Priority == JobPriority.High) + { + jobSelector.Priority = JobPriority.Medium; + Profile = Profile.WithJobPriority(jobSelector.Job.ID, JobPriority.Medium); + } + } + } + }; } } - #endregion + #endregion Jobs #region Antags - { - var antagList = new VBoxContainer(); + var antagList = new VBoxContainer(); var antagVBox = new VBoxContainer { @@ -500,11 +520,11 @@ namespace Content.Client.UserInterface } }; - tabContainer.AddChild(antagVBox); + tabContainer.AddChild(antagVBox); - tabContainer.SetTabTitle(2, Loc.GetString("Antags")); + tabContainer.SetTabTitle(2, Loc.GetString("Antags")); - _antagPreferences = new List(); + _antagPreferences = new List(); foreach (var antag in prototypeManager.EnumeratePrototypes().OrderBy(a => a.Name)) { @@ -517,41 +537,38 @@ namespace Content.Client.UserInterface antagList.AddChild(selector); _antagPreferences.Add(selector); - selector.PreferenceChanged += preference => - { - Profile = Profile.WithAntagPreference(antag.ID, preference); - IsDirty = true; - }; - } + selector.PreferenceChanged += preference => + { + Profile = Profile.WithAntagPreference(antag.ID, preference); + IsDirty = true; + }; } - #endregion + #endregion Antags var rightColumn = new VBoxContainer(); middleContainer.AddChild(rightColumn); #region Import/Export + var importExportPanelContainer = HighlightedContainer(); + var importExportHBox = new HBoxContainer(); + var importButton = new Button { - var panelContainer = HighlightedContainer(); - var hBox = new HBoxContainer(); - var importButton = new Button - { - Text = Loc.GetString("Import"), - Disabled = true, - ToolTip = "Not yet implemented!" - }; - var exportButton = new Button - { - Text = Loc.GetString("Export"), - Disabled = true, - ToolTip = "Not yet implemented!" - }; - hBox.AddChild(importButton); - hBox.AddChild(exportButton); - panelContainer.AddChild(hBox); - rightColumn.AddChild(panelContainer); - } + Text = Loc.GetString("Import"), + Disabled = true, + ToolTip = "Not yet implemented!" + }; + var exportButton = new Button + { + Text = Loc.GetString("Export"), + Disabled = true, + ToolTip = "Not yet implemented!" + }; + importExportHBox.AddChild(importButton); + importExportHBox.AddChild(exportButton); + importExportPanelContainer.AddChild(importExportHBox); + rightColumn.AddChild(importExportPanelContainer); #endregion Import/Export @@ -571,7 +588,7 @@ namespace Content.Client.UserInterface #endregion Save - #endregion + #endregion Left #region Right @@ -621,7 +638,7 @@ namespace Content.Client.UserInterface }; box.AddChild(_previewSpriteSide); - #endregion + #endregion Right #endregion @@ -757,6 +774,11 @@ namespace Content.Client.UserInterface Profile.Appearance.FacialHairStyleName); } + private void UpdateEyePickers() + { + _eyesPicker.SetData(Profile.Appearance.EyeColor); + } + private void UpdateSaveButton() { _saveButton.Disabled = Profile is null || !IsDirty; @@ -781,6 +803,7 @@ namespace Content.Client.UserInterface UpdateBackpackControls(); UpdateAgeEdit(); UpdateHairPickers(); + UpdateEyePickers(); UpdateSaveButton(); UpdateJobPriorities(); UpdateAntagPreferences(); diff --git a/Content.Server/GameObjects/Components/MagicMirrorComponent.cs b/Content.Server/GameObjects/Components/MagicMirrorComponent.cs index ad33d8d8da..8455b87c27 100644 --- a/Content.Server/GameObjects/Components/MagicMirrorComponent.cs +++ b/Content.Server/GameObjects/Components/MagicMirrorComponent.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using Content.Server.GameObjects.Components.Mobs; using Content.Server.Utility; using Content.Shared.GameObjects.Components; @@ -83,6 +83,14 @@ namespace Content.Server.GameObjects.Components looks.Appearance = looks.Appearance.WithHairColor(color); } + break; + + case EyeColorSelectedMessage msg: + var (eyeR, eyeG, eyeB) = msg.EyeColor; + var eyeColor = new Color(eyeR, eyeG, eyeB); + + looks.Appearance = looks.Appearance.WithEyeColor(eyeColor); + break; } } @@ -103,7 +111,7 @@ namespace Content.Server.GameObjects.Components UserInterface?.Toggle(actor.playerSession); var msg = new MagicMirrorInitialDataMessage(looks.Appearance.HairColor, looks.Appearance.FacialHairColor, looks.Appearance.HairStyleName, - looks.Appearance.FacialHairStyleName); + looks.Appearance.FacialHairStyleName, looks.Appearance.EyeColor); UserInterface?.SendMessage(msg, actor.playerSession); } diff --git a/Content.Shared/GameObjects/Components/SharedMagicMirrorComponent.cs b/Content.Shared/GameObjects/Components/SharedMagicMirrorComponent.cs index ad29deb50c..9783c90ea1 100644 --- a/Content.Shared/GameObjects/Components/SharedMagicMirrorComponent.cs +++ b/Content.Shared/GameObjects/Components/SharedMagicMirrorComponent.cs @@ -42,6 +42,17 @@ namespace Content.Shared.GameObjects.Components } } + [Serializable, NetSerializable] + public class EyeColorSelectedMessage : BoundUserInterfaceMessage + { + public (byte r, byte g, byte b) EyeColor; + + public EyeColorSelectedMessage((byte r, byte g, byte b) color) + { + EyeColor = color; + } + } + [Serializable, NetSerializable] public class MagicMirrorInitialDataMessage : BoundUserInterfaceMessage { @@ -49,13 +60,15 @@ namespace Content.Shared.GameObjects.Components public readonly Color FacialHairColor; public readonly string HairName; public readonly string FacialHairName; + public readonly Color EyeColor; - public MagicMirrorInitialDataMessage(Color hairColor, Color facialHairColor, string hairName, string facialHairName) + public MagicMirrorInitialDataMessage(Color hairColor, Color facialHairColor, string hairName, string facialHairName, Color eyeColor) { HairColor = hairColor; FacialHairColor = facialHairColor; HairName = hairName; FacialHairName = facialHairName; + EyeColor = eyeColor; } } }