2020-01-19 09:34:33 +01:00
using System.Linq ;
2021-10-21 05:52:26 -05:00
using System.Text.RegularExpressions ;
using Content.Shared.CCVar ;
2020-10-14 22:45:53 +02:00
using Content.Shared.GameTicking ;
Humanoid appearance refactor (#10882)
* initial commit
- species prototype modifications
- markings points as its own file
- shared humanoid component
* adds a tool to convert sprite accessories to markings (in go)
* removes a fmt call
* converts sprite accessory to markings
* adds hair and facial hair to marking categories
* multiple changes
- humanoid visualizer system
- markings modifications for visualizer
- modifications to shared humanoid component
- lays out a base for humanoid system
* hidden layers, ports some properties from appearance component, shrinks DefaultMarkings a little
* squishes the initialize event calls into one function
adds stuff to set species/skin color externally from a server message - currently laid out as if it a dirty call to a networked component, may be subject to change (server-side has not been implemented yet)
* makes the sprite pipeline more obvious
* apply all markings, hidden layer set replacement
* ensures that markings are cleared when the new set is applied
* starts refactoring markingsset (unfinished)
* more additions to the markingset api
* adds constructor logic to markingset
* adds a method to filter out markings in a set based on a given species
* fixes enumerators in markingset
* adds validator into MarkingSet, fixes ForwardMarkingEnumerator
* modifications to the humanoid visual system
* ensuredefault in markingset
* oop
* fixes up data keys, populates OnAppearanceChange in visualizer
* changes to humanoid component, markings
marking equality is now more strict, humanoidcomponent is now implemented for client as a child of sharedhumanoidcomponent
* markings are now applied the visualizer by diffing them
* base sprites are now applied to humanoids from humanoidvisualizer
* passes along base sprite settings to the marking application so that markings know to follow skin color/alpha or not (see: slimes)
* custom base layers on humanoids
* merges all data keys into one data class for humanoid visualizers
* setappearance in sharedhumanoidsystem, removes custombaselayercolors
* humanoidcomponent, system (empty) in server
* adds some basic public API functions to HumanoidSystem
* add marking, remove marking
* changes appearance MarkingsSet to a List<Marking>, adds listener for PlayerSpawnCompleteEvent in HumanoidSystem
* ensuredefaultmarkings, oninit for humanoids
* markingmanager API changes
* removes MarkingsSet
* LoadProfile, adjusts randomization in humanoid appearance to account for species
* base layer settings in humanoidsystem, eye color from profile
* rearranges files to centralize under Humanoid namespace
* more reorganization, deletes some stuff
gotta break stuff to make other things work, right?
goodbye SpriteAccessory...
* fixes a good chunk of server-side issues
still does not compile, yet
* singlemarkingpicker xaml layout
* singlemarkingpicker logic
* magic mirror window (varying pieces of it, mostly client-oriented)
* removes some imports, gives MagicMirror a BUI class (not filled in yet)
* populates magic mirror BUI functionality / window callbacks
* fixes up some errors in humanoidprofileeditor
* changes to SingleMarkingPicker
SingleMarkingPicker now accepts a List<Marking>, species, and total possible markings available in that marking category
* fixes up hair pickers on humanoid profile editor
* fixes the errors in markingpicker
* markingsystem is now gone
* fixes a bunch of build errors
* so that's why i did it like that
* namespace issues, adds robustxamlloader to singlemarkingpicker
* another robustxamlloader
* human, lizard sprites/points
* prototype fixes, deletion of old spriteaccessory
* component registration, fixes dwarf skin toning
no, 'ReptilianToned' does not exist
* removes component registration from abstract humanoid component
* visualizer data now cloneable
* serialize for visualizer key
* zero-count edge case
* missing semi-colon moment
* setspecies in humanoidsystem
* ensures that default markings, if empty, will cause ensuredefault to skip over that given category
* tryadd instead of add
* whoops
* diff and apply should properly apply markings now
* always ensure default, fixes double load for player spawning
* apply skin color now sets the skin color property in humanoidcomponent
* removes sprite from a few species prototypes
* sprite changes for specific base layers based on humanoid sex
* layer ordering fix, and a missing base layer should now disallow markings on that layer
* anymarking base layer, adds the right leg/foot for humans
* loading a profile will now clear all markings on that humanoid
* adds missing layers for humans
* separates species.yml into respective species prototype files
* ensures that if layer visibility was changed, all markings have to be reapplied
* server-side enforcement of hiding hair (and other head-related markings) when equipping things that hide hair
* slime fix, clothingsystem now dictates layer visibility server side
* sussy
* layer settings should now ensure a marking should match the skin tone
* whoops
* skincolor static class and functions in UI
* skin color validation in humanoidcharacterappearance
* markingpicker now shows only the markings for the selected category in used
* getter for slot in singlemarkingpicker now ensures slot is 0 if markings exists
* FilterSpecies no longer attempts to do removal while iterating
* expands for SingleMarkingPicker
* humanoid base dummy has blank layers now (and snout/tail/headside/headtop)
* fixes an issue with visualizer system if the marking count was different but the markings themselves were (somewhat) the same
* whoops
* adds edge case handlers for count differences in humanoid markings
* preview now loads profile instead of directly setting appearance
* moves marking set loading to update controls
* clones a marking set in markingpicker by using the deep clone constructor
* whoops (deep cloning a marking now copies the marking id)
* adds replace function for markingset
* points should now update after the markings are remove/added
* merging base layer sprites into a humanoid should now clear them before merging
* sets dirty range start to count only if the dirty range start was never set above 0
* fixes up some issues with singlemarkingpicker
* color selector sliders in single marking picker should now expand
* hair from hair pickers should now apply in profile loading (client-side)
* category in singlemarkingpicker now sets the private category variable
* slot selector should now populate
* single marking picker buttons now have text, also shows the category name over all user-clickable elements
* removes a comment
* removing hair slots now sets it to bald, defaults to zero used slots if current hair is bald on hair/facial hair
* random skin color, eye color
* populate colors now checks if the marking count is greater than zero in singlemarkingpicker
* hair/facial hair pickers now just get the first possible hair from the respective species list
* different approach to random skin color
* oh, that's why it wasn't working
* randomize everything now just updates every single control
* selecting a new marking in SingleMarkingPicker should attempt to copy over old colors, populate list now uses cache,
* markingmanager now uses OnlyWhitelisted to populate by category and species
* filterspecies now uses onlyWhitelist to filter markings based on whitelist or not
* oops
* ui fix for singlemarkingpicker, ensures that cache is not null if it is null when populatelist is called
* order of operations for the horizontal expand for add/remove
* hair pickers should now update when you add/remove the hair slot
* fixes variable naming error in character appearance
* loc string fix in singlemarkingpicker
* lizards, vox now have onlyWhitelist, vox restriction for hair/facialhairs
* having zero possible hairs should no longer cause an exception in randomization
* setting species should now update hair pickers
* ignore categories for marking picker
* and a clear as well for the category button
* places that functionality in its own function instead
* adds eye base sprite, vox now also have their own custom eye sprites
* loading a profile client-side should do FilterSpecies for markings now
* client-side load profile does filter species after adding in the hairs now
* magic mirror
* callbacks now call the callback instead of adding it on construct
* whoops
* in removemarking too
* adds missing synchronize calls
* comments out an updateinterface call in magic mirror
* magic mirror window title, minimum sizing
* fixes minsize, adds warning for players who try to set their hair for species that have no hair
* removes spaces in xaml
* namespace changes/organization
* whoopsie (merge conflicts)
* re-enables identity from humanoid component
* damagevisuals now uses the enum given to it instead of the layerstate given on that layer tied to the enum
* removes commas from json
* changes to visuals system so the change is consistent
* chest
* reptilian
* visualizer system now handles body sprite setting/coloration, similar to how characterappearance did it
not a big fan of this
* adds a check in applybasesprites
* adding/removing parts should now make them invisible on a humanoid
* body part removal/adding now enumerates over sublayers instead
* synchro now runs in bodycomponent startup
* parts instead of slots
* humanoidcompnent check
* switches from rsi to actualrsi
* removes all the body stuff (too slow)
* cleans up resolves from humanoid visualizer system
* merging sprites now checks if the base sprites have been modified or not (through things like species changes, or custom base sprite changes)
* not forgetting that one again
* merging now returns an actual dirty value
* replaces the sequenceequal with a more accurate solution
* permanent layers, layer visibility on add/remove part in body
* should send all hidden layers over now
* isdirty in visualizer system for base layers
* isdirty checks count as well
* ok, IsDirty should now set the base layers if the merged sprites are different
* equals override in HumanoidSpritePrototypes.cs
temporary until record prototypes :heck:
* makes fields readonly, equates IDs instead
* adds forced markings through marking picker
* forced in humanoidsystem api, ignorespecies in markingpicker
* marking bui
* makes that serializable as well
* ignore species/forced toggles now work
* adds icon to modifier verb, interface and keys to humanoid bases
* needs the actual enum value to open, no?
* makes the key the actual key
* actions now propagate upwards
* ignore species when set now repopulates markingpicker
* modifiable base layers in the markings window
* oops!
* layout changes
* info box should now appear
* adds ignorespecies for marking picker, collapsible for base layer section of appearance modification window
* collapsible layout moment
* if base layers have changed, all markings are now dirty (and if a base layer is missing, the marking is still 'applied' but it's now just invisible
* small change to marking visibility
* small changes to modifier UI
* markings now match skin on zombification
* zombie stuff
* makes the line edit in marking modifier window more obvious
* disables vox on round start
* horizontal expand on the single label in base layer modifiers
* humanoid profiles in prototypes
* randomhumanoidappearance won't work if the humanoid has a profile already stored
* removes unused code
* documentation in humanoidsystem server-side
* documentation in shared/client
* whoops
* converts accessory into marking in locale files (also adds marking loc string into single marking picker)
* be gone, shared humanoid appearance system from the last upstream merge
* species ignore on randomization (defaults to no ignored species)
* more upstream merge parts that bypassed any errors before merge
* addresses review (also just adds typeserializers in some places)
* submodule moment
* upstream merge issues
2022-09-22 15:19:00 -07:00
using Content.Shared.Humanoid ;
using Content.Shared.Humanoid.Prototypes ;
2024-04-16 22:57:43 +10:00
using Content.Shared.Preferences.Loadouts ;
2020-09-29 14:26:00 +02:00
using Content.Shared.Roles ;
2022-09-10 17:40:06 +02:00
using Content.Shared.Traits ;
2024-04-16 22:57:43 +10:00
using Robust.Shared.Collections ;
2021-10-21 05:52:26 -05:00
using Robust.Shared.Configuration ;
2021-02-22 00:07:46 +00:00
using Robust.Shared.Enums ;
2024-04-16 22:57:43 +10:00
using Robust.Shared.Player ;
2020-09-29 14:26:00 +02:00
using Robust.Shared.Prototypes ;
2020-10-11 13:15:09 +02:00
using Robust.Shared.Random ;
2019-12-22 13:47:34 +01:00
using Robust.Shared.Serialization ;
2022-05-14 08:58:45 +10:00
using Robust.Shared.Utility ;
2019-12-22 13:47:34 +01:00
namespace Content.Shared.Preferences
{
2020-12-24 13:42:40 +00:00
/// <summary>
/// Character profile. Looks immutable, but uses non-immutable semantics internally for serialization/code sanity purposes.
/// </summary>
Humanoid appearance refactor (#10882)
* initial commit
- species prototype modifications
- markings points as its own file
- shared humanoid component
* adds a tool to convert sprite accessories to markings (in go)
* removes a fmt call
* converts sprite accessory to markings
* adds hair and facial hair to marking categories
* multiple changes
- humanoid visualizer system
- markings modifications for visualizer
- modifications to shared humanoid component
- lays out a base for humanoid system
* hidden layers, ports some properties from appearance component, shrinks DefaultMarkings a little
* squishes the initialize event calls into one function
adds stuff to set species/skin color externally from a server message - currently laid out as if it a dirty call to a networked component, may be subject to change (server-side has not been implemented yet)
* makes the sprite pipeline more obvious
* apply all markings, hidden layer set replacement
* ensures that markings are cleared when the new set is applied
* starts refactoring markingsset (unfinished)
* more additions to the markingset api
* adds constructor logic to markingset
* adds a method to filter out markings in a set based on a given species
* fixes enumerators in markingset
* adds validator into MarkingSet, fixes ForwardMarkingEnumerator
* modifications to the humanoid visual system
* ensuredefault in markingset
* oop
* fixes up data keys, populates OnAppearanceChange in visualizer
* changes to humanoid component, markings
marking equality is now more strict, humanoidcomponent is now implemented for client as a child of sharedhumanoidcomponent
* markings are now applied the visualizer by diffing them
* base sprites are now applied to humanoids from humanoidvisualizer
* passes along base sprite settings to the marking application so that markings know to follow skin color/alpha or not (see: slimes)
* custom base layers on humanoids
* merges all data keys into one data class for humanoid visualizers
* setappearance in sharedhumanoidsystem, removes custombaselayercolors
* humanoidcomponent, system (empty) in server
* adds some basic public API functions to HumanoidSystem
* add marking, remove marking
* changes appearance MarkingsSet to a List<Marking>, adds listener for PlayerSpawnCompleteEvent in HumanoidSystem
* ensuredefaultmarkings, oninit for humanoids
* markingmanager API changes
* removes MarkingsSet
* LoadProfile, adjusts randomization in humanoid appearance to account for species
* base layer settings in humanoidsystem, eye color from profile
* rearranges files to centralize under Humanoid namespace
* more reorganization, deletes some stuff
gotta break stuff to make other things work, right?
goodbye SpriteAccessory...
* fixes a good chunk of server-side issues
still does not compile, yet
* singlemarkingpicker xaml layout
* singlemarkingpicker logic
* magic mirror window (varying pieces of it, mostly client-oriented)
* removes some imports, gives MagicMirror a BUI class (not filled in yet)
* populates magic mirror BUI functionality / window callbacks
* fixes up some errors in humanoidprofileeditor
* changes to SingleMarkingPicker
SingleMarkingPicker now accepts a List<Marking>, species, and total possible markings available in that marking category
* fixes up hair pickers on humanoid profile editor
* fixes the errors in markingpicker
* markingsystem is now gone
* fixes a bunch of build errors
* so that's why i did it like that
* namespace issues, adds robustxamlloader to singlemarkingpicker
* another robustxamlloader
* human, lizard sprites/points
* prototype fixes, deletion of old spriteaccessory
* component registration, fixes dwarf skin toning
no, 'ReptilianToned' does not exist
* removes component registration from abstract humanoid component
* visualizer data now cloneable
* serialize for visualizer key
* zero-count edge case
* missing semi-colon moment
* setspecies in humanoidsystem
* ensures that default markings, if empty, will cause ensuredefault to skip over that given category
* tryadd instead of add
* whoops
* diff and apply should properly apply markings now
* always ensure default, fixes double load for player spawning
* apply skin color now sets the skin color property in humanoidcomponent
* removes sprite from a few species prototypes
* sprite changes for specific base layers based on humanoid sex
* layer ordering fix, and a missing base layer should now disallow markings on that layer
* anymarking base layer, adds the right leg/foot for humans
* loading a profile will now clear all markings on that humanoid
* adds missing layers for humans
* separates species.yml into respective species prototype files
* ensures that if layer visibility was changed, all markings have to be reapplied
* server-side enforcement of hiding hair (and other head-related markings) when equipping things that hide hair
* slime fix, clothingsystem now dictates layer visibility server side
* sussy
* layer settings should now ensure a marking should match the skin tone
* whoops
* skincolor static class and functions in UI
* skin color validation in humanoidcharacterappearance
* markingpicker now shows only the markings for the selected category in used
* getter for slot in singlemarkingpicker now ensures slot is 0 if markings exists
* FilterSpecies no longer attempts to do removal while iterating
* expands for SingleMarkingPicker
* humanoid base dummy has blank layers now (and snout/tail/headside/headtop)
* fixes an issue with visualizer system if the marking count was different but the markings themselves were (somewhat) the same
* whoops
* adds edge case handlers for count differences in humanoid markings
* preview now loads profile instead of directly setting appearance
* moves marking set loading to update controls
* clones a marking set in markingpicker by using the deep clone constructor
* whoops (deep cloning a marking now copies the marking id)
* adds replace function for markingset
* points should now update after the markings are remove/added
* merging base layer sprites into a humanoid should now clear them before merging
* sets dirty range start to count only if the dirty range start was never set above 0
* fixes up some issues with singlemarkingpicker
* color selector sliders in single marking picker should now expand
* hair from hair pickers should now apply in profile loading (client-side)
* category in singlemarkingpicker now sets the private category variable
* slot selector should now populate
* single marking picker buttons now have text, also shows the category name over all user-clickable elements
* removes a comment
* removing hair slots now sets it to bald, defaults to zero used slots if current hair is bald on hair/facial hair
* random skin color, eye color
* populate colors now checks if the marking count is greater than zero in singlemarkingpicker
* hair/facial hair pickers now just get the first possible hair from the respective species list
* different approach to random skin color
* oh, that's why it wasn't working
* randomize everything now just updates every single control
* selecting a new marking in SingleMarkingPicker should attempt to copy over old colors, populate list now uses cache,
* markingmanager now uses OnlyWhitelisted to populate by category and species
* filterspecies now uses onlyWhitelist to filter markings based on whitelist or not
* oops
* ui fix for singlemarkingpicker, ensures that cache is not null if it is null when populatelist is called
* order of operations for the horizontal expand for add/remove
* hair pickers should now update when you add/remove the hair slot
* fixes variable naming error in character appearance
* loc string fix in singlemarkingpicker
* lizards, vox now have onlyWhitelist, vox restriction for hair/facialhairs
* having zero possible hairs should no longer cause an exception in randomization
* setting species should now update hair pickers
* ignore categories for marking picker
* and a clear as well for the category button
* places that functionality in its own function instead
* adds eye base sprite, vox now also have their own custom eye sprites
* loading a profile client-side should do FilterSpecies for markings now
* client-side load profile does filter species after adding in the hairs now
* magic mirror
* callbacks now call the callback instead of adding it on construct
* whoops
* in removemarking too
* adds missing synchronize calls
* comments out an updateinterface call in magic mirror
* magic mirror window title, minimum sizing
* fixes minsize, adds warning for players who try to set their hair for species that have no hair
* removes spaces in xaml
* namespace changes/organization
* whoopsie (merge conflicts)
* re-enables identity from humanoid component
* damagevisuals now uses the enum given to it instead of the layerstate given on that layer tied to the enum
* removes commas from json
* changes to visuals system so the change is consistent
* chest
* reptilian
* visualizer system now handles body sprite setting/coloration, similar to how characterappearance did it
not a big fan of this
* adds a check in applybasesprites
* adding/removing parts should now make them invisible on a humanoid
* body part removal/adding now enumerates over sublayers instead
* synchro now runs in bodycomponent startup
* parts instead of slots
* humanoidcompnent check
* switches from rsi to actualrsi
* removes all the body stuff (too slow)
* cleans up resolves from humanoid visualizer system
* merging sprites now checks if the base sprites have been modified or not (through things like species changes, or custom base sprite changes)
* not forgetting that one again
* merging now returns an actual dirty value
* replaces the sequenceequal with a more accurate solution
* permanent layers, layer visibility on add/remove part in body
* should send all hidden layers over now
* isdirty in visualizer system for base layers
* isdirty checks count as well
* ok, IsDirty should now set the base layers if the merged sprites are different
* equals override in HumanoidSpritePrototypes.cs
temporary until record prototypes :heck:
* makes fields readonly, equates IDs instead
* adds forced markings through marking picker
* forced in humanoidsystem api, ignorespecies in markingpicker
* marking bui
* makes that serializable as well
* ignore species/forced toggles now work
* adds icon to modifier verb, interface and keys to humanoid bases
* needs the actual enum value to open, no?
* makes the key the actual key
* actions now propagate upwards
* ignore species when set now repopulates markingpicker
* modifiable base layers in the markings window
* oops!
* layout changes
* info box should now appear
* adds ignorespecies for marking picker, collapsible for base layer section of appearance modification window
* collapsible layout moment
* if base layers have changed, all markings are now dirty (and if a base layer is missing, the marking is still 'applied' but it's now just invisible
* small change to marking visibility
* small changes to modifier UI
* markings now match skin on zombification
* zombie stuff
* makes the line edit in marking modifier window more obvious
* disables vox on round start
* horizontal expand on the single label in base layer modifiers
* humanoid profiles in prototypes
* randomhumanoidappearance won't work if the humanoid has a profile already stored
* removes unused code
* documentation in humanoidsystem server-side
* documentation in shared/client
* whoops
* converts accessory into marking in locale files (also adds marking loc string into single marking picker)
* be gone, shared humanoid appearance system from the last upstream merge
* species ignore on randomization (defaults to no ignored species)
* more upstream merge parts that bypassed any errors before merge
* addresses review (also just adds typeserializers in some places)
* submodule moment
* upstream merge issues
2022-09-22 15:19:00 -07:00
[DataDefinition]
2019-12-22 13:47:34 +01:00
[Serializable, NetSerializable]
2023-08-22 18:14:33 -07:00
public sealed partial class HumanoidCharacterProfile : ICharacterProfile
2019-12-22 13:47:34 +01:00
{
2024-06-13 12:35:00 +03:00
private static readonly Regex RestrictedNameRegex = new ( "[^А -Я,а -я,A-Z,a-z,0-9, ,\\-,']" ) ; //CP14 Cyrillic add
2024-05-06 00:57:32 +02:00
private static readonly Regex ICNameCaseRegex = new ( @"^(?<word>\w)|\b(?<word>\w)(?=\w*$)" ) ;
2021-03-28 08:26:32 +02:00
public const int MaxNameLength = 32 ;
2022-05-14 08:58:45 +10:00
public const int MaxDescLength = 512 ;
2021-03-28 08:26:32 +02:00
2024-05-12 09:18:21 +10:00
/// <summary>
/// Job preferences for initial spawn.
/// </summary>
[DataField]
2024-06-06 02:19:24 +12:00
private Dictionary < ProtoId < JobPrototype > , JobPriority > _jobPriorities = new ( )
2024-05-12 09:18:21 +10:00
{
{
SharedGameTicker . FallbackOverflowJob , JobPriority . High
}
} ;
/// <summary>
/// Antags we have opted in to.
/// </summary>
[DataField]
2024-06-06 02:19:24 +12:00
private HashSet < ProtoId < AntagPrototype > > _antagPreferences = new ( ) ;
2024-05-12 09:18:21 +10:00
/// <summary>
/// Enabled traits.
/// </summary>
[DataField]
2024-06-06 02:19:24 +12:00
private HashSet < ProtoId < TraitPrototype > > _traitPreferences = new ( ) ;
2020-01-19 09:34:33 +01:00
2024-05-12 09:18:21 +10:00
/// <summary>
/// <see cref="_loadouts"/>
/// </summary>
2024-04-16 22:57:43 +10:00
public IReadOnlyDictionary < string , RoleLoadout > Loadouts = > _loadouts ;
2024-05-12 09:18:21 +10:00
[DataField]
private Dictionary < string , RoleLoadout > _loadouts = new ( ) ;
[DataField]
public string Name { get ; set ; } = "John Doe" ;
/// <summary>
/// Detailed text that can appear for the character if <see cref="CCVars.FlavorText"/> is enabled.
/// </summary>
[DataField]
public string FlavorText { get ; set ; } = string . Empty ;
/// <summary>
/// Associated <see cref="SpeciesPrototype"/> for this profile.
/// </summary>
[DataField]
2024-06-06 02:19:24 +12:00
public ProtoId < SpeciesPrototype > Species { get ; set ; } = SharedHumanoidAppearanceSystem . DefaultSpecies ;
2024-05-12 09:18:21 +10:00
[DataField]
public int Age { get ; set ; } = 18 ;
[DataField]
public Sex Sex { get ; private set ; } = Sex . Male ;
[DataField]
public Gender Gender { get ; private set ; } = Gender . Male ;
/// <summary>
/// <see cref="Appearance"/>
/// </summary>
public ICharacterAppearance CharacterAppearance = > Appearance ;
2024-04-16 22:57:43 +10:00
2024-05-12 09:18:21 +10:00
/// <summary>
/// Stores markings, eye colors, etc for the profile.
/// </summary>
[DataField]
public HumanoidCharacterAppearance Appearance { get ; set ; } = new ( ) ;
/// <summary>
/// When spawning into a round what's the preferred spot to spawn.
/// </summary>
[DataField]
public SpawnPriorityPreference SpawnPriority { get ; private set ; } = SpawnPriorityPreference . None ;
/// <summary>
/// <see cref="_jobPriorities"/>
/// </summary>
2024-06-06 02:19:24 +12:00
public IReadOnlyDictionary < ProtoId < JobPrototype > , JobPriority > JobPriorities = > _jobPriorities ;
2024-05-12 09:18:21 +10:00
/// <summary>
/// <see cref="_antagPreferences"/>
/// </summary>
2024-06-06 02:19:24 +12:00
public IReadOnlySet < ProtoId < AntagPrototype > > AntagPreferences = > _antagPreferences ;
2024-05-12 09:18:21 +10:00
/// <summary>
/// <see cref="_traitPreferences"/>
/// </summary>
2024-06-06 02:19:24 +12:00
public IReadOnlySet < ProtoId < TraitPrototype > > TraitPreferences = > _traitPreferences ;
2024-05-12 09:18:21 +10:00
/// <summary>
/// If we're unable to get one of our preferred jobs do we spawn as a fallback job or do we stay in lobby.
/// </summary>
[DataField]
public PreferenceUnavailableMode PreferenceUnavailable { get ; private set ; } =
PreferenceUnavailableMode . SpawnAsOverflow ;
public HumanoidCharacterProfile (
2020-01-19 18:33:22 +01:00
string name ,
2022-05-14 08:58:45 +10:00
string flavortext ,
2022-01-08 19:53:14 -06:00
string species ,
2020-01-18 01:54:13 +01:00
int age ,
Sex sex ,
2020-12-24 13:42:40 +00:00
Gender gender ,
2020-01-19 09:34:33 +01:00
HumanoidCharacterAppearance appearance ,
2024-02-01 05:12:09 -05:00
SpawnPriorityPreference spawnPriority ,
2024-06-06 02:19:24 +12:00
Dictionary < ProtoId < JobPrototype > , JobPriority > jobPriorities ,
2020-07-06 16:24:29 -05:00
PreferenceUnavailableMode preferenceUnavailable ,
2024-06-06 02:19:24 +12:00
HashSet < ProtoId < AntagPrototype > > antagPreferences ,
HashSet < ProtoId < TraitPrototype > > traitPreferences ,
2024-04-16 22:57:43 +10:00
Dictionary < string , RoleLoadout > loadouts )
2020-01-18 01:54:13 +01:00
{
Name = name ;
2022-05-14 08:58:45 +10:00
FlavorText = flavortext ;
2022-01-08 19:53:14 -06:00
Species = species ;
2020-01-18 01:54:13 +01:00
Age = age ;
Sex = sex ;
2020-12-24 13:42:40 +00:00
Gender = gender ;
2020-01-18 01:54:13 +01:00
Appearance = appearance ;
2024-02-01 05:12:09 -05:00
SpawnPriority = spawnPriority ;
2020-01-19 09:34:33 +01:00
_jobPriorities = jobPriorities ;
2020-01-19 18:33:22 +01:00
PreferenceUnavailable = preferenceUnavailable ;
2020-07-06 16:24:29 -05:00
_antagPreferences = antagPreferences ;
2022-09-10 17:40:06 +02:00
_traitPreferences = traitPreferences ;
2024-04-16 22:57:43 +10:00
_loadouts = loadouts ;
2024-06-06 02:19:24 +12:00
var hasHighPrority = false ;
foreach ( var ( key , value ) in _jobPriorities )
{
if ( value = = JobPriority . Never )
_jobPriorities . Remove ( key ) ;
else if ( value ! = JobPriority . High )
continue ;
if ( hasHighPrority )
_jobPriorities [ key ] = JobPriority . Medium ;
hasHighPrority = true ;
}
2020-01-19 09:34:33 +01:00
}
2020-12-24 13:42:40 +00:00
/// <summary>Copy constructor</summary>
2024-05-12 09:18:21 +10:00
public HumanoidCharacterProfile ( HumanoidCharacterProfile other )
: this ( other . Name ,
other . FlavorText ,
other . Species ,
other . Age ,
other . Sex ,
other . Gender ,
other . Appearance . Clone ( ) ,
other . SpawnPriority ,
2024-06-06 02:19:24 +12:00
new Dictionary < ProtoId < JobPrototype > , JobPriority > ( other . JobPriorities ) ,
2024-05-12 09:18:21 +10:00
other . PreferenceUnavailable ,
2024-06-06 02:19:24 +12:00
new HashSet < ProtoId < AntagPrototype > > ( other . AntagPreferences ) ,
new HashSet < ProtoId < TraitPrototype > > ( other . TraitPreferences ) ,
2024-05-12 09:18:21 +10:00
new Dictionary < string , RoleLoadout > ( other . Loadouts ) )
2020-01-19 09:34:33 +01:00
{
2020-01-18 01:54:13 +01:00
}
2022-09-26 12:46:57 -07:00
/// <summary>
/// Get the default humanoid character profile, using internal constant values.
2023-01-24 13:38:19 +13:00
/// Defaults to <see cref="SharedHumanoidAppearanceSystem.DefaultSpecies"/> for the species.
2022-09-26 12:46:57 -07:00
/// </summary>
/// <returns></returns>
2024-05-12 09:18:21 +10:00
public HumanoidCharacterProfile ( )
2019-12-22 13:47:34 +01:00
{
2020-10-11 13:15:09 +02:00
}
2022-09-26 12:46:57 -07:00
/// <summary>
/// Return a default character profile, based on species.
/// </summary>
2023-01-24 13:38:19 +13:00
/// <param name="species">The species to use in this default profile. The default species is <see cref="SharedHumanoidAppearanceSystem.DefaultSpecies"/>.</param>
2022-09-26 12:46:57 -07:00
/// <returns>Humanoid character profile with default settings.</returns>
2023-01-24 13:38:19 +13:00
public static HumanoidCharacterProfile DefaultWithSpecies ( string species = SharedHumanoidAppearanceSystem . DefaultSpecies )
2022-09-26 12:46:57 -07:00
{
2024-05-12 09:18:21 +10:00
return new ( )
{
Species = species ,
} ;
2022-09-26 12:46:57 -07:00
}
// TODO: This should eventually not be a visual change only.
Humanoid appearance refactor (#10882)
* initial commit
- species prototype modifications
- markings points as its own file
- shared humanoid component
* adds a tool to convert sprite accessories to markings (in go)
* removes a fmt call
* converts sprite accessory to markings
* adds hair and facial hair to marking categories
* multiple changes
- humanoid visualizer system
- markings modifications for visualizer
- modifications to shared humanoid component
- lays out a base for humanoid system
* hidden layers, ports some properties from appearance component, shrinks DefaultMarkings a little
* squishes the initialize event calls into one function
adds stuff to set species/skin color externally from a server message - currently laid out as if it a dirty call to a networked component, may be subject to change (server-side has not been implemented yet)
* makes the sprite pipeline more obvious
* apply all markings, hidden layer set replacement
* ensures that markings are cleared when the new set is applied
* starts refactoring markingsset (unfinished)
* more additions to the markingset api
* adds constructor logic to markingset
* adds a method to filter out markings in a set based on a given species
* fixes enumerators in markingset
* adds validator into MarkingSet, fixes ForwardMarkingEnumerator
* modifications to the humanoid visual system
* ensuredefault in markingset
* oop
* fixes up data keys, populates OnAppearanceChange in visualizer
* changes to humanoid component, markings
marking equality is now more strict, humanoidcomponent is now implemented for client as a child of sharedhumanoidcomponent
* markings are now applied the visualizer by diffing them
* base sprites are now applied to humanoids from humanoidvisualizer
* passes along base sprite settings to the marking application so that markings know to follow skin color/alpha or not (see: slimes)
* custom base layers on humanoids
* merges all data keys into one data class for humanoid visualizers
* setappearance in sharedhumanoidsystem, removes custombaselayercolors
* humanoidcomponent, system (empty) in server
* adds some basic public API functions to HumanoidSystem
* add marking, remove marking
* changes appearance MarkingsSet to a List<Marking>, adds listener for PlayerSpawnCompleteEvent in HumanoidSystem
* ensuredefaultmarkings, oninit for humanoids
* markingmanager API changes
* removes MarkingsSet
* LoadProfile, adjusts randomization in humanoid appearance to account for species
* base layer settings in humanoidsystem, eye color from profile
* rearranges files to centralize under Humanoid namespace
* more reorganization, deletes some stuff
gotta break stuff to make other things work, right?
goodbye SpriteAccessory...
* fixes a good chunk of server-side issues
still does not compile, yet
* singlemarkingpicker xaml layout
* singlemarkingpicker logic
* magic mirror window (varying pieces of it, mostly client-oriented)
* removes some imports, gives MagicMirror a BUI class (not filled in yet)
* populates magic mirror BUI functionality / window callbacks
* fixes up some errors in humanoidprofileeditor
* changes to SingleMarkingPicker
SingleMarkingPicker now accepts a List<Marking>, species, and total possible markings available in that marking category
* fixes up hair pickers on humanoid profile editor
* fixes the errors in markingpicker
* markingsystem is now gone
* fixes a bunch of build errors
* so that's why i did it like that
* namespace issues, adds robustxamlloader to singlemarkingpicker
* another robustxamlloader
* human, lizard sprites/points
* prototype fixes, deletion of old spriteaccessory
* component registration, fixes dwarf skin toning
no, 'ReptilianToned' does not exist
* removes component registration from abstract humanoid component
* visualizer data now cloneable
* serialize for visualizer key
* zero-count edge case
* missing semi-colon moment
* setspecies in humanoidsystem
* ensures that default markings, if empty, will cause ensuredefault to skip over that given category
* tryadd instead of add
* whoops
* diff and apply should properly apply markings now
* always ensure default, fixes double load for player spawning
* apply skin color now sets the skin color property in humanoidcomponent
* removes sprite from a few species prototypes
* sprite changes for specific base layers based on humanoid sex
* layer ordering fix, and a missing base layer should now disallow markings on that layer
* anymarking base layer, adds the right leg/foot for humans
* loading a profile will now clear all markings on that humanoid
* adds missing layers for humans
* separates species.yml into respective species prototype files
* ensures that if layer visibility was changed, all markings have to be reapplied
* server-side enforcement of hiding hair (and other head-related markings) when equipping things that hide hair
* slime fix, clothingsystem now dictates layer visibility server side
* sussy
* layer settings should now ensure a marking should match the skin tone
* whoops
* skincolor static class and functions in UI
* skin color validation in humanoidcharacterappearance
* markingpicker now shows only the markings for the selected category in used
* getter for slot in singlemarkingpicker now ensures slot is 0 if markings exists
* FilterSpecies no longer attempts to do removal while iterating
* expands for SingleMarkingPicker
* humanoid base dummy has blank layers now (and snout/tail/headside/headtop)
* fixes an issue with visualizer system if the marking count was different but the markings themselves were (somewhat) the same
* whoops
* adds edge case handlers for count differences in humanoid markings
* preview now loads profile instead of directly setting appearance
* moves marking set loading to update controls
* clones a marking set in markingpicker by using the deep clone constructor
* whoops (deep cloning a marking now copies the marking id)
* adds replace function for markingset
* points should now update after the markings are remove/added
* merging base layer sprites into a humanoid should now clear them before merging
* sets dirty range start to count only if the dirty range start was never set above 0
* fixes up some issues with singlemarkingpicker
* color selector sliders in single marking picker should now expand
* hair from hair pickers should now apply in profile loading (client-side)
* category in singlemarkingpicker now sets the private category variable
* slot selector should now populate
* single marking picker buttons now have text, also shows the category name over all user-clickable elements
* removes a comment
* removing hair slots now sets it to bald, defaults to zero used slots if current hair is bald on hair/facial hair
* random skin color, eye color
* populate colors now checks if the marking count is greater than zero in singlemarkingpicker
* hair/facial hair pickers now just get the first possible hair from the respective species list
* different approach to random skin color
* oh, that's why it wasn't working
* randomize everything now just updates every single control
* selecting a new marking in SingleMarkingPicker should attempt to copy over old colors, populate list now uses cache,
* markingmanager now uses OnlyWhitelisted to populate by category and species
* filterspecies now uses onlyWhitelist to filter markings based on whitelist or not
* oops
* ui fix for singlemarkingpicker, ensures that cache is not null if it is null when populatelist is called
* order of operations for the horizontal expand for add/remove
* hair pickers should now update when you add/remove the hair slot
* fixes variable naming error in character appearance
* loc string fix in singlemarkingpicker
* lizards, vox now have onlyWhitelist, vox restriction for hair/facialhairs
* having zero possible hairs should no longer cause an exception in randomization
* setting species should now update hair pickers
* ignore categories for marking picker
* and a clear as well for the category button
* places that functionality in its own function instead
* adds eye base sprite, vox now also have their own custom eye sprites
* loading a profile client-side should do FilterSpecies for markings now
* client-side load profile does filter species after adding in the hairs now
* magic mirror
* callbacks now call the callback instead of adding it on construct
* whoops
* in removemarking too
* adds missing synchronize calls
* comments out an updateinterface call in magic mirror
* magic mirror window title, minimum sizing
* fixes minsize, adds warning for players who try to set their hair for species that have no hair
* removes spaces in xaml
* namespace changes/organization
* whoopsie (merge conflicts)
* re-enables identity from humanoid component
* damagevisuals now uses the enum given to it instead of the layerstate given on that layer tied to the enum
* removes commas from json
* changes to visuals system so the change is consistent
* chest
* reptilian
* visualizer system now handles body sprite setting/coloration, similar to how characterappearance did it
not a big fan of this
* adds a check in applybasesprites
* adding/removing parts should now make them invisible on a humanoid
* body part removal/adding now enumerates over sublayers instead
* synchro now runs in bodycomponent startup
* parts instead of slots
* humanoidcompnent check
* switches from rsi to actualrsi
* removes all the body stuff (too slow)
* cleans up resolves from humanoid visualizer system
* merging sprites now checks if the base sprites have been modified or not (through things like species changes, or custom base sprite changes)
* not forgetting that one again
* merging now returns an actual dirty value
* replaces the sequenceequal with a more accurate solution
* permanent layers, layer visibility on add/remove part in body
* should send all hidden layers over now
* isdirty in visualizer system for base layers
* isdirty checks count as well
* ok, IsDirty should now set the base layers if the merged sprites are different
* equals override in HumanoidSpritePrototypes.cs
temporary until record prototypes :heck:
* makes fields readonly, equates IDs instead
* adds forced markings through marking picker
* forced in humanoidsystem api, ignorespecies in markingpicker
* marking bui
* makes that serializable as well
* ignore species/forced toggles now work
* adds icon to modifier verb, interface and keys to humanoid bases
* needs the actual enum value to open, no?
* makes the key the actual key
* actions now propagate upwards
* ignore species when set now repopulates markingpicker
* modifiable base layers in the markings window
* oops!
* layout changes
* info box should now appear
* adds ignorespecies for marking picker, collapsible for base layer section of appearance modification window
* collapsible layout moment
* if base layers have changed, all markings are now dirty (and if a base layer is missing, the marking is still 'applied' but it's now just invisible
* small change to marking visibility
* small changes to modifier UI
* markings now match skin on zombification
* zombie stuff
* makes the line edit in marking modifier window more obvious
* disables vox on round start
* horizontal expand on the single label in base layer modifiers
* humanoid profiles in prototypes
* randomhumanoidappearance won't work if the humanoid has a profile already stored
* removes unused code
* documentation in humanoidsystem server-side
* documentation in shared/client
* whoops
* converts accessory into marking in locale files (also adds marking loc string into single marking picker)
* be gone, shared humanoid appearance system from the last upstream merge
* species ignore on randomization (defaults to no ignored species)
* more upstream merge parts that bypassed any errors before merge
* addresses review (also just adds typeserializers in some places)
* submodule moment
* upstream merge issues
2022-09-22 15:19:00 -07:00
public static HumanoidCharacterProfile Random ( HashSet < string > ? ignoredSpecies = null )
2020-10-11 13:15:09 +02:00
{
2022-05-12 20:43:15 -03:00
var prototypeManager = IoCManager . Resolve < IPrototypeManager > ( ) ;
2020-10-11 13:15:09 +02:00
var random = IoCManager . Resolve < IRobustRandom > ( ) ;
2022-01-08 19:53:14 -06:00
2022-05-12 20:43:15 -03:00
var species = random . Pick ( prototypeManager
Humanoid appearance refactor (#10882)
* initial commit
- species prototype modifications
- markings points as its own file
- shared humanoid component
* adds a tool to convert sprite accessories to markings (in go)
* removes a fmt call
* converts sprite accessory to markings
* adds hair and facial hair to marking categories
* multiple changes
- humanoid visualizer system
- markings modifications for visualizer
- modifications to shared humanoid component
- lays out a base for humanoid system
* hidden layers, ports some properties from appearance component, shrinks DefaultMarkings a little
* squishes the initialize event calls into one function
adds stuff to set species/skin color externally from a server message - currently laid out as if it a dirty call to a networked component, may be subject to change (server-side has not been implemented yet)
* makes the sprite pipeline more obvious
* apply all markings, hidden layer set replacement
* ensures that markings are cleared when the new set is applied
* starts refactoring markingsset (unfinished)
* more additions to the markingset api
* adds constructor logic to markingset
* adds a method to filter out markings in a set based on a given species
* fixes enumerators in markingset
* adds validator into MarkingSet, fixes ForwardMarkingEnumerator
* modifications to the humanoid visual system
* ensuredefault in markingset
* oop
* fixes up data keys, populates OnAppearanceChange in visualizer
* changes to humanoid component, markings
marking equality is now more strict, humanoidcomponent is now implemented for client as a child of sharedhumanoidcomponent
* markings are now applied the visualizer by diffing them
* base sprites are now applied to humanoids from humanoidvisualizer
* passes along base sprite settings to the marking application so that markings know to follow skin color/alpha or not (see: slimes)
* custom base layers on humanoids
* merges all data keys into one data class for humanoid visualizers
* setappearance in sharedhumanoidsystem, removes custombaselayercolors
* humanoidcomponent, system (empty) in server
* adds some basic public API functions to HumanoidSystem
* add marking, remove marking
* changes appearance MarkingsSet to a List<Marking>, adds listener for PlayerSpawnCompleteEvent in HumanoidSystem
* ensuredefaultmarkings, oninit for humanoids
* markingmanager API changes
* removes MarkingsSet
* LoadProfile, adjusts randomization in humanoid appearance to account for species
* base layer settings in humanoidsystem, eye color from profile
* rearranges files to centralize under Humanoid namespace
* more reorganization, deletes some stuff
gotta break stuff to make other things work, right?
goodbye SpriteAccessory...
* fixes a good chunk of server-side issues
still does not compile, yet
* singlemarkingpicker xaml layout
* singlemarkingpicker logic
* magic mirror window (varying pieces of it, mostly client-oriented)
* removes some imports, gives MagicMirror a BUI class (not filled in yet)
* populates magic mirror BUI functionality / window callbacks
* fixes up some errors in humanoidprofileeditor
* changes to SingleMarkingPicker
SingleMarkingPicker now accepts a List<Marking>, species, and total possible markings available in that marking category
* fixes up hair pickers on humanoid profile editor
* fixes the errors in markingpicker
* markingsystem is now gone
* fixes a bunch of build errors
* so that's why i did it like that
* namespace issues, adds robustxamlloader to singlemarkingpicker
* another robustxamlloader
* human, lizard sprites/points
* prototype fixes, deletion of old spriteaccessory
* component registration, fixes dwarf skin toning
no, 'ReptilianToned' does not exist
* removes component registration from abstract humanoid component
* visualizer data now cloneable
* serialize for visualizer key
* zero-count edge case
* missing semi-colon moment
* setspecies in humanoidsystem
* ensures that default markings, if empty, will cause ensuredefault to skip over that given category
* tryadd instead of add
* whoops
* diff and apply should properly apply markings now
* always ensure default, fixes double load for player spawning
* apply skin color now sets the skin color property in humanoidcomponent
* removes sprite from a few species prototypes
* sprite changes for specific base layers based on humanoid sex
* layer ordering fix, and a missing base layer should now disallow markings on that layer
* anymarking base layer, adds the right leg/foot for humans
* loading a profile will now clear all markings on that humanoid
* adds missing layers for humans
* separates species.yml into respective species prototype files
* ensures that if layer visibility was changed, all markings have to be reapplied
* server-side enforcement of hiding hair (and other head-related markings) when equipping things that hide hair
* slime fix, clothingsystem now dictates layer visibility server side
* sussy
* layer settings should now ensure a marking should match the skin tone
* whoops
* skincolor static class and functions in UI
* skin color validation in humanoidcharacterappearance
* markingpicker now shows only the markings for the selected category in used
* getter for slot in singlemarkingpicker now ensures slot is 0 if markings exists
* FilterSpecies no longer attempts to do removal while iterating
* expands for SingleMarkingPicker
* humanoid base dummy has blank layers now (and snout/tail/headside/headtop)
* fixes an issue with visualizer system if the marking count was different but the markings themselves were (somewhat) the same
* whoops
* adds edge case handlers for count differences in humanoid markings
* preview now loads profile instead of directly setting appearance
* moves marking set loading to update controls
* clones a marking set in markingpicker by using the deep clone constructor
* whoops (deep cloning a marking now copies the marking id)
* adds replace function for markingset
* points should now update after the markings are remove/added
* merging base layer sprites into a humanoid should now clear them before merging
* sets dirty range start to count only if the dirty range start was never set above 0
* fixes up some issues with singlemarkingpicker
* color selector sliders in single marking picker should now expand
* hair from hair pickers should now apply in profile loading (client-side)
* category in singlemarkingpicker now sets the private category variable
* slot selector should now populate
* single marking picker buttons now have text, also shows the category name over all user-clickable elements
* removes a comment
* removing hair slots now sets it to bald, defaults to zero used slots if current hair is bald on hair/facial hair
* random skin color, eye color
* populate colors now checks if the marking count is greater than zero in singlemarkingpicker
* hair/facial hair pickers now just get the first possible hair from the respective species list
* different approach to random skin color
* oh, that's why it wasn't working
* randomize everything now just updates every single control
* selecting a new marking in SingleMarkingPicker should attempt to copy over old colors, populate list now uses cache,
* markingmanager now uses OnlyWhitelisted to populate by category and species
* filterspecies now uses onlyWhitelist to filter markings based on whitelist or not
* oops
* ui fix for singlemarkingpicker, ensures that cache is not null if it is null when populatelist is called
* order of operations for the horizontal expand for add/remove
* hair pickers should now update when you add/remove the hair slot
* fixes variable naming error in character appearance
* loc string fix in singlemarkingpicker
* lizards, vox now have onlyWhitelist, vox restriction for hair/facialhairs
* having zero possible hairs should no longer cause an exception in randomization
* setting species should now update hair pickers
* ignore categories for marking picker
* and a clear as well for the category button
* places that functionality in its own function instead
* adds eye base sprite, vox now also have their own custom eye sprites
* loading a profile client-side should do FilterSpecies for markings now
* client-side load profile does filter species after adding in the hairs now
* magic mirror
* callbacks now call the callback instead of adding it on construct
* whoops
* in removemarking too
* adds missing synchronize calls
* comments out an updateinterface call in magic mirror
* magic mirror window title, minimum sizing
* fixes minsize, adds warning for players who try to set their hair for species that have no hair
* removes spaces in xaml
* namespace changes/organization
* whoopsie (merge conflicts)
* re-enables identity from humanoid component
* damagevisuals now uses the enum given to it instead of the layerstate given on that layer tied to the enum
* removes commas from json
* changes to visuals system so the change is consistent
* chest
* reptilian
* visualizer system now handles body sprite setting/coloration, similar to how characterappearance did it
not a big fan of this
* adds a check in applybasesprites
* adding/removing parts should now make them invisible on a humanoid
* body part removal/adding now enumerates over sublayers instead
* synchro now runs in bodycomponent startup
* parts instead of slots
* humanoidcompnent check
* switches from rsi to actualrsi
* removes all the body stuff (too slow)
* cleans up resolves from humanoid visualizer system
* merging sprites now checks if the base sprites have been modified or not (through things like species changes, or custom base sprite changes)
* not forgetting that one again
* merging now returns an actual dirty value
* replaces the sequenceequal with a more accurate solution
* permanent layers, layer visibility on add/remove part in body
* should send all hidden layers over now
* isdirty in visualizer system for base layers
* isdirty checks count as well
* ok, IsDirty should now set the base layers if the merged sprites are different
* equals override in HumanoidSpritePrototypes.cs
temporary until record prototypes :heck:
* makes fields readonly, equates IDs instead
* adds forced markings through marking picker
* forced in humanoidsystem api, ignorespecies in markingpicker
* marking bui
* makes that serializable as well
* ignore species/forced toggles now work
* adds icon to modifier verb, interface and keys to humanoid bases
* needs the actual enum value to open, no?
* makes the key the actual key
* actions now propagate upwards
* ignore species when set now repopulates markingpicker
* modifiable base layers in the markings window
* oops!
* layout changes
* info box should now appear
* adds ignorespecies for marking picker, collapsible for base layer section of appearance modification window
* collapsible layout moment
* if base layers have changed, all markings are now dirty (and if a base layer is missing, the marking is still 'applied' but it's now just invisible
* small change to marking visibility
* small changes to modifier UI
* markings now match skin on zombification
* zombie stuff
* makes the line edit in marking modifier window more obvious
* disables vox on round start
* horizontal expand on the single label in base layer modifiers
* humanoid profiles in prototypes
* randomhumanoidappearance won't work if the humanoid has a profile already stored
* removes unused code
* documentation in humanoidsystem server-side
* documentation in shared/client
* whoops
* converts accessory into marking in locale files (also adds marking loc string into single marking picker)
* be gone, shared humanoid appearance system from the last upstream merge
* species ignore on randomization (defaults to no ignored species)
* more upstream merge parts that bypassed any errors before merge
* addresses review (also just adds typeserializers in some places)
* submodule moment
* upstream merge issues
2022-09-22 15:19:00 -07:00
. EnumeratePrototypes < SpeciesPrototype > ( )
. Where ( x = > ignoredSpecies = = null ? x . RoundStart : x . RoundStart & & ! ignoredSpecies . Contains ( x . ID ) )
. ToArray ( )
) . ID ;
2022-09-26 12:46:57 -07:00
return RandomWithSpecies ( species ) ;
}
2023-01-24 13:38:19 +13:00
public static HumanoidCharacterProfile RandomWithSpecies ( string species = SharedHumanoidAppearanceSystem . DefaultSpecies )
2022-09-26 12:46:57 -07:00
{
var prototypeManager = IoCManager . Resolve < IPrototypeManager > ( ) ;
var random = IoCManager . Resolve < IRobustRandom > ( ) ;
2022-10-15 17:45:47 -04:00
var sex = Sex . Unsexed ;
2022-10-22 18:13:46 -04:00
var age = 18 ;
2022-10-15 17:45:47 -04:00
if ( prototypeManager . TryIndex < SpeciesPrototype > ( species , out var speciesPrototype ) )
{
sex = random . Pick ( speciesPrototype . Sexes ) ;
2022-10-22 18:13:46 -04:00
age = random . Next ( speciesPrototype . MinAge , speciesPrototype . OldAge ) ; // people don't look and keep making 119 year old characters with zero rp, cap it at middle aged
2022-10-15 17:45:47 -04:00
}
2024-02-19 17:38:06 -05:00
var gender = Gender . Epicene ;
switch ( sex )
{
case Sex . Male :
gender = Gender . Male ;
break ;
case Sex . Female :
gender = Gender . Female ;
break ;
}
2020-10-11 13:15:09 +02:00
2022-10-15 17:45:47 -04:00
var name = GetName ( species , gender ) ;
2020-10-11 13:15:09 +02:00
2024-05-12 09:18:21 +10:00
return new HumanoidCharacterProfile ( )
{
Name = name ,
Sex = sex ,
Age = age ,
Gender = gender ,
Species = species ,
Appearance = HumanoidCharacterAppearance . Random ( species , sex ) ,
} ;
2020-01-18 01:54:13 +01:00
}
public HumanoidCharacterProfile WithName ( string name )
{
2020-12-24 13:42:40 +00:00
return new ( this ) { Name = name } ;
2020-01-18 01:54:13 +01:00
}
2022-05-14 08:58:45 +10:00
public HumanoidCharacterProfile WithFlavorText ( string flavorText )
{
return new ( this ) { FlavorText = flavorText } ;
}
2020-01-18 01:54:13 +01:00
public HumanoidCharacterProfile WithAge ( int age )
{
2020-12-24 13:42:40 +00:00
return new ( this ) { Age = age } ;
2020-01-18 01:54:13 +01:00
}
public HumanoidCharacterProfile WithSex ( Sex sex )
{
2020-12-24 13:42:40 +00:00
return new ( this ) { Sex = sex } ;
}
public HumanoidCharacterProfile WithGender ( Gender gender )
{
return new ( this ) { Gender = gender } ;
2020-01-18 01:54:13 +01:00
}
2022-01-08 19:53:14 -06:00
public HumanoidCharacterProfile WithSpecies ( string species )
{
return new ( this ) { Species = species } ;
}
2020-01-18 01:54:13 +01:00
public HumanoidCharacterProfile WithCharacterAppearance ( HumanoidCharacterAppearance appearance )
{
2020-12-24 13:42:40 +00:00
return new ( this ) { Appearance = appearance } ;
}
2024-02-01 05:12:09 -05:00
public HumanoidCharacterProfile WithSpawnPriorityPreference ( SpawnPriorityPreference spawnPriority )
{
return new ( this ) { SpawnPriority = spawnPriority } ;
}
2024-04-16 22:57:43 +10:00
2024-06-06 02:19:24 +12:00
public HumanoidCharacterProfile WithJobPriorities ( IEnumerable < KeyValuePair < ProtoId < JobPrototype > , JobPriority > > jobPriorities )
2020-01-19 09:34:33 +01:00
{
2024-06-06 02:19:24 +12:00
var dictionary = new Dictionary < ProtoId < JobPrototype > , JobPriority > ( jobPriorities ) ;
var hasHighPrority = false ;
foreach ( var ( key , value ) in dictionary )
{
if ( value = = JobPriority . Never )
dictionary . Remove ( key ) ;
else if ( value ! = JobPriority . High )
continue ;
if ( hasHighPrority )
dictionary [ key ] = JobPriority . Medium ;
hasHighPrority = true ;
}
2024-05-12 09:18:21 +10:00
return new ( this )
{
2024-06-06 02:19:24 +12:00
_jobPriorities = dictionary
2024-05-12 09:18:21 +10:00
} ;
2020-01-19 09:34:33 +01:00
}
2024-06-06 02:19:24 +12:00
public HumanoidCharacterProfile WithJobPriority ( ProtoId < JobPrototype > jobId , JobPriority priority )
2020-01-19 09:34:33 +01:00
{
2024-06-06 02:19:24 +12:00
var dictionary = new Dictionary < ProtoId < JobPrototype > , JobPriority > ( _jobPriorities ) ;
2020-01-19 09:34:33 +01:00
if ( priority = = JobPriority . Never )
{
dictionary . Remove ( jobId ) ;
}
2024-06-06 02:19:24 +12:00
else if ( priority = = JobPriority . High )
{
// There can only ever be one high priority job.
foreach ( var ( job , value ) in dictionary )
{
if ( value = = JobPriority . High )
dictionary [ job ] = JobPriority . Medium ;
}
dictionary [ jobId ] = priority ;
}
2020-01-19 09:34:33 +01:00
else
{
dictionary [ jobId ] = priority ;
}
2024-05-12 09:18:21 +10:00
return new ( this )
{
_jobPriorities = dictionary ,
} ;
2020-01-19 18:33:22 +01:00
}
public HumanoidCharacterProfile WithPreferenceUnavailable ( PreferenceUnavailableMode mode )
{
2020-12-24 13:42:40 +00:00
return new ( this ) { PreferenceUnavailable = mode } ;
2020-07-06 16:24:29 -05:00
}
2024-06-06 02:19:24 +12:00
public HumanoidCharacterProfile WithAntagPreferences ( IEnumerable < ProtoId < AntagPrototype > > antagPreferences )
2020-07-06 16:24:29 -05:00
{
2024-05-12 09:18:21 +10:00
return new ( this )
{
2024-06-06 02:19:24 +12:00
_antagPreferences = new ( antagPreferences ) ,
2024-05-12 09:18:21 +10:00
} ;
2020-07-06 16:24:29 -05:00
}
2024-06-06 02:19:24 +12:00
public HumanoidCharacterProfile WithAntagPreference ( ProtoId < AntagPrototype > antagId , bool pref )
2020-07-06 16:24:29 -05:00
{
2024-06-06 02:19:24 +12:00
var list = new HashSet < ProtoId < AntagPrototype > > ( _antagPreferences ) ;
2024-02-19 17:38:06 -05:00
if ( pref )
2020-07-06 16:24:29 -05:00
{
2024-05-12 09:18:21 +10:00
list . Add ( antagId ) ;
2020-07-06 16:24:29 -05:00
}
else
{
2024-05-12 09:18:21 +10:00
list . Remove ( antagId ) ;
2020-07-06 16:24:29 -05:00
}
2024-04-17 12:54:54 +10:00
2024-05-12 09:18:21 +10:00
return new ( this )
{
_antagPreferences = list ,
} ;
2022-09-10 17:40:06 +02:00
}
2024-06-29 15:39:57 +10:00
public HumanoidCharacterProfile WithTraitPreference ( ProtoId < TraitPrototype > traitId , IPrototypeManager protoManager )
2022-09-10 17:40:06 +02:00
{
2024-06-29 15:39:57 +10:00
// null category is assumed to be default.
if ( ! protoManager . TryIndex ( traitId , out var traitProto ) )
return new ( this ) ;
2024-06-03 21:47:06 +03:00
2024-06-29 15:39:57 +10:00
var category = traitProto . Category ;
2024-06-03 21:47:06 +03:00
2024-06-29 15:39:57 +10:00
// Category not found so dump it.
TraitCategoryPrototype ? traitCategory = null ;
2022-09-10 17:40:06 +02:00
2024-06-29 15:39:57 +10:00
if ( category ! = null & & ! protoManager . TryIndex ( category , out traitCategory ) )
return new ( this ) ;
2024-06-03 21:47:06 +03:00
2024-06-29 15:39:57 +10:00
var list = new HashSet < ProtoId < TraitPrototype > > ( _traitPreferences ) { traitId } ;
2024-06-03 21:47:06 +03:00
2024-06-29 15:39:57 +10:00
if ( traitCategory = = null | | traitCategory . MaxTraitPoints < 0 )
{
return new ( this )
2024-06-03 21:47:06 +03:00
{
2024-06-29 15:39:57 +10:00
_traitPreferences = list ,
} ;
}
2024-06-03 21:47:06 +03:00
2024-06-29 15:39:57 +10:00
var count = 0 ;
foreach ( var trait in list )
{
// If trait not found or another category don't count its points.
if ( ! protoManager . TryIndex < TraitPrototype > ( trait , out var otherProto ) | |
otherProto . Category ! = traitCategory )
2024-06-03 21:47:06 +03:00
{
2024-06-29 15:39:57 +10:00
continue ;
2024-06-03 21:47:06 +03:00
}
2024-06-29 15:39:57 +10:00
count + = otherProto . Cost ;
2022-09-10 17:40:06 +02:00
}
2024-06-29 15:39:57 +10:00
if ( count > traitCategory . MaxTraitPoints & & traitProto . Cost ! = 0 )
2022-09-10 17:40:06 +02:00
{
2024-06-29 15:39:57 +10:00
return new ( this ) ;
2022-09-10 17:40:06 +02:00
}
2024-05-12 09:18:21 +10:00
return new ( this )
{
_traitPreferences = list ,
} ;
2019-12-22 13:47:34 +01:00
}
2024-06-29 15:39:57 +10:00
public HumanoidCharacterProfile WithoutTraitPreference ( ProtoId < TraitPrototype > traitId , IPrototypeManager protoManager )
{
var list = new HashSet < ProtoId < TraitPrototype > > ( _traitPreferences ) ;
list . Remove ( traitId ) ;
return new ( this )
{
_traitPreferences = list ,
} ;
}
2021-03-08 03:07:53 +01:00
public string Summary = >
Loc . GetString (
"humanoid-character-profile-summary" ,
( "name" , Name ) ,
( "gender" , Gender . ToString ( ) . ToLowerInvariant ( ) ) ,
( "age" , Age )
) ;
public bool MemberwiseEquals ( ICharacterProfile maybeOther )
2020-09-29 14:26:00 +02:00
{
2021-03-08 03:07:53 +01:00
if ( maybeOther is not HumanoidCharacterProfile other ) return false ;
if ( Name ! = other . Name ) return false ;
if ( Age ! = other . Age ) return false ;
if ( Sex ! = other . Sex ) return false ;
if ( Gender ! = other . Gender ) return false ;
2024-05-01 13:01:15 -04:00
if ( Species ! = other . Species ) return false ;
2021-03-08 03:07:53 +01:00
if ( PreferenceUnavailable ! = other . PreferenceUnavailable ) return false ;
2024-02-01 05:12:09 -05:00
if ( SpawnPriority ! = other . SpawnPriority ) return false ;
2021-03-08 03:07:53 +01:00
if ( ! _jobPriorities . SequenceEqual ( other . _jobPriorities ) ) return false ;
if ( ! _antagPreferences . SequenceEqual ( other . _antagPreferences ) ) return false ;
2022-09-10 17:40:06 +02:00
if ( ! _traitPreferences . SequenceEqual ( other . _traitPreferences ) ) return false ;
2024-04-16 22:57:43 +10:00
if ( ! Loadouts . SequenceEqual ( other . Loadouts ) ) return false ;
2024-05-18 19:23:44 -05:00
if ( FlavorText ! = other . FlavorText ) return false ;
2021-03-08 03:07:53 +01:00
return Appearance . MemberwiseEquals ( other . Appearance ) ;
}
2024-04-16 22:57:43 +10:00
public void EnsureValid ( ICommonSession session , IDependencyCollection collection )
2021-03-08 03:07:53 +01:00
{
2024-04-16 22:57:43 +10:00
var configManager = collection . Resolve < IConfigurationManager > ( ) ;
var prototypeManager = collection . Resolve < IPrototypeManager > ( ) ;
2024-06-09 04:48:09 +10:00
if ( ! prototypeManager . TryIndex ( Species , out var speciesPrototype ) | | speciesPrototype . RoundStart = = false )
2023-03-14 21:47:40 -07:00
{
Species = SharedHumanoidAppearanceSystem . DefaultSpecies ;
2024-06-09 04:48:09 +10:00
speciesPrototype = prototypeManager . Index ( Species ) ;
2023-03-14 21:47:40 -07:00
}
2022-10-15 17:45:47 -04:00
2021-03-08 03:07:53 +01:00
var sex = Sex switch
2020-09-29 14:26:00 +02:00
{
Sex . Male = > Sex . Male ,
Sex . Female = > Sex . Female ,
2022-10-15 17:45:47 -04:00
Sex . Unsexed = > Sex . Unsexed ,
2020-09-29 14:26:00 +02:00
_ = > Sex . Male // Invalid enum values.
} ;
2021-03-08 03:07:53 +01:00
2022-10-22 18:13:46 -04:00
// ensure the species can be that sex and their age fits the founds
2024-02-26 03:36:38 +01:00
if ( ! speciesPrototype . Sexes . Contains ( sex ) )
sex = speciesPrototype . Sexes [ 0 ] ;
var age = Math . Clamp ( Age , speciesPrototype . MinAge , speciesPrototype . MaxAge ) ;
2022-10-15 17:45:47 -04:00
2021-03-08 03:07:53 +01:00
var gender = Gender switch
2020-12-24 13:42:40 +00:00
{
Gender . Epicene = > Gender . Epicene ,
Gender . Female = > Gender . Female ,
Gender . Male = > Gender . Male ,
Gender . Neuter = > Gender . Neuter ,
_ = > Gender . Epicene // Invalid enum values.
} ;
2020-09-29 14:26:00 +02:00
string name ;
2021-03-08 03:07:53 +01:00
if ( string . IsNullOrEmpty ( Name ) )
2020-09-29 14:26:00 +02:00
{
2022-10-15 17:45:47 -04:00
name = GetName ( Species , gender ) ;
2020-09-29 14:26:00 +02:00
}
2021-03-08 03:07:53 +01:00
else if ( Name . Length > MaxNameLength )
2020-09-29 14:26:00 +02:00
{
2021-03-08 03:07:53 +01:00
name = Name [ . . MaxNameLength ] ;
2020-09-29 14:26:00 +02:00
}
else
{
2021-03-08 03:07:53 +01:00
name = Name ;
2020-09-29 14:26:00 +02:00
}
name = name . Trim ( ) ;
2022-09-14 05:50:15 -04:00
if ( configManager . GetCVar ( CCVars . RestrictedNames ) )
2021-10-21 05:52:26 -05:00
{
2024-05-06 00:57:32 +02:00
name = RestrictedNameRegex . Replace ( name , string . Empty ) ;
2021-10-21 05:52:26 -05:00
}
2022-09-14 05:50:15 -04:00
if ( configManager . GetCVar ( CCVars . ICNameCase ) )
{
// This regex replaces the first character of the first and last words of the name with their uppercase version
2024-05-06 00:57:32 +02:00
name = ICNameCaseRegex . Replace ( name , m = > m . Groups [ "word" ] . Value . ToUpper ( ) ) ;
2022-09-14 05:50:15 -04:00
}
2021-10-21 05:52:26 -05:00
if ( string . IsNullOrEmpty ( name ) )
{
2022-10-15 17:45:47 -04:00
name = GetName ( Species , gender ) ;
2021-10-21 05:52:26 -05:00
}
2022-05-14 08:58:45 +10:00
string flavortext ;
if ( FlavorText . Length > MaxDescLength )
{
2024-09-01 14:00:53 +03:00
flavortext = FormattedMessage . RemoveMarkupOrThrow ( FlavorText ) [ . . MaxDescLength ] ;
2022-05-14 08:58:45 +10:00
}
else
{
2024-09-01 14:00:53 +03:00
flavortext = FormattedMessage . RemoveMarkupOrThrow ( FlavorText ) ;
2022-05-14 08:58:45 +10:00
}
2023-09-19 23:56:10 +03:00
var appearance = HumanoidCharacterAppearance . EnsureValid ( Appearance , Species , Sex ) ;
2020-09-29 14:26:00 +02:00
2021-03-08 03:07:53 +01:00
var prefsUnavailableMode = PreferenceUnavailable switch
2020-09-29 14:26:00 +02:00
{
PreferenceUnavailableMode . StayInLobby = > PreferenceUnavailableMode . StayInLobby ,
PreferenceUnavailableMode . SpawnAsOverflow = > PreferenceUnavailableMode . SpawnAsOverflow ,
_ = > PreferenceUnavailableMode . StayInLobby // Invalid enum values.
} ;
2024-02-01 05:12:09 -05:00
var spawnPriority = SpawnPriority switch
{
2024-02-03 03:06:44 -05:00
SpawnPriorityPreference . None = > SpawnPriorityPreference . None ,
2024-02-01 05:12:09 -05:00
SpawnPriorityPreference . Arrivals = > SpawnPriorityPreference . Arrivals ,
SpawnPriorityPreference . Cryosleep = > SpawnPriorityPreference . Cryosleep ,
2024-02-03 03:06:44 -05:00
_ = > SpawnPriorityPreference . None // Invalid enum values.
2024-02-01 05:12:09 -05:00
} ;
2024-06-06 02:19:24 +12:00
var priorities = new Dictionary < ProtoId < JobPrototype > , JobPriority > ( JobPriorities
2024-02-26 03:36:38 +01:00
. Where ( p = > prototypeManager . TryIndex < JobPrototype > ( p . Key , out var job ) & & job . SetPreference & & p . Value switch
2020-09-29 14:26:00 +02:00
{
JobPriority . Never = > false , // Drop never since that's assumed default.
JobPriority . Low = > true ,
JobPriority . Medium = > true ,
JobPriority . High = > true ,
_ = > false
2020-10-06 15:13:16 +02:00
} ) ) ;
2020-09-29 14:26:00 +02:00
2024-06-06 02:19:24 +12:00
var hasHighPrio = false ;
foreach ( var ( key , value ) in priorities )
{
if ( value ! = JobPriority . High )
continue ;
if ( hasHighPrio )
priorities [ key ] = JobPriority . Medium ;
hasHighPrio = true ;
}
2021-03-08 03:07:53 +01:00
var antags = AntagPreferences
2024-06-30 23:47:22 +10:00
. Where ( id = > prototypeManager . TryIndex ( id , out var antag ) & & antag . SetPreference )
2020-09-29 14:26:00 +02:00
. ToList ( ) ;
2022-09-10 17:40:06 +02:00
var traits = TraitPreferences
2024-06-30 23:47:22 +10:00
. Where ( prototypeManager . HasIndex )
2022-09-10 17:40:06 +02:00
. ToList ( ) ;
2021-03-08 03:07:53 +01:00
Name = name ;
2022-05-14 08:58:45 +10:00
FlavorText = flavortext ;
2021-03-08 03:07:53 +01:00
Age = age ;
Sex = sex ;
Gender = gender ;
Appearance = appearance ;
2024-02-01 05:12:09 -05:00
SpawnPriority = spawnPriority ;
2020-09-29 14:26:00 +02:00
2021-03-08 03:07:53 +01:00
_jobPriorities . Clear ( ) ;
2019-12-22 13:47:34 +01:00
2021-03-08 03:07:53 +01:00
foreach ( var ( job , priority ) in priorities )
{
_jobPriorities . Add ( job , priority ) ;
}
PreferenceUnavailable = prefsUnavailableMode ;
_antagPreferences . Clear ( ) ;
2024-05-12 09:18:21 +10:00
_antagPreferences . UnionWith ( antags ) ;
2022-09-10 17:40:06 +02:00
_traitPreferences . Clear ( ) ;
2024-06-29 15:39:57 +10:00
_traitPreferences . UnionWith ( GetValidTraits ( traits , prototypeManager ) ) ;
2024-04-16 22:57:43 +10:00
// Checks prototypes exist for all loadouts and dump / set to default if not.
var toRemove = new ValueList < string > ( ) ;
foreach ( var ( roleName , loadouts ) in _loadouts )
{
if ( ! prototypeManager . HasIndex < RoleLoadoutPrototype > ( roleName ) )
{
toRemove . Add ( roleName ) ;
continue ;
}
2024-05-12 09:18:21 +10:00
loadouts . EnsureValid ( this , session , collection ) ;
2024-04-16 22:57:43 +10:00
}
foreach ( var value in toRemove )
{
_loadouts . Remove ( value ) ;
}
2019-12-22 13:47:34 +01:00
}
2020-10-12 18:26:17 +02:00
2024-06-29 15:39:57 +10:00
/// <summary>
/// Takes in an IEnumerable of traits and returns a List of the valid traits.
/// </summary>
public List < ProtoId < TraitPrototype > > GetValidTraits ( IEnumerable < ProtoId < TraitPrototype > > traits , IPrototypeManager protoManager )
{
// Track points count for each group.
var groups = new Dictionary < string , int > ( ) ;
var result = new List < ProtoId < TraitPrototype > > ( ) ;
foreach ( var trait in traits )
{
if ( ! protoManager . TryIndex ( trait , out var traitProto ) )
continue ;
// Always valid.
if ( traitProto . Category = = null )
{
result . Add ( trait ) ;
continue ;
}
// No category so dump it.
if ( ! protoManager . TryIndex ( traitProto . Category , out var category ) )
continue ;
var existing = groups . GetOrNew ( category . ID ) ;
existing + = traitProto . Cost ;
// Too expensive.
if ( existing > category . MaxTraitPoints )
continue ;
groups [ category . ID ] = existing ;
result . Add ( trait ) ;
}
return result ;
}
2024-04-16 22:57:43 +10:00
public ICharacterProfile Validated ( ICommonSession session , IDependencyCollection collection )
2024-02-26 03:36:38 +01:00
{
var profile = new HumanoidCharacterProfile ( this ) ;
2024-04-16 22:57:43 +10:00
profile . EnsureValid ( session , collection ) ;
2024-02-26 03:36:38 +01:00
return profile ;
}
2022-10-15 17:45:47 -04:00
// sorry this is kind of weird and duplicated,
/// working inside these non entity systems is a bit wack
public static string GetName ( string species , Gender gender )
{
var namingSystem = IoCManager . Resolve < IEntitySystemManager > ( ) . GetEntitySystem < NamingSystem > ( ) ;
return namingSystem . GetName ( species , gender ) ;
}
2020-10-12 18:26:17 +02:00
public override bool Equals ( object? obj )
{
2024-05-12 09:18:21 +10:00
return ReferenceEquals ( this , obj ) | | obj is HumanoidCharacterProfile other & & Equals ( other ) ;
2020-10-12 18:26:17 +02:00
}
public override int GetHashCode ( )
{
2024-05-12 09:18:21 +10:00
var hashCode = new HashCode ( ) ;
hashCode . Add ( _jobPriorities ) ;
hashCode . Add ( _antagPreferences ) ;
hashCode . Add ( _traitPreferences ) ;
hashCode . Add ( _loadouts ) ;
hashCode . Add ( Name ) ;
hashCode . Add ( FlavorText ) ;
hashCode . Add ( Species ) ;
hashCode . Add ( Age ) ;
hashCode . Add ( ( int ) Sex ) ;
hashCode . Add ( ( int ) Gender ) ;
hashCode . Add ( Appearance ) ;
hashCode . Add ( ( int ) SpawnPriority ) ;
hashCode . Add ( ( int ) PreferenceUnavailable ) ;
return hashCode . ToHashCode ( ) ;
2020-10-12 18:26:17 +02:00
}
2024-04-16 22:57:43 +10:00
public void SetLoadout ( RoleLoadout loadout )
{
_loadouts [ loadout . Role . Id ] = loadout ;
}
2024-04-17 12:54:54 +10:00
public HumanoidCharacterProfile WithLoadout ( RoleLoadout loadout )
{
// Deep copies so we don't modify the DB profile.
var copied = new Dictionary < string , RoleLoadout > ( ) ;
foreach ( var proto in _loadouts )
{
if ( proto . Key = = loadout . Role )
continue ;
copied [ proto . Key ] = proto . Value . Clone ( ) ;
}
copied [ loadout . Role ] = loadout . Clone ( ) ;
2024-05-12 09:18:21 +10:00
var profile = Clone ( ) ;
profile . _loadouts = copied ;
return profile ;
2024-04-17 12:54:54 +10:00
}
2024-06-15 16:53:42 +10:00
public RoleLoadout GetLoadoutOrDefault ( string id , ICommonSession ? session , ProtoId < SpeciesPrototype > ? species , IEntityManager entManager , IPrototypeManager protoManager )
2024-04-16 22:57:43 +10:00
{
if ( ! _loadouts . TryGetValue ( id , out var loadout ) )
{
loadout = new RoleLoadout ( id ) ;
2024-06-15 16:53:42 +10:00
loadout . SetDefault ( this , session , protoManager , force : true ) ;
2024-04-16 22:57:43 +10:00
}
2024-06-15 16:53:42 +10:00
loadout . SetDefault ( this , session , protoManager ) ;
2024-04-16 22:57:43 +10:00
return loadout ;
}
2024-05-12 09:18:21 +10:00
public HumanoidCharacterProfile Clone ( )
{
return new HumanoidCharacterProfile ( this ) ;
}
2019-12-22 13:47:34 +01:00
}
}