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
This commit is contained in:
RemberBL
2021-03-07 20:48:24 +01:00
committed by GitHub
parent b207162b25
commit 343f183b32
6 changed files with 510 additions and 400 deletions

View File

@@ -55,6 +55,11 @@ namespace Content.Client.GameObjects.Components
isFacialHair)); isFacialHair));
} }
internal void EyeColorSelected(Color color)
{
SendMessage(new EyeColorSelectedMessage((color.RByte, color.GByte, color.BByte)));
}
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(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 class FacialHairStylePicker : HairStylePicker
{ {
public override void Populate() public override void Populate()
@@ -175,91 +260,64 @@ namespace Content.Client.GameObjects.Components
OnHairStylePicked?.Invoke(Items[args.ItemIndex].Text); OnHairStylePicked?.Invoke(Items[args.ItemIndex].Text);
} }
private sealed class ColorSlider : Control // ColorSlider
}
public class EyeColorPicker : Control
{
public event Action<Color> 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; _lastColor = color;
private readonly LineEdit _textBox;
private byte _colorValue;
private bool _ignoreEvents;
public event Action OnValueChanged; _colorSliderR.ColorValue = color.RByte;
_colorSliderG.ColorValue = color.GByte;
public byte ColorValue _colorSliderB.ColorValue = color.BByte;
{
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 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 public class MagicMirrorWindow : SS14Window
{ {
private readonly HairStylePicker _hairStylePicker; private readonly HairStylePicker _hairStylePicker;
private readonly FacialHairStylePicker _facialHairStylePicker; private readonly FacialHairStylePicker _facialHairStylePicker;
private readonly EyeColorPicker _eyeColorPicker;
public MagicMirrorWindow(MagicMirrorBoundUserInterface owner) public MagicMirrorWindow(MagicMirrorBoundUserInterface owner)
{ {
@@ -276,10 +334,13 @@ namespace Content.Client.GameObjects.Components
_facialHairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, true); _facialHairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, true);
_facialHairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, true); _facialHairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, true);
_eyeColorPicker = new EyeColorPicker {SizeFlagsHorizontal = SizeFlags.FillExpand};
_eyeColorPicker.OnEyeColorPicked += newColor => owner.EyeColorSelected(newColor);
Contents.AddChild(new HBoxContainer Contents.AddChild(new HBoxContainer
{ {
SeparationOverride = 8, SeparationOverride = 8,
Children = {_hairStylePicker, _facialHairStylePicker} Children = {_hairStylePicker, _facialHairStylePicker, _eyeColorPicker}
}); });
} }
@@ -291,6 +352,7 @@ namespace Content.Client.GameObjects.Components
{ {
_hairStylePicker.Dispose(); _hairStylePicker.Dispose();
_facialHairStylePicker.Dispose(); _facialHairStylePicker.Dispose();
_eyeColorPicker.Dispose();
} }
} }
@@ -298,6 +360,7 @@ namespace Content.Client.GameObjects.Components
{ {
_facialHairStylePicker.SetData(initialData.FacialHairColor, initialData.FacialHairName); _facialHairStylePicker.SetData(initialData.FacialHairColor, initialData.FacialHairName);
_hairStylePicker.SetData(initialData.HairColor, initialData.HairName); _hairStylePicker.SetData(initialData.HairColor, initialData.HairName);
_eyeColorPicker.SetData(initialData.EyeColor);
} }
} }
} }

View File

@@ -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;
using Content.Shared.GameObjects.Components.Body.Part; using Content.Shared.GameObjects.Components.Body.Part;
using Content.Shared.GameObjects.Components.Mobs; 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.Hair, Appearance.HairColor);
sprite.LayerSetColor(HumanoidVisualLayers.FacialHair, Appearance.FacialHairColor); 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.Chest, Sex == Sex.Male ? "torso_m" : "torso_f");
sprite.LayerSetState(HumanoidVisualLayers.Head, Sex == Sex.Male ? "head_m" : "head_f"); sprite.LayerSetState(HumanoidVisualLayers.Head, Sex == Sex.Male ? "head_m" : "head_f");

View File

@@ -1,4 +1,4 @@
using Content.Shared.Preferences; using Content.Shared.Preferences;
using Content.Shared.Prototypes; using Content.Shared.Prototypes;
using Content.Shared.Utility; using Content.Shared.Utility;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -20,6 +20,7 @@ namespace Content.Client.UserInterface
UpdateAgeEdit(); UpdateAgeEdit();
UpdateNameEdit(); UpdateNameEdit();
UpdateHairPickers(); UpdateHairPickers();
UpdateEyePickers();
} }
private void RandomizeName() private void RandomizeName()

View File

@@ -47,6 +47,7 @@ namespace Content.Client.UserInterface
private readonly OptionButton _backpackButton; private readonly OptionButton _backpackButton;
private readonly HairStylePicker _hairPicker; private readonly HairStylePicker _hairPicker;
private readonly FacialHairStylePicker _facialHairPicker; private readonly FacialHairStylePicker _facialHairPicker;
private readonly EyeColorPicker _eyesPicker;
private readonly List<JobPrioritySelector> _jobPriorities; private readonly List<JobPrioritySelector> _jobPriorities;
private readonly OptionButton _preferenceUnavailableButton; private readonly OptionButton _preferenceUnavailableButton;
@@ -90,45 +91,40 @@ namespace Content.Client.UserInterface
#region Randomize #region Randomize
var randomizePanel = HighlightedContainer();
var randomizeEverythingButton = new Button
{ {
var panel = HighlightedContainer(); Text = Loc.GetString("Randomize everything")
var randomizeEverythingButton = new Button };
{ randomizeEverythingButton.OnPressed += args => { RandomizeEverything(); };
Text = Loc.GetString("Randomize everything") randomizePanel.AddChild(randomizeEverythingButton);
}; leftColumn.AddChild(randomizePanel);
randomizeEverythingButton.OnPressed += args => { RandomizeEverything(); };
panel.AddChild(randomizeEverythingButton);
leftColumn.AddChild(panel);
}
#endregion Randomize #endregion Randomize
#region Name #region Name
var namePanel = HighlightedContainer();
var nameHBox = new HBoxContainer
{ {
var panel = HighlightedContainer(); VerticalExpand = true
var hBox = new HBoxContainer };
{ var nameLabel = new Label { Text = Loc.GetString("Name:") };
VerticalExpand = true _nameEdit = new LineEdit
}; {
var nameLabel = new Label {Text = Loc.GetString("Name:")}; MinSize = (270, 0),
_nameEdit = new LineEdit VerticalAlignment = VAlignment.Center
{ };
MinSize = (270, 0), _nameEdit.OnTextChanged += args => { SetName(args.Text); };
VerticalAlignment = VAlignment.Center var nameRandomButton = new Button
}; {
_nameEdit.OnTextChanged += args => { SetName(args.Text); }; Text = Loc.GetString("Randomize"),
var nameRandomButton = new Button };
{ nameRandomButton.OnPressed += args => RandomizeName();
Text = Loc.GetString("Randomize"), nameHBox.AddChild(nameLabel);
}; nameHBox.AddChild(_nameEdit);
nameRandomButton.OnPressed += _ => RandomizeName(); nameHBox.AddChild(nameRandomButton);
hBox.AddChild(nameLabel); randomizePanel.AddChild(nameHBox);
hBox.AddChild(_nameEdit);
hBox.AddChild(nameRandomButton);
panel.AddChild(hBox);
leftColumn.AddChild(panel);
}
#endregion Name #endregion Name
@@ -137,233 +133,259 @@ namespace Content.Client.UserInterface
#region Appearance #region Appearance
var appearanceList = new VBoxContainer();
var appearanceVBox = new VBoxContainer
{ {
var appearanceVBox = new VBoxContainer(); Children =
tabContainer.AddChild(appearanceVBox);
tabContainer.SetTabTitle(0, Loc.GetString("Appearance"));
var sexAndAgeRow = new HBoxContainer
{ {
SeparationOverride = 10 new ScrollContainer
};
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
{ {
Text = Loc.GetString("Male"), VerticalExpand = true,
Group = sexButtonGroup Children =
};
_sexMaleButton.OnPressed += args =>
{
SetSex(Sex.Male);
if (Profile.Gender == Gender.Female)
{ {
SetGender(Gender.Male); appearanceList
UpdateGenderControls();
} }
}; }
_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(); SetGender(Gender.Male);
var hBox = new HBoxContainer(); UpdateGenderControls();
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);
} }
};
#endregion Age _sexFemaleButton = new Button
{
#region Gender Text = Loc.GetString("Female"),
Group = sexButtonGroup
};
_sexFemaleButton.OnPressed += args =>
{
SetSex(Sex.Female);
if (Profile.Gender == Gender.Male)
{ {
var panel = HighlightedContainer(); SetGender(Gender.Female);
var hBox = new HBoxContainer(); UpdateGenderControls();
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);
} }
};
#endregion Gender sexHBox.AddChild(sexLabel);
sexHBox.AddChild(_sexMaleButton);
sexHBox.AddChild(_sexFemaleButton);
sexPanel.AddChild(sexHBox);
sexAndAgeRow.AddChild(sexPanel);
#region Hair #endregion Sex
{ #region Age
var panel = HighlightedContainer();
panel.HorizontalAlignment = HAlignment.Left;
var hairHBox = new HBoxContainer();
_hairPicker = new HairStylePicker(); var agePanel = HighlightedContainer();
_hairPicker.Populate(); 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 => #endregion Age
{
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithHairStyleName(newStyle));
IsDirty = true;
};
_hairPicker.OnHairColorPicked += newColor => #region Gender
{
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithHairColor(newColor));
IsDirty = true;
};
_facialHairPicker = new FacialHairStylePicker(); var genderPanel = HighlightedContainer();
_facialHairPicker.Populate(); var genderHBox = new HBoxContainer();
var genderLabel = new Label { Text = Loc.GetString("Pronouns:") };
_facialHairPicker.OnHairStylePicked += newStyle => _genderButton = new OptionButton();
{
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithFacialHairStyleName(newStyle));
IsDirty = true;
};
_facialHairPicker.OnHairColorPicked += newColor => _genderButton.AddItem(Loc.GetString("He / Him"), (int) Gender.Male);
{ _genderButton.AddItem(Loc.GetString("She / Her"), (int) Gender.Female);
if (Profile is null) _genderButton.AddItem(Loc.GetString("They / Them"), (int) Gender.Epicene);
return; _genderButton.AddItem(Loc.GetString("It / It"), (int) Gender.Neuter);
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithFacialHairColor(newColor));
IsDirty = true;
};
hairHBox.AddChild(_hairPicker); _genderButton.OnItemSelected += args =>
hairHBox.AddChild(_facialHairPicker); {
_genderButton.SelectId(args.Id);
SetGender((Gender) args.Id);
};
panel.AddChild(hairHBox); genderHBox.AddChild(genderLabel);
appearanceVBox.AddChild(panel); genderHBox.AddChild(_genderButton);
} genderPanel.AddChild(genderHBox);
sexAndAgeRow.AddChild(genderPanel);
#endregion Hair #endregion Gender
#region Clothing #region Hair
{ var hairPanel = HighlightedContainer();
var panel = HighlightedContainer(); var hairHBox = new HBoxContainer();
var hBox = new HBoxContainer();
var clothingLabel = new Label {Text = Loc.GetString("Clothing:")};
_clothingButton = new OptionButton(); _hairPicker = new HairStylePicker
{
HorizontalAlignment = HAlignment.Center
};
_hairPicker.Populate();
_clothingButton.AddItem(Loc.GetString("Jumpsuit"), (int) ClothingPreference.Jumpsuit); _hairPicker.OnHairStylePicked += newStyle =>
_clothingButton.AddItem(Loc.GetString("Jumpskirt"), (int) ClothingPreference.Jumpskirt); {
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithHairStyleName(newStyle));
IsDirty = true;
};
_clothingButton.OnItemSelected += args => _hairPicker.OnHairColorPicked += newColor =>
{ {
_clothingButton.SelectId(args.Id); if (Profile is null)
SetClothing((ClothingPreference) args.Id); return;
}; Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithHairColor(newColor));
IsDirty = true;
};
hBox.AddChild(clothingLabel); _facialHairPicker = new FacialHairStylePicker();
hBox.AddChild(_clothingButton); _facialHairPicker.Populate();
panel.AddChild(hBox);
appearanceVBox.AddChild(panel);
}
#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;
};
{ hairHBox.AddChild(_hairPicker);
var panel = HighlightedContainer(); hairHBox.AddChild(_facialHairPicker);
var hBox = new HBoxContainer();
var backpackLabel = new Label {Text = Loc.GetString("Backpack:")};
_backpackButton = new OptionButton(); hairPanel.AddChild(hairHBox);
appearanceList.AddChild(hairPanel);
_backpackButton.AddItem(Loc.GetString("Backpack"), (int) BackpackPreference.Backpack); #endregion Hair
_backpackButton.AddItem(Loc.GetString("Satchel"), (int) BackpackPreference.Satchel);
_backpackButton.AddItem(Loc.GetString("Duffelbag"), (int) BackpackPreference.Duffelbag);
_backpackButton.OnItemSelected += args => #region Clothing
{
_backpackButton.SelectId(args.Id);
SetBackpack((BackpackPreference) args.Id);
};
hBox.AddChild(backpackLabel); var clothingPanel = HighlightedContainer();
hBox.AddChild(_backpackButton); var clothingHBox = new HBoxContainer();
panel.AddChild(hBox); var clothingLabel = new Label { Text = Loc.GetString("Clothing:") };
appearanceVBox.AddChild(panel);
}
#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 #region Jobs
{ var jobList = new VBoxContainer();
var jobList = new VBoxContainer();
var jobVBox = 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( _preferenceUnavailableButton.AddItem(
Loc.GetString("Stay in lobby if preference unavailable."), Loc.GetString("Stay in lobby if preference unavailable."),
(int) PreferenceUnavailableMode.StayInLobby); (int) PreferenceUnavailableMode.StayInLobby);
_preferenceUnavailableButton.AddItem( _preferenceUnavailableButton.AddItem(
Loc.GetString("Be an {0} if preference unavailable.", Loc.GetString("Be an {0} if preference unavailable.",
Loc.GetString(SharedGameTicker.OverflowJobName)), Loc.GetString(SharedGameTicker.OverflowJobName)),
(int) PreferenceUnavailableMode.SpawnAsOverflow); (int) PreferenceUnavailableMode.SpawnAsOverflow);
_preferenceUnavailableButton.OnItemSelected += args => _preferenceUnavailableButton.OnItemSelected += args =>
{
_preferenceUnavailableButton.SelectId(args.Id);
Profile = Profile.WithPreferenceUnavailable((PreferenceUnavailableMode) args.Id);
IsDirty = true;
};
_jobPriorities = new List<JobPrioritySelector>();
_jobCategories = new Dictionary<string, VBoxContainer>();
var firstCategory = true;
foreach (var job in prototypeManager.EnumeratePrototypes<JobPrototype>().OrderBy(j => j.Name))
{
foreach (var department in job.Departments)
{ {
_preferenceUnavailableButton.SelectId(args.Id); if (!_jobCategories.TryGetValue(department, out var category))
Profile = Profile.WithPreferenceUnavailable((PreferenceUnavailableMode) args.Id);
IsDirty = true;
};
_jobPriorities = new List<JobPrioritySelector>();
_jobCategories = new Dictionary<string, VBoxContainer>();
var firstCategory = true;
foreach (var job in prototypeManager.EnumeratePrototypes<JobPrototype>().OrderBy(j => j.Name))
{
foreach (var department in job.Departments)
{ {
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) if (firstCategory)
{ {
@@ -430,60 +452,58 @@ namespace Content.Client.UserInterface
}); });
} }
category.AddChild(new PanelContainer 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 =>
{ {
Profile = Profile.WithJobPriority(job.ID, priority); PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#464966")},
IsDirty = true; Children =
foreach (var jobSelector in _jobPriorities)
{ {
// Sync other selectors with the same job in case of multiple department jobs new Label
if (jobSelector.Job == selector.Job)
{ {
jobSelector.Priority = priority; Text = Loc.GetString("{0} jobs", department)
}
// 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);
}
} }
} }
}; });
_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 #region Antags
{ var antagList = new VBoxContainer();
var antagList = new VBoxContainer();
var antagVBox = 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<AntagPreferenceSelector>(); _antagPreferences = new List<AntagPreferenceSelector>();
foreach (var antag in prototypeManager.EnumeratePrototypes<AntagPrototype>().OrderBy(a => a.Name)) foreach (var antag in prototypeManager.EnumeratePrototypes<AntagPrototype>().OrderBy(a => a.Name))
{ {
@@ -517,41 +537,38 @@ namespace Content.Client.UserInterface
antagList.AddChild(selector); antagList.AddChild(selector);
_antagPreferences.Add(selector); _antagPreferences.Add(selector);
selector.PreferenceChanged += preference => selector.PreferenceChanged += preference =>
{ {
Profile = Profile.WithAntagPreference(antag.ID, preference); Profile = Profile.WithAntagPreference(antag.ID, preference);
IsDirty = true; IsDirty = true;
}; };
}
} }
#endregion #endregion Antags
var rightColumn = new VBoxContainer(); var rightColumn = new VBoxContainer();
middleContainer.AddChild(rightColumn); middleContainer.AddChild(rightColumn);
#region Import/Export #region Import/Export
var importExportPanelContainer = HighlightedContainer();
var importExportHBox = new HBoxContainer();
var importButton = new Button
{ {
var panelContainer = HighlightedContainer(); Text = Loc.GetString("Import"),
var hBox = new HBoxContainer(); Disabled = true,
var importButton = new Button ToolTip = "Not yet implemented!"
{ };
Text = Loc.GetString("Import"), var exportButton = new Button
Disabled = true, {
ToolTip = "Not yet implemented!" Text = Loc.GetString("Export"),
}; Disabled = true,
var exportButton = new Button ToolTip = "Not yet implemented!"
{ };
Text = Loc.GetString("Export"), importExportHBox.AddChild(importButton);
Disabled = true, importExportHBox.AddChild(exportButton);
ToolTip = "Not yet implemented!" importExportPanelContainer.AddChild(importExportHBox);
}; rightColumn.AddChild(importExportPanelContainer);
hBox.AddChild(importButton);
hBox.AddChild(exportButton);
panelContainer.AddChild(hBox);
rightColumn.AddChild(panelContainer);
}
#endregion Import/Export #endregion Import/Export
@@ -571,7 +588,7 @@ namespace Content.Client.UserInterface
#endregion Save #endregion Save
#endregion #endregion Left
#region Right #region Right
@@ -621,7 +638,7 @@ namespace Content.Client.UserInterface
}; };
box.AddChild(_previewSpriteSide); box.AddChild(_previewSpriteSide);
#endregion #endregion Right
#endregion #endregion
@@ -757,6 +774,11 @@ namespace Content.Client.UserInterface
Profile.Appearance.FacialHairStyleName); Profile.Appearance.FacialHairStyleName);
} }
private void UpdateEyePickers()
{
_eyesPicker.SetData(Profile.Appearance.EyeColor);
}
private void UpdateSaveButton() private void UpdateSaveButton()
{ {
_saveButton.Disabled = Profile is null || !IsDirty; _saveButton.Disabled = Profile is null || !IsDirty;
@@ -781,6 +803,7 @@ namespace Content.Client.UserInterface
UpdateBackpackControls(); UpdateBackpackControls();
UpdateAgeEdit(); UpdateAgeEdit();
UpdateHairPickers(); UpdateHairPickers();
UpdateEyePickers();
UpdateSaveButton(); UpdateSaveButton();
UpdateJobPriorities(); UpdateJobPriorities();
UpdateAntagPreferences(); UpdateAntagPreferences();

View File

@@ -1,4 +1,4 @@
#nullable enable #nullable enable
using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Mobs;
using Content.Server.Utility; using Content.Server.Utility;
using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components;
@@ -83,6 +83,14 @@ namespace Content.Server.GameObjects.Components
looks.Appearance = looks.Appearance.WithHairColor(color); 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; break;
} }
} }
@@ -103,7 +111,7 @@ namespace Content.Server.GameObjects.Components
UserInterface?.Toggle(actor.playerSession); UserInterface?.Toggle(actor.playerSession);
var msg = new MagicMirrorInitialDataMessage(looks.Appearance.HairColor, looks.Appearance.FacialHairColor, looks.Appearance.HairStyleName, 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); UserInterface?.SendMessage(msg, actor.playerSession);
} }

View File

@@ -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] [Serializable, NetSerializable]
public class MagicMirrorInitialDataMessage : BoundUserInterfaceMessage public class MagicMirrorInitialDataMessage : BoundUserInterfaceMessage
{ {
@@ -49,13 +60,15 @@ namespace Content.Shared.GameObjects.Components
public readonly Color FacialHairColor; public readonly Color FacialHairColor;
public readonly string HairName; public readonly string HairName;
public readonly string FacialHairName; 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; HairColor = hairColor;
FacialHairColor = facialHairColor; FacialHairColor = facialHairColor;
HairName = hairName; HairName = hairName;
FacialHairName = facialHairName; FacialHairName = facialHairName;
EyeColor = eyeColor;
} }
} }
} }