Upstream species (#6066)
* Step 1 of porting; grabbed most of the files via patches. * Add species field to the DB * Appearance patches for slimes. * Fix the db test. * Add slime's biocompat. * slimby * Fixes, allow specifying if a species is playable or not. * Update Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs Co-authored-by: Javier Guardia Fernández <DrSmugleaf@users.noreply.github.com> * Update Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs Co-authored-by: Javier Guardia Fernández <DrSmugleaf@users.noreply.github.com> * Update Content.Client/Preferences/UI/HumanoidProfileEditor.xaml.cs Co-authored-by: Javier Guardia Fernández <DrSmugleaf@users.noreply.github.com> * Address reviews. * Address reviews. * make an if-case. * Fix a goof where species wouldn't get shown in the editor correctly (it'd always default to human) Co-authored-by: Javier Guardia Fernández <DrSmugleaf@users.noreply.github.com>
This commit is contained in:
@@ -10,6 +10,7 @@ using Content.Shared.CharacterAppearance.Systems;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
using Content.Shared.Species;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
@@ -28,6 +29,7 @@ using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||
using Range = Robust.Client.UserInterface.Controls.Range;
|
||||
|
||||
namespace Content.Client.Preferences.UI
|
||||
{
|
||||
@@ -55,6 +57,7 @@ namespace Content.Client.Preferences.UI
|
||||
private Button _randomizeEverythingButton => CRandomizeEverything;
|
||||
private RichTextLabel _warningLabel => CWarningLabel;
|
||||
private readonly IClientPreferencesManager _preferencesManager;
|
||||
private readonly IEntityManager _entMan;
|
||||
private Button _saveButton => CSaveButton;
|
||||
private Button _sexFemaleButton => CSexFemale;
|
||||
private Button _sexMaleButton => CSexMale;
|
||||
@@ -72,14 +75,15 @@ namespace Content.Client.Preferences.UI
|
||||
private readonly List<JobPrioritySelector> _jobPriorities;
|
||||
private OptionButton _preferenceUnavailableButton => CPreferenceUnavailableButton;
|
||||
private readonly Dictionary<string, BoxContainer> _jobCategories;
|
||||
|
||||
// Mildly hacky, as I don't trust prototype order to stay consistent and don't want the UI to break should a new one get added mid-edit. --moony
|
||||
private readonly List<SpeciesPrototype> _speciesList;
|
||||
private readonly List<AntagPreferenceSelector> _antagPreferences;
|
||||
|
||||
private readonly EntityUid _previewDummy;
|
||||
private EntityUid _previewDummy;
|
||||
private Control _previewSpriteControl => CSpriteViewFront;
|
||||
private Control _previewSpriteSideControl => CSpriteViewSide;
|
||||
private readonly SpriteView _previewSprite;
|
||||
private readonly SpriteView _previewSpriteSide;
|
||||
private SpriteView? _previewSprite;
|
||||
private SpriteView? _previewSpriteSide;
|
||||
|
||||
private bool _isDirty;
|
||||
private bool _needUpdatePreview;
|
||||
@@ -94,7 +98,7 @@ namespace Content.Client.Preferences.UI
|
||||
RobustXamlLoader.Load(this);
|
||||
_random = IoCManager.Resolve<IRobustRandom>();
|
||||
_prototypeManager = prototypeManager;
|
||||
|
||||
_entMan = entityManager;
|
||||
_preferencesManager = preferencesManager;
|
||||
|
||||
#region Left
|
||||
@@ -171,6 +175,23 @@ namespace Content.Client.Preferences.UI
|
||||
|
||||
#endregion Gender
|
||||
|
||||
#region Species
|
||||
|
||||
_speciesList = prototypeManager.EnumeratePrototypes<SpeciesPrototype>().ToList();
|
||||
for (var i = 0; i < _speciesList.Count; i++)
|
||||
{
|
||||
CSpeciesButton.AddItem(_speciesList[i].Name, i);
|
||||
}
|
||||
|
||||
CSpeciesButton.OnItemSelected += args =>
|
||||
{
|
||||
CSpeciesButton.SelectId(args.Id);
|
||||
SetSpecies(_speciesList[args.Id].ID);
|
||||
OnSkinColorOnValueChanged(CSkin);
|
||||
};
|
||||
|
||||
#endregion Species
|
||||
|
||||
#region Skin
|
||||
|
||||
// 0 - 100, 0 being gold/yellowish and 100 being dark
|
||||
@@ -181,33 +202,7 @@ namespace Content.Client.Preferences.UI
|
||||
// 0 is 45 - 20 - 100
|
||||
// 20 is 25 - 20 - 100
|
||||
// 100 is 25 - 100 - 20
|
||||
_skinColor.OnValueChanged += range =>
|
||||
{
|
||||
if (Profile is null)
|
||||
return;
|
||||
|
||||
int rangeOffset = (int) range.Value - 20;
|
||||
|
||||
float hue = 25;
|
||||
float sat = 20;
|
||||
float val = 100;
|
||||
|
||||
if (rangeOffset < 0)
|
||||
{
|
||||
hue += Math.Abs(rangeOffset);
|
||||
}
|
||||
else if (rangeOffset > 0)
|
||||
{
|
||||
sat += rangeOffset;
|
||||
val -= rangeOffset;
|
||||
}
|
||||
|
||||
var color = Color.FromHsv(new Vector4(hue / 360, sat / 100, val / 100, 1.0f));
|
||||
|
||||
Profile = Profile.WithCharacterAppearance(
|
||||
Profile.Appearance.WithSkinColor(color));
|
||||
IsDirty = true;
|
||||
};
|
||||
_skinColor.OnValueChanged += OnSkinColorOnValueChanged;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -434,12 +429,76 @@ namespace Content.Client.Preferences.UI
|
||||
|
||||
#endregion Left
|
||||
|
||||
#region Right
|
||||
if (preferencesManager.ServerDataLoaded)
|
||||
{
|
||||
LoadServerData();
|
||||
}
|
||||
|
||||
#region Preview
|
||||
preferencesManager.OnServerDataLoaded += LoadServerData;
|
||||
|
||||
_previewDummy = entityManager.SpawnEntity("MobHumanDummy", MapCoordinates.Nullspace);
|
||||
var sprite = IoCManager.Resolve<IEntityManager>().GetComponent<SpriteComponent>(_previewDummy);
|
||||
IsDirty = false;
|
||||
}
|
||||
|
||||
private void OnSkinColorOnValueChanged(Range range)
|
||||
{
|
||||
if (Profile is null) return;
|
||||
|
||||
var skin = _prototypeManager.Index<SpeciesPrototype>(Profile.Species).SkinColoration;
|
||||
|
||||
switch (skin)
|
||||
{
|
||||
case SpeciesSkinColor.HumanToned:
|
||||
{
|
||||
var rangeOffset = (int) range.Value - 20;
|
||||
|
||||
float hue = 25;
|
||||
float sat = 20;
|
||||
float val = 100;
|
||||
|
||||
if (rangeOffset <= 0)
|
||||
{
|
||||
hue += Math.Abs(rangeOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
sat += rangeOffset;
|
||||
val -= rangeOffset;
|
||||
}
|
||||
|
||||
var color = Color.FromHsv(new Vector4(hue / 360, sat / 100, val / 100, 1.0f));
|
||||
|
||||
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
|
||||
break;
|
||||
}
|
||||
case SpeciesSkinColor.Hues:
|
||||
{
|
||||
var color = Color.FromHsv(new Vector4(range.Value / 100.0f, 1.0f, 1.0f, 1.0f));
|
||||
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_entMan.DeleteEntity(_previewDummy);
|
||||
_preferencesManager.OnServerDataLoaded -= LoadServerData;
|
||||
}
|
||||
|
||||
private void RebuildSpriteView()
|
||||
{
|
||||
var dollProto = _prototypeManager.Index<SpeciesPrototype>(Profile?.Species ?? SpeciesManager.DefaultSpecies).DollPrototype;
|
||||
_previewDummy = _entMan.SpawnEntity(dollProto, MapCoordinates.Nullspace);
|
||||
|
||||
var sprite = _entMan.GetComponent<SpriteComponent>(_previewDummy);
|
||||
|
||||
_previewSpriteControl.DisposeAllChildren();
|
||||
|
||||
// Front
|
||||
_previewSprite = new SpriteView
|
||||
@@ -452,6 +511,8 @@ namespace Content.Client.Preferences.UI
|
||||
};
|
||||
_previewSpriteControl.AddChild(_previewSprite);
|
||||
|
||||
_previewSpriteSideControl.DisposeAllChildren();
|
||||
|
||||
// Side
|
||||
_previewSpriteSide = new SpriteView
|
||||
{
|
||||
@@ -462,29 +523,6 @@ namespace Content.Client.Preferences.UI
|
||||
SizeFlagsStretchRatio = 1
|
||||
};
|
||||
_previewSpriteSideControl.AddChild(_previewSpriteSide);
|
||||
|
||||
#endregion Right
|
||||
|
||||
#endregion
|
||||
|
||||
if (preferencesManager.ServerDataLoaded)
|
||||
{
|
||||
LoadServerData();
|
||||
}
|
||||
|
||||
preferencesManager.OnServerDataLoaded += LoadServerData;
|
||||
|
||||
IsDirty = false;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
IoCManager.Resolve<IEntityManager>().DeleteEntity((EntityUid) _previewDummy);
|
||||
_preferencesManager.OnServerDataLoaded -= LoadServerData;
|
||||
}
|
||||
|
||||
private void LoadServerData()
|
||||
@@ -512,6 +550,13 @@ namespace Content.Client.Preferences.UI
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
private void SetSpecies(string newSpecies)
|
||||
{
|
||||
Profile = Profile?.WithSpecies(newSpecies);
|
||||
OnSkinColorOnValueChanged(CSkin); // Species may have special color prefs, make sure to update it.
|
||||
IsDirty = true;
|
||||
}
|
||||
|
||||
private void SetName(string newName)
|
||||
{
|
||||
Profile = Profile?.WithName(newName);
|
||||
@@ -576,20 +621,45 @@ namespace Content.Client.Preferences.UI
|
||||
if (Profile == null)
|
||||
return;
|
||||
|
||||
var skin = _prototypeManager.Index<SpeciesPrototype>(Profile.Species).SkinColoration;
|
||||
var color = Color.ToHsv(Profile.Appearance.SkinColor);
|
||||
// check for hue/value first, if hue is lower than this percentage
|
||||
// and value is 1.0
|
||||
// then it'll be hue
|
||||
if (Math.Clamp(color.X, 25f / 360f, 1) > 25f / 360f
|
||||
&& color.Z == 1.0)
|
||||
|
||||
switch (skin)
|
||||
{
|
||||
_skinColor.Value = Math.Abs(45 - (color.X * 360));
|
||||
case SpeciesSkinColor.HumanToned:
|
||||
{
|
||||
// check for hue/value first, if hue is lower than this percentage
|
||||
// and value is 1.0
|
||||
// then it'll be hue
|
||||
if (Math.Clamp(color.X, 25f / 360f, 1) > 25f / 360f
|
||||
&& color.Z == 1.0)
|
||||
{
|
||||
_skinColor.Value = Math.Abs(45 - (color.X * 360));
|
||||
}
|
||||
// otherwise it'll directly be the saturation
|
||||
else
|
||||
{
|
||||
_skinColor.Value = color.Y * 100;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpeciesSkinColor.Hues:
|
||||
{
|
||||
_skinColor.Value = color.X * 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// otherwise it'll directly be the saturation
|
||||
else
|
||||
|
||||
}
|
||||
|
||||
private void UpdateSpecies()
|
||||
{
|
||||
if (Profile == null)
|
||||
{
|
||||
_skinColor.Value = color.Y * 100;
|
||||
return;
|
||||
}
|
||||
|
||||
CSpeciesButton.Select(_speciesList.FindIndex(x => x.ID == Profile.Species));
|
||||
}
|
||||
|
||||
private void UpdateGenderControls()
|
||||
@@ -660,6 +730,7 @@ namespace Content.Client.Preferences.UI
|
||||
{
|
||||
if (Profile is null)
|
||||
return;
|
||||
RebuildSpriteView();
|
||||
|
||||
EntitySystem.Get<SharedHumanoidAppearanceSystem>().UpdateFromProfile(_previewDummy, Profile);
|
||||
LobbyCharacterPreviewPanel.GiveDummyJobClothes(_previewDummy, Profile);
|
||||
@@ -672,6 +743,7 @@ namespace Content.Client.Preferences.UI
|
||||
UpdateSexControls();
|
||||
UpdateGenderControls();
|
||||
UpdateSkinColor();
|
||||
UpdateSpecies();
|
||||
UpdateClothingControls();
|
||||
UpdateBackpackControls();
|
||||
UpdateAgeEdit();
|
||||
|
||||
Reference in New Issue
Block a user