mirror of
https://github.com/space-wizards/space-station-14.git
synced 2026-02-15 03:31:30 +01:00
* separate humanoid profile editor into different files * move this to the rest of the fields
300 lines
9.1 KiB
C#
300 lines
9.1 KiB
C#
using System.Linq;
|
|
using Content.Client.UserInterface.Systems.Guidebook;
|
|
using Content.Shared.Guidebook;
|
|
using Content.Shared.Humanoid;
|
|
using Content.Shared.Humanoid.Prototypes;
|
|
using Content.Shared.Preferences;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Shared.Enums;
|
|
using Robust.Shared.Prototypes;
|
|
|
|
namespace Content.Client.Lobby.UI;
|
|
|
|
public sealed partial class HumanoidProfileEditor
|
|
{
|
|
public event Action<List<ProtoId<GuideEntryPrototype>>>? OnOpenGuidebook;
|
|
|
|
private ColorSelectorSliders _rgbSkinColorSelector;
|
|
private List<SpeciesPrototype> _species = new();
|
|
private static readonly ProtoId<GuideEntryPrototype> DefaultSpeciesGuidebook = "Species";
|
|
|
|
public void UpdateSpeciesGuidebookIcon()
|
|
{
|
|
SpeciesInfoButton.StyleClasses.Clear();
|
|
|
|
var species = Profile?.Species;
|
|
if (species is null)
|
|
return;
|
|
|
|
if (!_prototypeManager.Resolve<SpeciesPrototype>(species, out var speciesProto))
|
|
return;
|
|
|
|
// Don't display the info button if no guide entry is found
|
|
if (!_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
|
return;
|
|
|
|
const string style = "SpeciesInfoDefault";
|
|
SpeciesInfoButton.StyleIdentifier = style;
|
|
}
|
|
|
|
private void UpdateGenderControls()
|
|
{
|
|
if (Profile == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
PronounsButton.SelectId((int)Profile.Gender);
|
|
}
|
|
|
|
private void UpdateAgeEdit()
|
|
{
|
|
AgeEdit.Text = Profile?.Age.ToString() ?? "";
|
|
}
|
|
|
|
private void UpdateSexControls()
|
|
{
|
|
if (Profile == null)
|
|
return;
|
|
|
|
SexButton.Clear();
|
|
|
|
var sexes = new List<Sex>();
|
|
|
|
// add species sex options, default to just none if we are in bizzaro world and have no species
|
|
if (_prototypeManager.Resolve(Profile.Species, out var speciesProto))
|
|
{
|
|
foreach (var sex in speciesProto.Sexes)
|
|
{
|
|
sexes.Add(sex);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sexes.Add(Sex.Unsexed);
|
|
}
|
|
|
|
// add button for each sex
|
|
foreach (var sex in sexes)
|
|
{
|
|
SexButton.AddItem(Loc.GetString($"humanoid-profile-editor-sex-{sex.ToString().ToLower()}-text"), (int)sex);
|
|
}
|
|
|
|
if (sexes.Contains(Profile.Sex))
|
|
SexButton.SelectId((int)Profile.Sex);
|
|
else
|
|
SexButton.SelectId((int)sexes[0]);
|
|
}
|
|
|
|
private void UpdateEyePickers()
|
|
{
|
|
if (Profile == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_markingsModel.SetOrganEyeColor(Profile.Appearance.EyeColor);
|
|
EyeColorPicker.SetData(Profile.Appearance.EyeColor);
|
|
}
|
|
|
|
private void UpdateSkinColor()
|
|
{
|
|
if (Profile == null)
|
|
return;
|
|
|
|
var skin = _prototypeManager.Index<SpeciesPrototype>(Profile.Species).SkinColoration;
|
|
var strategy = _prototypeManager.Index(skin).Strategy;
|
|
|
|
switch (strategy.InputType)
|
|
{
|
|
case SkinColorationStrategyInput.Unary:
|
|
{
|
|
if (!Skin.Visible)
|
|
{
|
|
Skin.Visible = true;
|
|
RgbSkinColorContainer.Visible = false;
|
|
}
|
|
|
|
Skin.Value = strategy.ToUnary(Profile.Appearance.SkinColor);
|
|
|
|
break;
|
|
}
|
|
case SkinColorationStrategyInput.Color:
|
|
{
|
|
if (!RgbSkinColorContainer.Visible)
|
|
{
|
|
Skin.Visible = false;
|
|
RgbSkinColorContainer.Visible = true;
|
|
}
|
|
|
|
_rgbSkinColorSelector.Color = strategy.ClosestSkinColor(Profile.Appearance.SkinColor);
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UpdateSpawnPriorityControls()
|
|
{
|
|
if (Profile == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
SpawnPriorityButton.SelectId((int)Profile.SpawnPriority);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Refreshes the species selector.
|
|
/// </summary>
|
|
public void RefreshSpecies()
|
|
{
|
|
SpeciesButton.Clear();
|
|
_species.Clear();
|
|
|
|
_species.AddRange(_prototypeManager.EnumeratePrototypes<SpeciesPrototype>().Where(o => o.RoundStart));
|
|
_species.Sort((a, b) => string.Compare(a.Name, b.Name, StringComparison.CurrentCultureIgnoreCase));
|
|
var speciesIds = _species.Select(o => o.ID).ToList();
|
|
|
|
for (var i = 0; i < _species.Count; i++)
|
|
{
|
|
var name = Loc.GetString(_species[i].Name);
|
|
SpeciesButton.AddItem(name, i);
|
|
|
|
if (Profile?.Species.Equals(_species[i].ID) == true)
|
|
{
|
|
SpeciesButton.SelectId(i);
|
|
}
|
|
}
|
|
|
|
// If our species isn't available then reset it to default.
|
|
if (Profile != null)
|
|
{
|
|
if (!speciesIds.Contains(Profile.Species))
|
|
{
|
|
SetSpecies(HumanoidCharacterProfile.DefaultSpecies);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SetSpecies(string newSpecies)
|
|
{
|
|
Profile = Profile?.WithSpecies(newSpecies);
|
|
OnSkinColorOnValueChanged(); // Species may have special color prefs, make sure to update it.
|
|
_markingsModel.OrganData = _markingManager.GetMarkingData(newSpecies);
|
|
_markingsModel.ValidateMarkings();
|
|
// In case there's job restrictions for the species
|
|
RefreshJobs();
|
|
// In case there's species restrictions for loadouts
|
|
RefreshLoadouts();
|
|
UpdateSexControls(); // update sex for new species
|
|
UpdateSpeciesGuidebookIcon();
|
|
ReloadPreview();
|
|
}
|
|
|
|
private void SetAge(int newAge)
|
|
{
|
|
Profile = Profile?.WithAge(newAge);
|
|
ReloadPreview();
|
|
}
|
|
|
|
private void SetSex(Sex newSex)
|
|
{
|
|
Profile = Profile?.WithSex(newSex);
|
|
// for convenience, default to most common gender when new sex is selected
|
|
switch (newSex)
|
|
{
|
|
case Sex.Male:
|
|
Profile = Profile?.WithGender(Gender.Male);
|
|
break;
|
|
case Sex.Female:
|
|
Profile = Profile?.WithGender(Gender.Female);
|
|
break;
|
|
default:
|
|
Profile = Profile?.WithGender(Gender.Epicene);
|
|
break;
|
|
}
|
|
|
|
UpdateGenderControls();
|
|
_markingsModel.SetOrganSexes(newSex);
|
|
ReloadPreview();
|
|
}
|
|
|
|
private void SetGender(Gender newGender)
|
|
{
|
|
Profile = Profile?.WithGender(newGender);
|
|
ReloadPreview();
|
|
}
|
|
|
|
private void SetSpawnPriority(SpawnPriorityPreference newSpawnPriority)
|
|
{
|
|
Profile = Profile?.WithSpawnPriorityPreference(newSpawnPriority);
|
|
SetDirty();
|
|
}
|
|
|
|
private void OnSpeciesInfoButtonPressed(BaseButton.ButtonEventArgs args)
|
|
{
|
|
// TODO GUIDEBOOK
|
|
// make the species guide book a field on the species prototype.
|
|
// I.e., do what jobs/antags do.
|
|
|
|
var guidebookController = UserInterfaceManager.GetUIController<GuidebookUIController>();
|
|
var species = Profile?.Species ?? HumanoidCharacterProfile.DefaultSpecies;
|
|
var page = DefaultSpeciesGuidebook;
|
|
if (_prototypeManager.HasIndex<GuideEntryPrototype>(species))
|
|
page = new ProtoId<GuideEntryPrototype>(species.Id); // Gross. See above todo comment.
|
|
|
|
if (_prototypeManager.Resolve(DefaultSpeciesGuidebook, out var guideRoot))
|
|
{
|
|
var dict = new Dictionary<ProtoId<GuideEntryPrototype>, GuideEntry>();
|
|
dict.Add(DefaultSpeciesGuidebook, guideRoot);
|
|
//TODO: Don't close the guidebook if its already open, just go to the correct page
|
|
guidebookController.OpenGuidebook(dict, includeChildren: true, selected: page);
|
|
}
|
|
}
|
|
|
|
private void OnSkinColorOnValueChanged()
|
|
{
|
|
if (Profile is null) return;
|
|
|
|
var skin = _prototypeManager.Index<SpeciesPrototype>(Profile.Species).SkinColoration;
|
|
var strategy = _prototypeManager.Index(skin).Strategy;
|
|
|
|
switch (strategy.InputType)
|
|
{
|
|
case SkinColorationStrategyInput.Unary:
|
|
{
|
|
if (!Skin.Visible)
|
|
{
|
|
Skin.Visible = true;
|
|
RgbSkinColorContainer.Visible = false;
|
|
}
|
|
|
|
var color = strategy.FromUnary(Skin.Value);
|
|
|
|
_markingsModel.SetOrganSkinColor(color);
|
|
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
|
|
|
|
break;
|
|
}
|
|
case SkinColorationStrategyInput.Color:
|
|
{
|
|
if (!RgbSkinColorContainer.Visible)
|
|
{
|
|
Skin.Visible = false;
|
|
RgbSkinColorContainer.Visible = true;
|
|
}
|
|
|
|
var color = strategy.ClosestSkinColor(_rgbSkinColorSelector.Color);
|
|
|
|
_markingsModel.SetOrganSkinColor(color);
|
|
Profile = Profile.WithCharacterAppearance(Profile.Appearance.WithSkinColor(color));
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
ReloadProfilePreview();
|
|
}
|
|
}
|