From f0463062812428625da9e8adad60c8a567fdacbe Mon Sep 17 00:00:00 2001 From: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> Date: Sun, 24 Nov 2024 21:43:25 -0800 Subject: [PATCH 1/2] Loadouts V4 (#1164) # Description # TODO - [x] Custom name/desc/color tint, toggleable individually per-loadout - [x] Fix them not changing correctly between profiles in-editor - [x] Preview colors in the lobby - [x] Allow the users to null the color themselves (and default it to such) - [x] Pick what should be allowed to be recolored - [x] Guidebook links - [x] Make an example - [x] Special components for loadouts - [x] Heirlooms - [x] Pick what should have heirlooms - [x] Decimate lag - [x] Fix live character preview - Maybe do characters per job - Rethink unusable ---

Media

https://github.com/user-attachments/assets/bcf61517-6b64-40d2-b299-7462e2469fe2

--- # Changelog :cl: - add: Players can set custom names, descriptions, and color tints for their loadout items - add: Certain loadouts may have Guidebook pages shown in the editor - add: Players can pick a list of loadout items to have one randomly be their family heirloom for a mood bonus or deficit if they are carrying it - fix: Loadouts have almost as little lag as possible (hopefully none) - fix: Everything properly updates your character editor's live preview --------- Signed-off-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: VMSolidus Co-authored-by: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com> --- Content.Client/Lobby/LobbyUIController.cs | 24 +- .../Lobby/UI/CharacterPickerButton.xaml.cs | 2 +- .../Lobby/UI/HumanoidProfileEditor.xaml.cs | 73 +- .../Lobby/UI/LoadoutPreferenceSelector.xaml | 81 +- .../UI/LoadoutPreferenceSelector.xaml.cs | 160 +- .../Lobby/UI/TraitPreferenceSelector.xaml.cs | 2 +- .../Controls/ResizableControl.cs | 151 ++ .../Controls/StyledButtonGroup.cs | 43 + .../Controls/StyledButtonGroup.xaml | 5 + .../Content.Server.Database.csproj | 1 + ...tomLoadoutNameDescriptionColor.Designer.cs | 1908 ++++++++++++++++ ...25707_CustomLoadoutNameDescriptionColor.cs | 48 + ...6073335_CustomLoadoutHeirlooms.Designer.cs | 1912 +++++++++++++++++ .../20241106073335_CustomLoadoutHeirlooms.cs | 28 + .../PostgresServerDbContextModelSnapshot.cs | 16 + ...tomLoadoutNameDescriptionColor.Designer.cs | 1835 ++++++++++++++++ ...25658_CustomLoadoutNameDescriptionColor.cs | 48 + ...6073327_CustomLoadoutHeirlooms.Designer.cs | 1839 ++++++++++++++++ .../20241106073327_CustomLoadoutHeirlooms.cs | 28 + .../SqliteServerDbContextModelSnapshot.cs | 16 + Content.Server.Database/Model.cs | 13 +- Content.Server.Database/remove-migration.ps1 | 12 + Content.Server.Database/remove-migration.sh | 9 + .../Clothing/Systems/LoadoutSystem.cs | 84 +- Content.Server/Database/ServerDbBase.cs | 15 +- Content.Server/Paint/PaintSystem.cs | 10 +- .../Traits/Assorted/HeirloomSystem.cs | 56 + .../Loadouts/Prototypes/LoadoutPrototype.cs | 26 +- ...oadoutSystem.cs => SharedLoadoutSystem.cs} | 98 +- .../Systems/CharacterRequirements.Job.cs | 116 +- .../Systems/CharacterRequirements.Logic.cs | 77 +- .../Systems/CharacterRequirements.Profile.cs | 182 +- .../CharacterRequirements.Whitelist.cs | 16 +- .../Systems/CharacterRequirements.cs | 2 +- .../Systems/CharacterRequirementsSystem.cs | 12 +- .../Preferences/HumanoidCharacterProfile.cs | 26 +- .../Prototypes/CharacterItemGroupPrototype.cs | 3 +- .../Assorted/Components/HeirloomComponents.cs | 22 + Resources/Locale/en-US/guidebook/guides.ftl | 3 + Resources/Locale/en-US/loadouts/eyes.ftl | 4 +- Resources/Locale/en-US/mood/mood.ftl | 3 + .../ui/humanoid-profile-editor.ftl | 10 +- .../Jobs/Medical/uncategorized.yml | 2 + .../Guidebook/Loadouts/loadoutInfo.yml | 11 + Resources/Prototypes/Guidebook/ss14.yml | 3 +- .../Prototypes/Loadouts/Generic/eyes.yml | 3 + .../Prototypes/Loadouts/Generic/hands.yml | 4 + .../Prototypes/Loadouts/Generic/head.yml | 9 + .../Prototypes/Loadouts/Generic/items.yml | 3 + .../Prototypes/Loadouts/Generic/mask.yml | 2 + .../Prototypes/Loadouts/Generic/neck.yml | 12 + .../Loadouts/Generic/outerClothing.yml | 4 + .../Prototypes/Loadouts/Generic/shoes.yml | 9 + .../Prototypes/Loadouts/Generic/uniform.yml | 19 + .../Loadouts/Jobs/Command/captain.yml | 5 + .../Loadouts/Jobs/Command/headOfPersonnel.yml | 4 + .../Loadouts/Jobs/Command/uncategorized.yml | 1 + .../Engineering/atmosphericTechnician.yml | 1 + .../Jobs/Engineering/uncategorized.yml | 1 + .../Loadouts/Jobs/Epistemics/chaplain.yml | 3 + .../Loadouts/Jobs/Epistemics/mystic.yml | 1 + .../Jobs/Epistemics/uncategorized.yml | 3 + .../Jobs/Logistics/salvageSpecialist.yml | 1 + .../Loadouts/Jobs/Medical/chemist.yml | 1 + .../Loadouts/Jobs/Medical/uncategorized.yml | 17 + .../Loadouts/Jobs/Security/headOfSecurity.yml | 7 + .../Loadouts/Jobs/Security/uncategorized.yml | 26 + .../Loadouts/Jobs/Service/bartender.yml | 2 + .../Loadouts/Jobs/Service/clown.yml | 20 + .../Prototypes/Loadouts/Jobs/Service/mime.yml | 12 + .../Loadouts/Jobs/Service/musician.yml | 47 + Resources/Prototypes/Mood/categories.yml | 11 +- Resources/Prototypes/Mood/drugs.yml | 6 - .../Mood/genericNegativeEffects.yml | 5 + .../Mood/genericPositiveEffects.yml | 7 + .../Eyes/LoadoutInfoLoadoutEyesEyepatch.xml | 4 + .../Guidebook/LoadoutInfo/LoadoutInfo.xml | 4 + 77 files changed, 9009 insertions(+), 280 deletions(-) create mode 100644 Content.Client/UserInterface/Controls/ResizableControl.cs create mode 100644 Content.Client/UserInterface/Controls/StyledButtonGroup.cs create mode 100644 Content.Client/UserInterface/Controls/StyledButtonGroup.xaml create mode 100644 Content.Server.Database/Migrations/Postgres/20241029025707_CustomLoadoutNameDescriptionColor.Designer.cs create mode 100644 Content.Server.Database/Migrations/Postgres/20241029025707_CustomLoadoutNameDescriptionColor.cs create mode 100644 Content.Server.Database/Migrations/Postgres/20241106073335_CustomLoadoutHeirlooms.Designer.cs create mode 100644 Content.Server.Database/Migrations/Postgres/20241106073335_CustomLoadoutHeirlooms.cs create mode 100644 Content.Server.Database/Migrations/Sqlite/20241029025658_CustomLoadoutNameDescriptionColor.Designer.cs create mode 100644 Content.Server.Database/Migrations/Sqlite/20241029025658_CustomLoadoutNameDescriptionColor.cs create mode 100644 Content.Server.Database/Migrations/Sqlite/20241106073327_CustomLoadoutHeirlooms.Designer.cs create mode 100644 Content.Server.Database/Migrations/Sqlite/20241106073327_CustomLoadoutHeirlooms.cs create mode 100755 Content.Server.Database/remove-migration.ps1 create mode 100755 Content.Server.Database/remove-migration.sh create mode 100644 Content.Server/Traits/Assorted/HeirloomSystem.cs rename Content.Shared/Clothing/Loadouts/Systems/{LoadoutSystem.cs => SharedLoadoutSystem.cs} (58%) create mode 100644 Content.Shared/Traits/Assorted/Components/HeirloomComponents.cs create mode 100644 Resources/Prototypes/Guidebook/Loadouts/loadoutInfo.yml create mode 100644 Resources/ServerInfo/Guidebook/LoadoutInfo/Eyes/LoadoutInfoLoadoutEyesEyepatch.xml create mode 100644 Resources/ServerInfo/Guidebook/LoadoutInfo/LoadoutInfo.xml diff --git a/Content.Client/Lobby/LobbyUIController.cs b/Content.Client/Lobby/LobbyUIController.cs index 26643cb603cd11..7f3ad60c3dac64 100644 --- a/Content.Client/Lobby/LobbyUIController.cs +++ b/Content.Client/Lobby/LobbyUIController.cs @@ -41,7 +41,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered() - .LoadProfileEntity(humanoid, true); + .LoadProfileEntity(humanoid, true, true); var highPriorityJob = humanoid.JobPriorities.SingleOrDefault(p => p.Value == JobPriority.High).Key; if (highPriorityJob != null) diff --git a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs index c4e1e1fc13b97e..f23fd6b4a0ded7 100644 --- a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs +++ b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs @@ -11,6 +11,7 @@ using Content.Shared.CCVar; using Content.Shared.Clothing.Components; using Content.Shared.Clothing.Loadouts.Prototypes; +using Content.Shared.Clothing.Loadouts.Systems; using Content.Shared.Customization.Systems; using Content.Shared.GameTicking; using Content.Shared.Humanoid; @@ -76,7 +77,7 @@ public sealed partial class HumanoidProfileEditor : BoxContainer private Dictionary _confirmationData = new(); private List _traitPreferences = new(); private int _traitCount; - private List _loadoutPreferences = new(); + private HashSet _loadoutPreferences = new(); private Direction _previewRotation = Direction.North; private ColorSelectorSliders _rgbSkinColorSelector; @@ -427,7 +428,7 @@ public HumanoidProfileEditor( // Set up the loadouts tab LoadoutsTab.Orphan(); CTabContainer.AddTab(LoadoutsTab, Loc.GetString("humanoid-profile-editor-loadouts-tab")); - _loadoutPreferences = new List(); + _loadoutPreferences = new(); // Show/Hide the loadouts tab if they ever get enabled/disabled var loadoutsEnabled = cfgManager.GetCVar(CCVars.GameLoadoutsEnabled); @@ -473,7 +474,8 @@ public HumanoidProfileEditor( #endregion Left - ShowClothes.OnToggled += args => { ReloadProfilePreview(); }; + ShowClothes.OnToggled += _ => { SetProfile(Profile, CharacterSlot); }; + ShowLoadouts.OnToggled += _ => { SetProfile(Profile, CharacterSlot); }; SpeciesInfoButton.OnPressed += OnSpeciesInfoButtonPressed; UpdateSpeciesGuidebookIcon(); @@ -614,7 +616,7 @@ private void ReloadPreview() if (Profile == null || !_prototypeManager.HasIndex(Profile.Species)) return; - PreviewDummy = _controller.LoadProfileEntity(Profile, ShowClothes.Pressed); + PreviewDummy = _controller.LoadProfileEntity(Profile, ShowClothes.Pressed, ShowLoadouts.Pressed); SpriteView.SetEntity(PreviewDummy); } @@ -823,20 +825,6 @@ public void RefreshJobs() UpdateJobPriorities(); } - private void ToggleClothes(BaseButton.ButtonEventArgs _) - { - //TODO: Optimization - // _controller.ShowClothes = ShowClothes.Pressed; - // _controller.UpdateCharacterUI(); - } - - private void ToggleLoadouts(BaseButton.ButtonEventArgs _) - { - //TODO: Optimization - // _controller.ShowLoadouts = ShowLoadouts.Pressed; - // _controller.UpdateCharacterUI(); - } - private void UpdateRoleRequirements() { JobList.DisposeAllChildren(); @@ -959,7 +947,7 @@ private void UpdateRoleRequirements() Profile = Profile?.WithJobPriority(job.ID, (JobPriority) priority); ReloadPreview(); SetDirty(); - UpdateCharacterRequired(); + SetProfile(Profile, CharacterSlot); }; _jobPriorities.Add((job.ID, selector)); @@ -1610,7 +1598,7 @@ private async void ExportProfile() } catch (Exception exc) { - Logger.Error($"Error when exporting profile\n{exc.StackTrace}"); + Logger.Error($"Error when exporting profile: {exc.Message}\n{exc.StackTrace}"); } finally { @@ -1882,7 +1870,7 @@ void AddSelector(TraitPreferenceSelector selector) Profile = Profile?.WithTraitPreference(selector.Trait.ID, preference); IsDirty = true; UpdateTraitPreferences(); - UpdateCharacterRequired(); + SetProfile(Profile, CharacterSlot); }; } @@ -1969,11 +1957,18 @@ private void UpdateLoadoutPreferences() foreach (var preferenceSelector in _loadoutPreferences) { var loadoutId = preferenceSelector.Loadout.ID; - var preference = Profile?.LoadoutPreferences.Contains(loadoutId) ?? false; + var loadoutPreference = Profile?.LoadoutPreferences.FirstOrDefault(l => l.LoadoutName == loadoutId) ?? preferenceSelector.Preference; + var preference = new LoadoutPreference( + loadoutPreference.LoadoutName, + loadoutPreference.CustomName, + loadoutPreference.CustomDescription, + loadoutPreference.CustomColorTint, + loadoutPreference.CustomHeirloom) + { Selected = loadoutPreference.Selected }; preferenceSelector.Preference = preference; - if (preference) + if (preference.Selected) { points -= preferenceSelector.Loadout.Cost; LoadoutPointsBar.Value = points; @@ -1985,14 +1980,12 @@ private void UpdateLoadoutPreferences() LoadoutsRemoveUnusableButton.Text = Loc.GetString("humanoid-profile-editor-loadouts-remove-unusable-button", ("count", _loadouts .Where(l => _loadoutPreferences - .Where(lps => lps.Preference).Select(lps => lps.Loadout).Contains(l.Key)) + .Where(lps => lps.Preference.Selected).Select(lps => lps.Loadout).Contains(l.Key)) .Count(l => !l.Value - || !_loadoutPreferences.Find(lps => lps.Loadout == l.Key)!.Wearable))); + || !_loadoutPreferences.First(lps => lps.Loadout == l.Key).Wearable))); AdminUIHelpers.RemoveConfirm(LoadoutsRemoveUnusableButton, _confirmationData); IsDirty = true; - //TODO: Optimization - // _controller.UpdateClothes = true; ReloadProfilePreview(); } @@ -2039,10 +2032,11 @@ out _ ); _loadouts.Add(loadout, usable); - if (_loadoutPreferences.FindIndex(lps => lps.Loadout.ID == loadout.ID) is not (not -1 and var i)) + var list = _loadoutPreferences.ToList(); + if (list.FindIndex(lps => lps.Loadout.ID == loadout.ID) is not (not -1 and var i)) continue; - var selector = _loadoutPreferences[i]; + var selector = list[i]; UpdateSelector(selector, usable); } @@ -2108,6 +2102,8 @@ out _ if (_loadoutPreferences.Select(lps => lps.Loadout.ID).Contains(loadout.ID)) { var first = _loadoutPreferences.First(lps => lps.Loadout.ID == loadout.ID); + var prof = Profile?.LoadoutPreferences.FirstOrDefault(lp => lp.LoadoutName == loadout.ID); + first.Preference = new(loadout.ID, prof?.CustomName, prof?.CustomDescription, prof?.CustomColorTint, prof?.CustomHeirloom); UpdateSelector(first, usable); continue; } @@ -2115,7 +2111,8 @@ out _ var selector = new LoadoutPreferenceSelector( loadout, highJob ?? new JobPrototype(), Profile ?? HumanoidCharacterProfile.DefaultWithSpecies(), ref _dummyLoadouts, - _entManager, _prototypeManager, _cfgManager, _characterRequirementsSystem, _requirements); + _entManager, _prototypeManager, _cfgManager, _characterRequirementsSystem, _requirements) + { Preference = new(loadout.ID) }; UpdateSelector(selector, usable); AddSelector(selector); @@ -2226,13 +2223,21 @@ void AddSelector(LoadoutPreferenceSelector selector) selector.PreferenceChanged += preference => { // Make sure they have enough loadout points - preference = preference ? CheckPoints(-selector.Loadout.Cost, preference) : CheckPoints(selector.Loadout.Cost, preference); + var selected = preference.Selected + ? CheckPoints(-selector.Loadout.Cost, preference.Selected) + : CheckPoints(selector.Loadout.Cost, preference.Selected); // Update Preferences - Profile = Profile?.WithLoadoutPreference(selector.Loadout.ID, preference); + Profile = Profile?.WithLoadoutPreference( + selector.Loadout.ID, + selected, + preference.CustomName, + preference.CustomDescription, + preference.CustomColorTint, + preference.CustomHeirloom); IsDirty = true; UpdateLoadoutPreferences(); - UpdateCharacterRequired(); + SetProfile(Profile, CharacterSlot); }; } @@ -2320,7 +2325,7 @@ private void TryRemoveUnusableLoadouts() // Remove unusable and unwearable loadouts foreach (var (loadout, _) in _loadouts.Where(l => - !l.Value || !_loadoutPreferences.Find(lps => lps.Loadout.ID == l.Key.ID)!.Wearable).ToList()) + !l.Value || !_loadoutPreferences.First(lps => lps.Loadout.ID == l.Key.ID).Wearable).ToList()) Profile = Profile?.WithLoadoutPreference(loadout.ID, false); UpdateCharacterRequired(); } diff --git a/Content.Client/Lobby/UI/LoadoutPreferenceSelector.xaml b/Content.Client/Lobby/UI/LoadoutPreferenceSelector.xaml index a6fbf162bc1871..e04fdc1c69bb15 100644 --- a/Content.Client/Lobby/UI/LoadoutPreferenceSelector.xaml +++ b/Content.Client/Lobby/UI/LoadoutPreferenceSelector.xaml @@ -1,10 +1,77 @@ - - + + + + +