From 0ac4c0e85c05dbf06b2948ecc7fcf19663de666c Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sun, 28 Mar 2021 08:26:32 +0200 Subject: [PATCH] SKREEEEEE (#3706) * Import bird sprites and define basic mob. * SKREEEEEEEEE * Move hair styles to new sprite accessory prototypes. Basic stuff, no multi-species stuff yet. * Vox hair styles and clothes * Make HumanoidCharacterProfile.Default() a static default to fix tests. Usages that wanted the previous random behavior now call Random(). * Remove names from hair style prototypes. (They're in localization files) * Update Content.Shared/Actions/ActionType.cs (sk)reeee github Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- .../Components/Clothing/ClothingComponent.cs | 11 +- .../HUD/Inventory/ClientInventoryComponent.cs | 9 +- .../MagicMirrorBoundUserInterface.cs | 102 +- .../Mobs/HumanoidAppearanceComponent.cs | 39 +- .../UserInterface/CharacterSetupGui.cs | 2 +- .../UserInterface/HumanoidProfileEditor.cs | 13 +- Content.Server/Database/ServerDbBase.cs | 4 +- .../Components/MagicMirrorComponent.cs | 30 +- Content.Server/GameTicking/GameTicker.cs | 2 +- .../Preferences/ServerPreferencesManager.cs | 4 +- Content.Shared/Actions/ActionType.cs | 3 +- Content.Shared/EntryPoint.cs | 3 + .../Mobs/SharedHumanoidAppearanceComponent.cs | 23 +- .../Components/SharedMagicMirrorComponent.cs | 25 +- .../Preferences/Appearance/HairStyles.cs | 280 +---- .../Appearance/SpriteAccessoryCategories.cs | 16 + .../Appearance/SpriteAccessoryManager.cs | 67 ++ .../Appearance/SpriteAccessoryPrototype.cs | 33 + .../HumanoidCharacterAppearance.cs | 65 +- .../Preferences/HumanoidCharacterProfile.cs | 22 +- Content.Shared/SharedContentIoC.cs | 13 + Content.Tests/ContentUnitTest.cs | 3 + Resources/Audio/Voice/Vox/shriek1.ogg | Bin 0 -> 14929 bytes Resources/Locale/en-US/accessories/common.ftl | 2 + .../en-US/accessories/human-facial-hair.ftl | 35 + .../Locale/en-US/accessories/human-hair.ftl | 174 +++ .../en-US/accessories/vox-facial-hair.ftl | 5 + .../Locale/en-US/accessories/vox-hair.ftl | 13 + Resources/Prototypes/Actions/actions.yml | 15 + .../Prototypes/Body/Mechanisms/vox_organs.yml | 1 + Resources/Prototypes/Body/Parts/vox_parts.yml | 274 +++++ Resources/Prototypes/Body/Presets/vox.yml | 14 + .../Prototypes/Entities/Mobs/Player/vox.yml | 23 + .../Prototypes/Entities/Mobs/Species/vox.yml | 109 ++ Resources/Prototypes/HairStyles/common.yml | 19 + .../HairStyles/human_facial_hair.yml | 210 ++++ .../Prototypes/HairStyles/human_hair.yml | 1044 +++++++++++++++++ .../Prototypes/HairStyles/vox_facial_hair.yml | 34 + Resources/Prototypes/HairStyles/vox_hair.yml | 91 ++ .../Color/yellow.rsi/equipped-HAND-vox.png | Bin 0 -> 387 bytes .../Hands/Gloves/Color/yellow.rsi/meta.json | 27 +- .../Mask/breath.rsi/equipped-MASK-vox.png | Bin 0 -> 434 bytes .../Clothing/Mask/breath.rsi/meta.json | 27 +- .../Color/black.rsi/equipped-FEET-vox.png | Bin 0 -> 467 bytes .../Clothing/Shoes/Color/black.rsi/meta.json | 27 +- .../grey.rsi/equipped-INNERCLOTHING-vox.png | Bin 0 -> 1049 bytes .../Jumpsuit/Color/grey.rsi/meta.json | 27 +- .../Mobs/Customization/eyes.rsi/meta.json | 2 +- .../Customization/eyes.rsi/vox_eyes_s.png | Bin 0 -> 125 bytes .../vox_facial_hair.rsi/meta.json | 1 + .../vox_facial_hair.rsi/vox_beard_s.png | Bin 0 -> 159 bytes .../vox_facial_hair.rsi/vox_colonel_s.png | Bin 0 -> 150 bytes .../vox_facial_hair.rsi/vox_fu_s.png | Bin 0 -> 169 bytes .../vox_facial_hair.rsi/vox_neck_s.png | Bin 0 -> 186 bytes .../vox_facial_hair.rsi/vox_ruff_beard_s.png | Bin 0 -> 314 bytes .../vox_facial_hair.rsi/vox_ruff_beard_s2.png | Bin 0 -> 96 bytes .../Mobs/Customization/vox_hair.rsi/meta.json | 1 + .../Customization/vox_hair.rsi/vox_afro_s.png | Bin 0 -> 298 bytes .../vox_hair.rsi/vox_afro_s2.png | Bin 0 -> 96 bytes .../Customization/vox_hair.rsi/vox_bald_s.png | Bin 0 -> 96 bytes .../vox_hair.rsi/vox_cropped_s.png | Bin 0 -> 262 bytes .../vox_hair.rsi/vox_cropped_s2.png | Bin 0 -> 96 bytes .../vox_hair.rsi/vox_horns_s.png | Bin 0 -> 236 bytes .../vox_hair.rsi/vox_horns_s2.png | Bin 0 -> 96 bytes .../vox_hair.rsi/vox_kingly_s.png | Bin 0 -> 309 bytes .../vox_hair.rsi/vox_kingly_s2.png | Bin 0 -> 96 bytes .../vox_hair.rsi/vox_mange_s.png | Bin 0 -> 296 bytes .../vox_hair.rsi/vox_mange_s2.png | Bin 0 -> 96 bytes .../vox_hair.rsi/vox_mohawk_s.png | Bin 0 -> 237 bytes .../vox_hair.rsi/vox_mohawk_s2.png | Bin 0 -> 96 bytes .../vox_hair.rsi/vox_nights_s.png | Bin 0 -> 256 bytes .../vox_hair.rsi/vox_nights_s2.png | Bin 0 -> 96 bytes .../Customization/vox_hair.rsi/vox_pony_s.png | Bin 0 -> 384 bytes .../vox_hair.rsi/vox_pony_s2.png | Bin 0 -> 96 bytes .../Customization/vox_hair.rsi/vox_rows_s.png | Bin 0 -> 227 bytes .../vox_hair.rsi/vox_rows_s2.png | Bin 0 -> 96 bytes .../vox_hair.rsi/vox_ruff_hawk_s.png | Bin 0 -> 402 bytes .../vox_hair.rsi/vox_ruff_hawk_s2.png | Bin 0 -> 96 bytes .../vox_hair.rsi/vox_shortquills_s.png | Bin 0 -> 250 bytes .../vox_hair.rsi/vox_shortquills_s2.png | Bin 0 -> 96 bytes .../Customization/vox_hair.rsi/vox_surf_s.png | Bin 0 -> 377 bytes .../vox_hair.rsi/vox_surf_s2.png | Bin 0 -> 96 bytes .../Customization/vox_hair.rsi/vox_yasu_s.png | Bin 0 -> 356 bytes .../vox_hair.rsi/vox_yasu_s2.png | Bin 0 -> 96 bytes .../Mobs/Species/Vox/parts.rsi/groin_f.png | Bin 0 -> 318 bytes .../Mobs/Species/Vox/parts.rsi/groin_m.png | Bin 0 -> 318 bytes .../Mobs/Species/Vox/parts.rsi/head_f.png | Bin 0 -> 737 bytes .../Mobs/Species/Vox/parts.rsi/head_m.png | Bin 0 -> 737 bytes .../Mobs/Species/Vox/parts.rsi/l_arm.png | Bin 0 -> 385 bytes .../Mobs/Species/Vox/parts.rsi/l_foot.png | Bin 0 -> 255 bytes .../Mobs/Species/Vox/parts.rsi/l_hand.png | Bin 0 -> 337 bytes .../Mobs/Species/Vox/parts.rsi/l_leg.png | Bin 0 -> 596 bytes .../Mobs/Species/Vox/parts.rsi/meta.json | 1 + .../Species/Vox/parts.rsi/overlay_husk.png | Bin 0 -> 542 bytes .../Mobs/Species/Vox/parts.rsi/r_arm.png | Bin 0 -> 391 bytes .../Mobs/Species/Vox/parts.rsi/r_foot.png | Bin 0 -> 252 bytes .../Mobs/Species/Vox/parts.rsi/r_hand.png | Bin 0 -> 354 bytes .../Mobs/Species/Vox/parts.rsi/r_leg.png | Bin 0 -> 591 bytes .../Mobs/Species/Vox/parts.rsi/torso_f.png | Bin 0 -> 1038 bytes .../Mobs/Species/Vox/parts.rsi/torso_m.png | Bin 0 -> 1038 bytes .../Mobs/Species/Vox/parts.rsi/vox_m.png | Bin 0 -> 2545 bytes 101 files changed, 2440 insertions(+), 505 deletions(-) create mode 100644 Content.Shared/Preferences/Appearance/SpriteAccessoryCategories.cs create mode 100644 Content.Shared/Preferences/Appearance/SpriteAccessoryManager.cs create mode 100644 Content.Shared/Preferences/Appearance/SpriteAccessoryPrototype.cs create mode 100644 Content.Shared/SharedContentIoC.cs create mode 100644 Resources/Audio/Voice/Vox/shriek1.ogg create mode 100644 Resources/Locale/en-US/accessories/common.ftl create mode 100644 Resources/Locale/en-US/accessories/human-facial-hair.ftl create mode 100644 Resources/Locale/en-US/accessories/human-hair.ftl create mode 100644 Resources/Locale/en-US/accessories/vox-facial-hair.ftl create mode 100644 Resources/Locale/en-US/accessories/vox-hair.ftl create mode 100644 Resources/Prototypes/Body/Mechanisms/vox_organs.yml create mode 100644 Resources/Prototypes/Body/Parts/vox_parts.yml create mode 100644 Resources/Prototypes/Body/Presets/vox.yml create mode 100644 Resources/Prototypes/Entities/Mobs/Player/vox.yml create mode 100644 Resources/Prototypes/Entities/Mobs/Species/vox.yml create mode 100644 Resources/Prototypes/HairStyles/common.yml create mode 100644 Resources/Prototypes/HairStyles/human_facial_hair.yml create mode 100644 Resources/Prototypes/HairStyles/human_hair.yml create mode 100644 Resources/Prototypes/HairStyles/vox_facial_hair.yml create mode 100644 Resources/Prototypes/HairStyles/vox_hair.yml create mode 100644 Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/equipped-HAND-vox.png create mode 100644 Resources/Textures/Clothing/Mask/breath.rsi/equipped-MASK-vox.png create mode 100644 Resources/Textures/Clothing/Shoes/Color/black.rsi/equipped-FEET-vox.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/Color/grey.rsi/equipped-INNERCLOTHING-vox.png create mode 100644 Resources/Textures/Mobs/Customization/eyes.rsi/vox_eyes_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/meta.json create mode 100644 Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_beard_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_colonel_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_fu_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_neck_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/meta.json create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_bald_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s2.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s.png create mode 100644 Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s2.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_f.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_m.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/head_f.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/head_m.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/l_arm.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/l_foot.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/l_hand.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/l_leg.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/overlay_husk.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/r_arm.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/r_foot.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/r_hand.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/r_leg.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_f.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_m.png create mode 100644 Resources/Textures/Mobs/Species/Vox/parts.rsi/vox_m.png diff --git a/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs b/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs index 9ae32a580d..e2b6abd950 100644 --- a/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs +++ b/Content.Client/GameObjects/Components/Clothing/ClothingComponent.cs @@ -61,7 +61,7 @@ namespace Content.Client.GameObjects.Components.Clothing set => _femaleMask = value; } - public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EquipmentSlotDefines.SlotFlags slot) + public (RSI rsi, RSI.StateId stateId)? GetEquippedStateInfo(EquipmentSlotDefines.SlotFlags slot, string? speciesId=null) { if (RsiPath == null) { @@ -77,6 +77,15 @@ namespace Content.Client.GameObjects.Components.Clothing var prefix = ClothingEquippedPrefix ?? EquippedPrefix; var stateId = prefix != null ? $"{prefix}-equipped-{slot}" : $"equipped-{slot}"; + if (speciesId != null) + { + var speciesState = $"{stateId}-{speciesId}"; + if (rsi.TryGetState(speciesState, out _)) + { + return (rsi, speciesState); + } + } + if (rsi.TryGetState(stateId, out _)) { return (rsi, stateId); diff --git a/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs b/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs index 4588465624..84f43e203a 100644 --- a/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs +++ b/Content.Client/GameObjects/Components/HUD/Inventory/ClientInventoryComponent.cs @@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Client.GameObjects.Components.Clothing; -using Content.Client.GameObjects.Components.Items; using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.EntitySystems.EffectBlocker; @@ -10,6 +9,7 @@ using Content.Shared.Preferences.Appearance; using Robust.Client.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines; using static Content.Shared.GameObjects.Components.Inventory.SharedInventoryComponent.ClientInventoryMessage; @@ -34,6 +34,9 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory private bool _playerAttached = false; + [ViewVariables] + [DataField("speciesId")] public string? SpeciesId { get; set; } + public override void OnRemove() { base.OnRemove(); @@ -182,7 +185,7 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory if (entity.TryGetComponent(out ClothingComponent? clothing)) { var flag = SlotMasks[slot]; - var data = clothing.GetEquippedStateInfo(flag); + var data = clothing.GetEquippedStateInfo(flag, SpeciesId); if (data != null) { var (rsi, state) = data.Value; @@ -190,7 +193,7 @@ namespace Content.Client.GameObjects.Components.HUD.Inventory _sprite.LayerSetState(slot, state, rsi); _sprite.LayerSetAutoAnimated(slot, true); - if (slot == Slots.INNERCLOTHING) + if (slot == Slots.INNERCLOTHING && _sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _)) { _sprite.LayerSetState(HumanoidVisualLayers.StencilMask, clothing.FemaleMask switch { diff --git a/Content.Client/GameObjects/Components/MagicMirrorBoundUserInterface.cs b/Content.Client/GameObjects/Components/MagicMirrorBoundUserInterface.cs index fea4b46bbb..3dd39e460b 100644 --- a/Content.Client/GameObjects/Components/MagicMirrorBoundUserInterface.cs +++ b/Content.Client/GameObjects/Components/MagicMirrorBoundUserInterface.cs @@ -4,15 +4,15 @@ using Content.Client.UserInterface.Stylesheets; using Content.Shared.Preferences.Appearance; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; +using Robust.Client.Utility; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Maths; using static Content.Shared.GameObjects.Components.SharedMagicMirrorComponent; -using static Content.Client.StaticIoC; namespace Content.Client.GameObjects.Components { @@ -97,7 +97,7 @@ namespace Content.Client.GameObjects.Components { _slider = new Slider { - StyleClasses = { styleClass }, + StyleClasses = {styleClass}, HorizontalExpand = true, VerticalAlignment = VAlignment.Center, MaxValue = byte.MaxValue @@ -110,10 +110,10 @@ namespace Content.Client.GameObjects.Components AddChild(new HBoxContainer { Children = - { - _slider, - _textBox - } + { + _slider, + _textBox + } }); _slider.OnValueChanged += _ => @@ -151,47 +151,42 @@ namespace Content.Client.GameObjects.Components } } - public class FacialHairStylePicker : HairStylePicker + public sealed class HairStylePicker : Control { - public override void Populate() - { - var humanFacialHairRSIPath = SharedSpriteComponent.TextureRoot / "Mobs/Customization/human_facial_hair.rsi"; - var humanFacialHairRSI = ResC.GetResource(humanFacialHairRSIPath).RSI; + [Dependency] private readonly SpriteAccessoryManager _spriteAccessoryManager = default!; - var styles = HairStyles.FacialHairStylesMap.ToList(); - styles.Sort(HairStyles.FacialHairStyleComparer); - - foreach (var (styleName, styleState) in HairStyles.FacialHairStylesMap) - { - Items.AddItem(styleName, humanFacialHairRSI[styleState].Frame0); - } - } - } - - public class HairStylePicker : Control - { public event Action? OnHairColorPicked; public event Action? OnHairStylePicked; - protected readonly ItemList Items; + private readonly ItemList _items; + private readonly Control _colorContainer; private readonly ColorSlider _colorSliderR; private readonly ColorSlider _colorSliderG; private readonly ColorSlider _colorSliderB; private Color _lastColor; + private SpriteAccessoryCategories _categories; - public void SetData(Color color, string styleName) + public void SetData(Color color, string styleId, SpriteAccessoryCategories categories, bool canColor) { + if (_categories != categories) + { + _categories = categories; + Populate(); + } + + _colorContainer.Visible = canColor; _lastColor = color; _colorSliderR.ColorValue = color.RByte; _colorSliderG.ColorValue = color.GByte; _colorSliderB.ColorValue = color.BByte; - foreach (var item in Items) + foreach (var item in _items) { - item.Selected = item.Text == styleName; + var prototype = (SpriteAccessoryPrototype) item.Metadata!; + item.Selected = prototype.ID == styleId; } UpdateStylePickerColor(); @@ -199,7 +194,7 @@ namespace Content.Client.GameObjects.Components private void UpdateStylePickerColor() { - foreach (var item in Items) + foreach (var item in _items) { item.IconModulate = _lastColor; } @@ -207,25 +202,29 @@ namespace Content.Client.GameObjects.Components public HairStylePicker() { + IoCManager.InjectDependencies(this); + var vBox = new VBoxContainer(); AddChild(vBox); - vBox.AddChild(_colorSliderR = new ColorSlider(StyleNano.StyleClassSliderRed)); - vBox.AddChild(_colorSliderG = new ColorSlider(StyleNano.StyleClassSliderGreen)); - vBox.AddChild(_colorSliderB = new ColorSlider(StyleNano.StyleClassSliderBlue)); + _colorContainer = new VBoxContainer(); + vBox.AddChild(_colorContainer); + _colorContainer.AddChild(_colorSliderR = new ColorSlider(StyleNano.StyleClassSliderRed)); + _colorContainer.AddChild(_colorSliderG = new ColorSlider(StyleNano.StyleClassSliderGreen)); + _colorContainer.AddChild(_colorSliderB = new ColorSlider(StyleNano.StyleClassSliderBlue)); Action colorValueChanged = ColorValueChanged; _colorSliderR.OnValueChanged += colorValueChanged; _colorSliderG.OnValueChanged += colorValueChanged; _colorSliderB.OnValueChanged += colorValueChanged; - Items = new ItemList + _items = new ItemList { VerticalExpand = true, MinSize = (300, 250) }; - vBox.AddChild(Items); - Items.OnItemSelected += ItemSelected; + vBox.AddChild(_items); + _items.OnItemSelected += ItemSelected; } private void ColorValueChanged() @@ -241,27 +240,28 @@ namespace Content.Client.GameObjects.Components UpdateStylePickerColor(); } - public virtual void Populate() + public void Populate() { - var humanHairRSIPath = SharedSpriteComponent.TextureRoot / "Mobs/Customization/human_hair.rsi"; - var humanHairRSI = ResC.GetResource(humanHairRSIPath).RSI; + var styles = _spriteAccessoryManager + .AccessoriesForCategory(_categories) + .ToList(); + styles.Sort(HairStyles.SpriteAccessoryComparer); - var styles = HairStyles.HairStylesMap.ToList(); - styles.Sort(HairStyles.HairStyleComparer); - - foreach (var (styleName, styleState) in styles) + foreach (var style in styles) { - Items.AddItem(styleName, humanHairRSI[styleState].Frame0); + var item = _items.AddItem(style.Name, style.Sprite.Frame0()); + item.Metadata = style; } } private void ItemSelected(ItemList.ItemListSelectedEventArgs args) { - var hairColor = Items[args.ItemIndex].Text; + var prototype = (SpriteAccessoryPrototype?) _items[args.ItemIndex].Metadata; + var style = prototype?.ID; - if (hairColor != null) + if (style != null) { - OnHairStylePicked?.Invoke(hairColor); + OnHairStylePicked?.Invoke(style); } } @@ -321,7 +321,7 @@ namespace Content.Client.GameObjects.Components public class MagicMirrorWindow : SS14Window { private readonly HairStylePicker _hairStylePicker; - private readonly FacialHairStylePicker _facialHairStylePicker; + private readonly HairStylePicker _facialHairStylePicker; private readonly EyeColorPicker _eyeColorPicker; public MagicMirrorWindow(MagicMirrorBoundUserInterface owner) @@ -330,12 +330,10 @@ namespace Content.Client.GameObjects.Components Title = Loc.GetString("Magic Mirror"); _hairStylePicker = new HairStylePicker {HorizontalExpand = true}; - _hairStylePicker.Populate(); _hairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, false); _hairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, false); - _facialHairStylePicker = new FacialHairStylePicker {HorizontalExpand = true}; - _facialHairStylePicker.Populate(); + _facialHairStylePicker = new HairStylePicker {HorizontalExpand = true}; _facialHairStylePicker.OnHairStylePicked += newStyle => owner.HairSelected(newStyle, true); _facialHairStylePicker.OnHairColorPicked += newColor => owner.HairColorSelected(newColor, true); @@ -363,8 +361,8 @@ namespace Content.Client.GameObjects.Components public void SetInitialData(MagicMirrorInitialDataMessage initialData) { - _facialHairStylePicker.SetData(initialData.FacialHairColor, initialData.FacialHairName); - _hairStylePicker.SetData(initialData.HairColor, initialData.HairName); + _facialHairStylePicker.SetData(initialData.FacialHairColor, initialData.FacialHairId, initialData.CategoriesFacialHair, initialData.CanColorFacialHair); + _hairStylePicker.SetData(initialData.HairColor, initialData.HairId, initialData.CategoriesHair, initialData.CanColorHair); _eyeColorPicker.SetData(initialData.EyeColor); } } diff --git a/Content.Client/GameObjects/Components/Mobs/HumanoidAppearanceComponent.cs b/Content.Client/GameObjects/Components/Mobs/HumanoidAppearanceComponent.cs index 96aa3360c7..6ee722c792 100644 --- a/Content.Client/GameObjects/Components/Mobs/HumanoidAppearanceComponent.cs +++ b/Content.Client/GameObjects/Components/Mobs/HumanoidAppearanceComponent.cs @@ -6,12 +6,18 @@ using Content.Shared.Preferences; using Content.Shared.Preferences.Appearance; using Robust.Client.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; namespace Content.Client.GameObjects.Components.Mobs { [RegisterComponent] public sealed class HumanoidAppearanceComponent : SharedHumanoidAppearanceComponent, IBodyPartAdded, IBodyPartRemoved { + [Dependency] private readonly SpriteAccessoryManager _accessoryManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + public override HumanoidCharacterAppearance Appearance { get => base.Appearance; @@ -60,15 +66,18 @@ namespace Content.Client.GameObjects.Components.Mobs } } - sprite.LayerSetColor(HumanoidVisualLayers.Hair, Appearance.HairColor); - sprite.LayerSetColor(HumanoidVisualLayers.FacialHair, Appearance.FacialHairColor); + sprite.LayerSetColor(HumanoidVisualLayers.Hair, + CanColorHair ? Appearance.HairColor : Color.White); + sprite.LayerSetColor(HumanoidVisualLayers.FacialHair, + CanColorFacialHair ? Appearance.FacialHairColor : Color.White); sprite.LayerSetColor(HumanoidVisualLayers.Eyes, Appearance.EyeColor); sprite.LayerSetState(HumanoidVisualLayers.Chest, Sex == Sex.Male ? "torso_m" : "torso_f"); sprite.LayerSetState(HumanoidVisualLayers.Head, Sex == Sex.Male ? "head_m" : "head_f"); - sprite.LayerSetVisible(HumanoidVisualLayers.StencilMask, Sex == Sex.Female); + if (sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out _)) + sprite.LayerSetVisible(HumanoidVisualLayers.StencilMask, Sex == Sex.Female); if (Owner.TryGetComponent(out var cuffed)) { @@ -79,17 +88,25 @@ namespace Content.Client.GameObjects.Components.Mobs sprite.LayerSetVisible(HumanoidVisualLayers.Handcuffs, false); } - var hairStyle = Appearance.HairStyleName; - if (string.IsNullOrWhiteSpace(hairStyle) || !HairStyles.HairStylesMap.ContainsKey(hairStyle)) + var hairStyle = Appearance.HairStyleId; + if (string.IsNullOrWhiteSpace(hairStyle) || + !_accessoryManager.IsValidAccessoryInCategory(hairStyle, CategoriesHair)) + { hairStyle = HairStyles.DefaultHairStyle; - sprite.LayerSetState(HumanoidVisualLayers.Hair, - HairStyles.HairStylesMap[hairStyle]); + } - var facialHairStyle = Appearance.FacialHairStyleName; - if (string.IsNullOrWhiteSpace(facialHairStyle) || !HairStyles.FacialHairStylesMap.ContainsKey(facialHairStyle)) + var facialHairStyle = Appearance.FacialHairStyleId; + if (string.IsNullOrWhiteSpace(facialHairStyle) || + !_accessoryManager.IsValidAccessoryInCategory(facialHairStyle, CategoriesFacialHair)) + { facialHairStyle = HairStyles.DefaultFacialHairStyle; - sprite.LayerSetState(HumanoidVisualLayers.FacialHair, - HairStyles.FacialHairStylesMap[facialHairStyle]); + } + + var hairPrototype = _prototypeManager.Index(hairStyle); + var facialHairPrototype = _prototypeManager.Index(facialHairStyle); + + sprite.LayerSetSprite(HumanoidVisualLayers.Hair, hairPrototype.Sprite); + sprite.LayerSetSprite(HumanoidVisualLayers.FacialHair, facialHairPrototype.Sprite); } public void BodyPartAdded(BodyPartAddedEventArgs args) diff --git a/Content.Client/UserInterface/CharacterSetupGui.cs b/Content.Client/UserInterface/CharacterSetupGui.cs index e0917d43a8..2dcaf3d406 100644 --- a/Content.Client/UserInterface/CharacterSetupGui.cs +++ b/Content.Client/UserInterface/CharacterSetupGui.cs @@ -125,7 +125,7 @@ namespace Content.Client.UserInterface }; _createNewCharacterButton.OnPressed += args => { - preferencesManager.CreateCharacter(HumanoidCharacterProfile.Default()); + preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random()); UpdateUI(); args.Event.Handle(); }; diff --git a/Content.Client/UserInterface/HumanoidProfileEditor.cs b/Content.Client/UserInterface/HumanoidProfileEditor.cs index 1c2df31e34..55319fba4b 100644 --- a/Content.Client/UserInterface/HumanoidProfileEditor.cs +++ b/Content.Client/UserInterface/HumanoidProfileEditor.cs @@ -7,6 +7,7 @@ using Content.Client.Interfaces; using Content.Client.UserInterface.Stylesheets; using Content.Shared.GameTicking; using Content.Shared.Preferences; +using Content.Shared.Preferences.Appearance; using Content.Shared.Roles; using Robust.Client.GameObjects; using Robust.Client.Graphics; @@ -46,7 +47,7 @@ namespace Content.Client.UserInterface private readonly OptionButton _clothingButton; private readonly OptionButton _backpackButton; private readonly HairStylePicker _hairPicker; - private readonly FacialHairStylePicker _facialHairPicker; + private readonly HairStylePicker _facialHairPicker; private readonly EyeColorPicker _eyesPicker; private readonly List _jobPriorities; @@ -281,7 +282,7 @@ namespace Content.Client.UserInterface IsDirty = true; }; - _facialHairPicker = new FacialHairStylePicker(); + _facialHairPicker = new HairStylePicker(); _facialHairPicker.Populate(); _facialHairPicker.OnHairStylePicked += newStyle => @@ -794,10 +795,14 @@ namespace Content.Client.UserInterface _hairPicker.SetData( Profile.Appearance.HairColor, - Profile.Appearance.HairStyleName); + Profile.Appearance.HairStyleId, + SpriteAccessoryCategories.HumanHair, + true); _facialHairPicker.SetData( Profile.Appearance.FacialHairColor, - Profile.Appearance.FacialHairStyleName); + Profile.Appearance.FacialHairStyleId, + SpriteAccessoryCategories.HumanFacialHair, + false); } private void UpdateEyePickers() diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index 3e4c22b1e3..263988a537 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -197,9 +197,9 @@ namespace Content.Server.Database Age = humanoid.Age, Sex = humanoid.Sex.ToString(), Gender = humanoid.Gender.ToString(), - HairName = appearance.HairStyleName, + HairName = appearance.HairStyleId, HairColor = appearance.HairColor.ToHex(), - FacialHairName = appearance.FacialHairStyleName, + FacialHairName = appearance.FacialHairStyleId, FacialHairColor = appearance.FacialHairColor.ToHex(), EyeColor = appearance.EyeColor.ToHex(), SkinColor = appearance.SkinColor.ToHex(), diff --git a/Content.Server/GameObjects/Components/MagicMirrorComponent.cs b/Content.Server/GameObjects/Components/MagicMirrorComponent.cs index 077f62944c..a4ee2566d4 100644 --- a/Content.Server/GameObjects/Components/MagicMirrorComponent.cs +++ b/Content.Server/GameObjects/Components/MagicMirrorComponent.cs @@ -7,6 +7,7 @@ using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Preferences.Appearance; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Maths; using Robust.Shared.ViewVariables; @@ -17,6 +18,8 @@ namespace Content.Server.GameObjects.Components [ComponentReference(typeof(IActivate))] public class MagicMirrorComponent : SharedMagicMirrorComponent, IActivate { + [Dependency] private readonly SpriteAccessoryManager _spriteAccessoryManager = default!; + [ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(MagicMirrorUiKey.Key); public override void Initialize() @@ -39,7 +42,7 @@ namespace Content.Server.GameObjects.Components base.OnRemove(); } - private static void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) + private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) { if (obj.Session.AttachedEntity == null) { @@ -54,18 +57,23 @@ namespace Content.Server.GameObjects.Components switch (obj.Message) { case HairSelectedMessage msg: - var map = - msg.IsFacialHair ? HairStyles.FacialHairStylesMap : HairStyles.HairStylesMap; - if (!map.ContainsKey(msg.HairName)) + var cat = msg.IsFacialHair + ? looks.CategoriesFacialHair + : looks.CategoriesHair; + + if (!_spriteAccessoryManager.IsValidAccessoryInCategory(msg.HairId, cat)) return; looks.Appearance = msg.IsFacialHair - ? looks.Appearance.WithFacialHairStyleName(msg.HairName) - : looks.Appearance.WithHairStyleName(msg.HairName); + ? looks.Appearance.WithFacialHairStyleName(msg.HairId) + : looks.Appearance.WithHairStyleName(msg.HairId); break; case HairColorSelectedMessage msg: + if (msg.IsFacialHair ? !looks.CanColorFacialHair : !looks.CanColorHair) + return; + var (r, g, b) = msg.HairColor; var color = new Color(r, g, b); @@ -105,9 +113,13 @@ namespace Content.Server.GameObjects.Components var msg = new MagicMirrorInitialDataMessage( appearance.HairColor, appearance.FacialHairColor, - appearance.HairStyleName, - appearance.FacialHairStyleName, - appearance.EyeColor); + appearance.HairStyleId, + appearance.FacialHairStyleId, + appearance.EyeColor, + looks.CategoriesHair, + looks.CategoriesFacialHair, + looks.CanColorHair, + looks.CanColorFacialHair); UserInterface?.SendMessage(msg, actor.playerSession); } diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index c24a07ea4c..f305495498 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -286,7 +286,7 @@ namespace Content.Server.GameTicking { if (!profiles.ContainsKey(readyPlayer.UserId)) { - profiles.Add(readyPlayer.UserId, HumanoidCharacterProfile.Default()); + profiles.Add(readyPlayer.UserId, HumanoidCharacterProfile.Random()); } } diff --git a/Content.Server/Preferences/ServerPreferencesManager.cs b/Content.Server/Preferences/ServerPreferencesManager.cs index 23f791d17e..a580e9d942 100644 --- a/Content.Server/Preferences/ServerPreferencesManager.cs +++ b/Content.Server/Preferences/ServerPreferencesManager.cs @@ -182,7 +182,7 @@ namespace Content.Server.Preferences { PrefsLoaded = Task.CompletedTask, Prefs = new PlayerPreferences( - new[] {new KeyValuePair(0, HumanoidCharacterProfile.Default())}, + new[] {new KeyValuePair(0, HumanoidCharacterProfile.Random())}, 0, Color.Transparent) }; @@ -249,7 +249,7 @@ namespace Content.Server.Preferences var prefs = await _db.GetPlayerPreferencesAsync(userId); if (prefs is null) { - return await _db.InitPrefsAsync(userId, HumanoidCharacterProfile.Default()); + return await _db.InitPrefsAsync(userId, HumanoidCharacterProfile.Random()); } return SanitizePreferences(prefs); diff --git a/Content.Shared/Actions/ActionType.cs b/Content.Shared/Actions/ActionType.cs index dec3ae5494..beb5e6136d 100644 --- a/Content.Shared/Actions/ActionType.cs +++ b/Content.Shared/Actions/ActionType.cs @@ -7,9 +7,10 @@ namespace Content.Shared.Actions public enum ActionType : byte { Error, + HumanScream, + VoxScream, CombatMode, Disarm, - HumanScream, GhostBoo, DebugInstant, DebugToggle, diff --git a/Content.Shared/EntryPoint.cs b/Content.Shared/EntryPoint.cs index 42250b1c2c..7eb6c60ee0 100644 --- a/Content.Shared/EntryPoint.cs +++ b/Content.Shared/EntryPoint.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using Content.Shared.Chemistry; using Content.Shared.Maps; +using Content.Shared.Preferences.Appearance; using Robust.Shared.ContentPack; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -19,6 +20,7 @@ namespace Content.Shared public override void PreInit() { IoCManager.InjectDependencies(this); + SharedContentIoC.Register(); Localization.Init(); } @@ -33,6 +35,7 @@ namespace Content.Shared _initTileDefinitions(); CheckReactions(); + IoCManager.Resolve().Initialize(); } private void CheckReactions() diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedHumanoidAppearanceComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedHumanoidAppearanceComponent.cs index 1285b3fa5f..67d740aea9 100644 --- a/Content.Shared/GameObjects/Components/Mobs/SharedHumanoidAppearanceComponent.cs +++ b/Content.Shared/GameObjects/Components/Mobs/SharedHumanoidAppearanceComponent.cs @@ -1,23 +1,41 @@ #nullable enable using System; using Content.Shared.Preferences; +using Content.Shared.Preferences.Appearance; using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.Players; using Robust.Shared.Serialization; +using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; namespace Content.Shared.GameObjects.Components.Mobs { public abstract class SharedHumanoidAppearanceComponent : Component { - private HumanoidCharacterAppearance _appearance = default!; + private HumanoidCharacterAppearance _appearance = HumanoidCharacterAppearance.Default(); private Sex _sex; private Gender _gender; public sealed override string Name => "HumanoidAppearance"; public sealed override uint? NetID => ContentNetIDs.HUMANOID_APPEARANCE; + [DataField("categoriesHair")] + [ViewVariables] + public SpriteAccessoryCategories CategoriesHair { get; set; } = SpriteAccessoryCategories.HumanHair; + + [DataField("categoriesFacialHair")] + [ViewVariables] + public SpriteAccessoryCategories CategoriesFacialHair { get; set; } = SpriteAccessoryCategories.HumanFacialHair; + + [ViewVariables] + [DataField("canColorHair")] + public bool CanColorHair { get; set; } = true; + + [ViewVariables] + [DataField("canColorFacialHair")] + public bool CanColorFacialHair { get; set; } = true; + [ViewVariables(VVAccess.ReadWrite)] public virtual HumanoidCharacterAppearance Appearance { @@ -80,7 +98,8 @@ namespace Content.Shared.GameObjects.Components.Mobs [NetSerializable] private sealed class HumanoidAppearanceComponentState : ComponentState { - public HumanoidAppearanceComponentState(HumanoidCharacterAppearance appearance, Sex sex, Gender gender) : base(ContentNetIDs.HUMANOID_APPEARANCE) + public HumanoidAppearanceComponentState(HumanoidCharacterAppearance appearance, Sex sex, Gender gender) : + base(ContentNetIDs.HUMANOID_APPEARANCE) { Appearance = appearance; Sex = sex; diff --git a/Content.Shared/GameObjects/Components/SharedMagicMirrorComponent.cs b/Content.Shared/GameObjects/Components/SharedMagicMirrorComponent.cs index 9783c90ea1..8f57996d1e 100644 --- a/Content.Shared/GameObjects/Components/SharedMagicMirrorComponent.cs +++ b/Content.Shared/GameObjects/Components/SharedMagicMirrorComponent.cs @@ -1,5 +1,6 @@ #nullable enable using System; +using Content.Shared.Preferences.Appearance; using Robust.Shared.GameObjects; using Robust.Shared.Maths; using Robust.Shared.Serialization; @@ -19,12 +20,12 @@ namespace Content.Shared.GameObjects.Components [Serializable, NetSerializable] public class HairSelectedMessage : BoundUserInterfaceMessage { - public readonly string HairName; + public readonly string HairId; public readonly bool IsFacialHair; - public HairSelectedMessage(string name, bool isFacialHair) + public HairSelectedMessage(string id, bool isFacialHair) { - HairName = name; + HairId = id; IsFacialHair = isFacialHair; } } @@ -58,17 +59,25 @@ namespace Content.Shared.GameObjects.Components { public readonly Color HairColor; public readonly Color FacialHairColor; - public readonly string HairName; - public readonly string FacialHairName; + public readonly string HairId; + public readonly string FacialHairId; public readonly Color EyeColor; + public readonly SpriteAccessoryCategories CategoriesHair; + public readonly SpriteAccessoryCategories CategoriesFacialHair; + public readonly bool CanColorHair; + public readonly bool CanColorFacialHair; - public MagicMirrorInitialDataMessage(Color hairColor, Color facialHairColor, string hairName, string facialHairName, Color eyeColor) + public MagicMirrorInitialDataMessage(Color hairColor, Color facialHairColor, string hairId, string facialHairId, Color eyeColor, SpriteAccessoryCategories categoriesHair, SpriteAccessoryCategories categoriesFacialHair, bool canColorHair, bool canColorFacialHair) { HairColor = hairColor; FacialHairColor = facialHairColor; - HairName = hairName; - FacialHairName = facialHairName; + HairId = hairId; + FacialHairId = facialHairId; EyeColor = eyeColor; + CategoriesHair = categoriesHair; + CategoriesFacialHair = categoriesFacialHair; + CanColorHair = canColorHair; + CanColorFacialHair = canColorFacialHair; } } } diff --git a/Content.Shared/Preferences/Appearance/HairStyles.cs b/Content.Shared/Preferences/Appearance/HairStyles.cs index 15f00f1f6c..f33b522bf4 100644 --- a/Content.Shared/Preferences/Appearance/HairStyles.cs +++ b/Content.Shared/Preferences/Appearance/HairStyles.cs @@ -1,277 +1,16 @@ #nullable enable using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using Robust.Shared.Maths; namespace Content.Shared.Preferences.Appearance { - [SuppressMessage("ReSharper", "StringLiteralTypo")] public static class HairStyles { - public const string DefaultHairStyle = "Bald"; - public const string DefaultFacialHairStyle = "Shaved"; + public const string DefaultHairStyle = "HairBald"; + public const string DefaultFacialHairStyle = "FacialHairShaved"; - public static readonly Dictionary HairStylesMap = new() - { - {"Afro", "afro"}, - {"Afro 2", "afro2"}, - {"Afro (Large)", "bigafro"}, - {"Ahoge", "antenna"}, - {"Bald", "bald"}, - {"Balding Hair", "e"}, - {"Bedhead", "bedhead"}, - {"Bedhead 2", "bedheadv2"}, - {"Bedhead 3", "bedheadv3"}, - {"Long Bedhead", "long_bedhead"}, - {"Floorlength Bedhead", "floorlength_bedhead"}, - {"Beehive", "beehive"}, - {"Beehive 2", "beehivev2"}, - {"Bob Hair", "bob"}, - {"Bob Hair 2", "bob2"}, - {"Bob Hair 3", "bobcut"}, - {"Bob Hair 4", "bob4"}, - {"Bobcurl", "bobcurl"}, - {"Boddicker", "boddicker"}, - {"Bowlcut", "bowlcut"}, - {"Bowlcut 2", "bowlcut2"}, - {"Braid (Floorlength)", "braid"}, - {"Braided", "braided"}, - {"Braided Front", "braidfront"}, - {"Braid (High)", "braid2"}, - {"Braid (Low)", "hbraid"}, - {"Braid (Short)", "shortbraid"}, - {"Braided Tail", "braidtail"}, - {"Bun Head", "bun"}, - {"Bun Head 2", "bunhead2"}, - {"Bun Head 3", "bun3"}, - {"Bun (Large)", "largebun"}, - {"Bun (Manbun)", "manbun"}, - {"Bun (Tight)", "tightbun"}, - {"Business Hair", "business"}, - {"Business Hair 2", "business2"}, - {"Business Hair 3", "business3"}, - {"Business Hair 4", "business4"}, - {"Buzzcut", "buzzcut"}, - {"CIA", "cia"}, - {"Coffee House", "coffeehouse"}, - {"Combover", "combover"}, - {"Cornrows", "cornrows"}, - {"Cornrows 2", "cornrows2"}, - {"Cornrow Bun", "cornrowbun"}, - {"Cornrow Braid", "cornrowbraid"}, - {"Cornrow Tail", "cornrowtail"}, - {"Crewcut", "crewcut"}, - {"Curls", "curls"}, - {"Cut Hair", "c"}, - {"Dandy Pompadour", "dandypompadour"}, - {"Devil Lock", "devilock"}, - {"Double Bun", "doublebun"}, - {"Dreadlocks", "dreads"}, - {"Drillruru", "drillruru"}, - {"Drill Hair (Extended)", "drillhairextended"}, - {"Emo", "emo"}, - {"Emo Fringe", "emofringe"}, - {"Fade (None)", "nofade"}, - {"Fade (High)", "highfade"}, - {"Fade (Medium)", "medfade"}, - {"Fade (Low)", "lowfade"}, - {"Fade (Bald)", "baldfade"}, - {"Feather", "feather"}, - {"Father", "father"}, - {"Flat Top", "sargeant"}, - {"Flair", "flair"}, - {"Flat Top (Big)", "bigflattop"}, - {"Flow Hair", "f"}, - {"Gelled Back", "gelled"}, - {"Gentle", "gentle"}, - {"Half-banged Hair", "halfbang"}, - {"Half-banged Hair 2", "halfbang2"}, - {"Half-shaved", "halfshaved"}, - {"Hedgehog Hair", "hedgehog"}, - {"Hime Cut", "himecut"}, - {"Hime Cut 2", "himecut2"}, - {"Hime Cut (Short)", "shorthime"}, - {"Hime Updo", "himeup"}, - {"Hitop", "hitop"}, - {"Jade", "jade"}, - {"Jensen Hair", "jensen"}, - {"Joestar", "joestar"}, - {"Keanu Hair", "keanu"}, - {"Kusanagi Hair", "kusanagi"}, - {"Long Hair 1", "long"}, - {"Long Hair 2", "long2"}, - {"Long Hair 3", "long3"}, - {"Long Over Eye", "longovereye"}, - {"Long Bangs", "lbangs"}, - {"Long Emo", "longemo"}, - {"Long Fringe", "longfringe"}, - {"Long Side Part", "longsidepart"}, - {"Mega Eyebrows", "megaeyebrows"}, - {"Messy", "messy"}, - {"Modern", "modern"}, - {"Mohawk", "d"}, - {"Nitori", "nitori"}, - {"Mohawk (Reverse)", "reversemohawk"}, - {"Mohawk (Unshaven)", "unshaven_mohawk"}, - {"Mulder", "mulder"}, - {"Odango", "odango"}, - {"Ombre", "ombre"}, - {"One Shoulder", "oneshoulder"}, - {"Over Eye", "shortovereye"}, - {"Oxton", "oxton"}, - {"Parted", "parted"}, - {"Parted (Side)", "part"}, - {"Pigtails", "kagami"}, - {"Pigtails 2", "pigtails"}, - {"Pigtails 3", "pigtails2"}, - {"Pixie Cut", "pixie"}, - {"Pompadour", "pompadour"}, - {"Pompadour (Big)", "bigpompadour"}, - {"Ponytail", "ponytail"}, - {"Ponytail 2", "ponytail2"}, - {"Ponytail 3", "ponytail3"}, - {"Ponytail 4", "ponytail4"}, - {"Ponytail 5", "ponytail5"}, - {"Ponytail 6", "ponytail6"}, - {"Ponytail 7", "ponytail7"}, - {"Ponytail (High)", "highponytail"}, - {"Ponytail (Short)", "stail"}, - {"Ponytail (Long)", "longstraightponytail"}, - {"Ponytail (Country)", "country"}, - {"Ponytail (Fringe)", "fringetail"}, - {"Ponytail (Side)", "sidetail"}, - {"Ponytail (Side) 2", "sidetail2"}, - {"Ponytail (Side) 3", "sidetail3"}, - {"Ponytail (Side) 4", "sidetail4"}, - {"Ponytail (Spiky)", "spikyponytail"}, - {"Poofy", "poofy"}, - {"Quiff", "quiff"}, - {"Ronin", "ronin"}, - {"Shaved", "shaved"}, - {"Shaved Part", "shavedpart"}, - {"Short Bangs", "shortbangs"}, - {"Short Hair", "a"}, - {"Short Hair 2", "shorthair2"}, - {"Short Hair 3", "shorthair3"}, - {"Short Hair 4", "d"}, - {"Short Hair 5", "e"}, - {"Short Hair 6", "f"}, - {"Short Hair 7", "shorthairg"}, - {"Short Hair 80s", "80s"}, - {"Short Hair Rosa", "rosa"}, - {"Shoulder-length Hair", "b"}, - {"Sidecut", "sidecut"}, - {"Skinhead", "skinhead"}, - {"Slightly Long Hair", "protagonist"}, - {"Spiky", "spikey"}, - {"Spiky 2", "spiky"}, - {"Spiky 3", "spiky2"}, - {"Swept Back Hair", "swept"}, - {"Swept Back Hair 2", "swept2"}, - {"Thinning", "thinning"}, - {"Thinning (Front)", "thinningfront"}, - {"Thinning (Rear)", "thinningrear"}, - {"Topknot", "topknot"}, - {"Tress Shoulder", "tressshoulder"}, - {"Trimmed", "trimmed"}, - {"Trim Flat", "trimflat"}, - {"Twintails", "twintail"}, - {"Undercut", "undercut"}, - {"Undercut Left", "undercutleft"}, - {"Undercut Right", "undercutright"}, - {"Unkept", "unkept"}, - {"Updo", "updo"}, - {"Very Long Hair", "vlong"}, - {"Very Long Hair 2", "longest"}, - {"Very Long Over Eye", "longest2"}, - {"Very Short Over Eye", "veryshortovereyealternate"}, - {"Very Long with Fringe", "vlongfringe"}, - {"Volaju", "volaju"}, - {"Wisp", "wisp"}, - }; - - public static readonly Dictionary FacialHairStylesMap = new() - { - {"Beard (Abraham Lincoln)", "abe"}, - {"Beard (Broken Man)", "brokenman"}, - {"Beard (Chinstrap)", "chin"}, - {"Beard (Dwarf)", "dwarf"}, - {"Beard (Full)", "fullbeard"}, - {"Beard (Cropped Fullbeard)", "croppedfullbeard"}, - {"Beard (Goatee)", "gt"}, - {"Beard (Hipster)", "hip"}, - {"Beard (Jensen)", "jensen"}, - {"Beard (Neckbeard)", "neckbeard"}, - {"Beard (Very Long)", "wise"}, - {"Beard (Muttonmus)", "muttonmus"}, - {"Beard (Martial Artist)", "martialartist"}, - {"Beard (Chinless Beard)", "chinlessbeard"}, - {"Beard (Moonshiner)", "moonshiner"}, - {"Beard (Long)", "longbeard"}, - {"Beard (Volaju)", "volaju"}, - {"Beard (Three o Clock Shadow)", "3oclock"}, - {"Beard (Five o Clock Shadow)", "fiveoclock"}, - {"Beard (Five o Clock Moustache)", "5oclockmoustache"}, - {"Beard (Seven o Clock Shadow)", "7oclock"}, - {"Beard (Seven o Clock Moustache)", "7oclockmoustache"}, - {"Moustache", "moustache"}, - {"Moustache (Pencilstache)", "pencilstache"}, - {"Moustache (Smallstache)", "smallstache"}, - {"Moustache (Walrus)", "walrus"}, - {"Moustache (Fu Manchu)", "fumanchu"}, - {"Moustache (Hulk Hogan)", "hogan"}, - {"Moustache (Selleck)", "selleck"}, - {"Moustache (Square)", "chaplin"}, - {"Moustache (Van Dyke)", "vandyke"}, - {"Moustache (Watson)", "watson"}, - {"Sideburns (Elvis)", "elvis"}, - {"Sideburns (Mutton Chops)", "mutton"}, - {"Sideburns", "sideburn"}, - {"Shaved", "shaved"} - }; - - // These comparers put the default hair style (shaved/bald) at the very top. - // For in the hair style pickers. - - public static readonly IComparer> HairStyleComparer = - Comparer>.Create((a, b) => - { - var styleA = a.Key; - var styleB = b.Key; - if (styleA == DefaultHairStyle) - { - return -1; - } - - if (styleB == DefaultHairStyle) - { - return 1; - } - - return string.Compare(styleA, styleB, StringComparison.CurrentCulture); - }); - - public static readonly IComparer> FacialHairStyleComparer = - Comparer>.Create((a, b) => - { - var styleA = a.Key; - var styleB = b.Key; - - if (styleA == DefaultFacialHairStyle) - { - return -1; - } - - if (styleB == DefaultFacialHairStyle) - { - return 1; - } - - return string.Compare(styleA, styleB, StringComparison.CurrentCulture); - }); - - public static IReadOnlyList RealisticHairColors = new List + public static readonly IReadOnlyList RealisticHairColors = new List { Color.Yellow, Color.Black, @@ -280,5 +19,18 @@ namespace Content.Shared.Preferences.Appearance Color.Wheat, Color.Gray }; + + // These comparers put the default hair style (shaved/bald) at the very top. + // For in the hair style pickers. + + public static readonly IComparer SpriteAccessoryComparer = + Comparer.Create((a, b) => + { + var cmp = -a.Priority.CompareTo(b.Priority); + if (cmp != 0) + return cmp; + + return string.Compare(a.ID, b.ID, StringComparison.CurrentCulture); + }); } } diff --git a/Content.Shared/Preferences/Appearance/SpriteAccessoryCategories.cs b/Content.Shared/Preferences/Appearance/SpriteAccessoryCategories.cs new file mode 100644 index 0000000000..0609e54c9c --- /dev/null +++ b/Content.Shared/Preferences/Appearance/SpriteAccessoryCategories.cs @@ -0,0 +1,16 @@ +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.Preferences.Appearance +{ + [Flags] + [Serializable, NetSerializable] + public enum SpriteAccessoryCategories + { + None = 0, + HumanHair = 1 << 0, + HumanFacialHair = 1 << 1, + VoxHair = 1 << 2, + VoxFacialHair = 1 << 3 + } +} diff --git a/Content.Shared/Preferences/Appearance/SpriteAccessoryManager.cs b/Content.Shared/Preferences/Appearance/SpriteAccessoryManager.cs new file mode 100644 index 0000000000..7fe8d11465 --- /dev/null +++ b/Content.Shared/Preferences/Appearance/SpriteAccessoryManager.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Preferences.Appearance +{ + public sealed class SpriteAccessoryManager + { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + private readonly Dictionary> _index = new(); + + public void Initialize() + { + _prototypeManager.PrototypesReloaded += OnPrototypesReloaded; + + foreach (var category in Enum.GetValues()) + { + _index.Add(category, new List()); + } + + foreach (var prototype in _prototypeManager.EnumeratePrototypes()) + { + AddToIndexes(prototype); + } + } + + public IReadOnlyList AccessoriesForCategory(SpriteAccessoryCategories categories) + { + return _index[categories]; + } + + public bool IsValidAccessoryInCategory(string accessory, SpriteAccessoryCategories categories) + { + return _prototypeManager.TryIndex(accessory, out SpriteAccessoryPrototype? accessoryPrototype) + && (accessoryPrototype.Categories & categories) != 0; + } + + private void OnPrototypesReloaded(PrototypesReloadedEventArgs eventArgs) + { + if (!eventArgs.ByType.TryGetValue(typeof(SpriteAccessoryPrototype), out var set)) + return; + + foreach (var list in _index.Values) + { + list.RemoveAll(a => set.Modified.ContainsKey(a.ID)); + } + + foreach (var prototype in set.Modified.Values) + { + var accessoryPrototype = (SpriteAccessoryPrototype) prototype; + AddToIndexes(accessoryPrototype); + } + } + + private void AddToIndexes(SpriteAccessoryPrototype accessoryPrototype) + { + for (var i = 0; i < sizeof(SpriteAccessoryCategories) * 8; i++) + { + var flag = (SpriteAccessoryCategories) (1 << i); + if ((accessoryPrototype.Categories & flag) != 0) + _index[flag].Add(accessoryPrototype); + } + } + } +} diff --git a/Content.Shared/Preferences/Appearance/SpriteAccessoryPrototype.cs b/Content.Shared/Preferences/Appearance/SpriteAccessoryPrototype.cs new file mode 100644 index 0000000000..423a2f9306 --- /dev/null +++ b/Content.Shared/Preferences/Appearance/SpriteAccessoryPrototype.cs @@ -0,0 +1,33 @@ +using Robust.Shared.Localization; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Utility; + +namespace Content.Shared.Preferences.Appearance +{ + /// + /// Contains data for a single hair style + /// + [Prototype("spriteAccessory")] + public sealed class SpriteAccessoryPrototype : IPrototype, ISerializationHooks + { + [field: DataField("id", required: true)] + public string ID { get; } = default!; + + [field: DataField("categories", required: true)] + public SpriteAccessoryCategories Categories { get; } = default!; + + public string Name { get; private set; } = default!; + + [field: DataField("sprite", required: true)] + public SpriteSpecifier Sprite { get; } = default!; + + [field: DataField("priority")] public int Priority { get; } = 0; + + void ISerializationHooks.AfterDeserialization() + { + Name = Loc.GetString($"accessory-{ID}"); + } + } +} diff --git a/Content.Shared/Preferences/HumanoidCharacterAppearance.cs b/Content.Shared/Preferences/HumanoidCharacterAppearance.cs index 2f11b65b1e..2fdfc76d60 100644 --- a/Content.Shared/Preferences/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Preferences/HumanoidCharacterAppearance.cs @@ -1,6 +1,5 @@ #nullable enable using System; -using System.Linq; using Content.Shared.Preferences.Appearance; using Robust.Shared.IoC; using Robust.Shared.Maths; @@ -12,64 +11,64 @@ namespace Content.Shared.Preferences [Serializable, NetSerializable] public class HumanoidCharacterAppearance : ICharacterAppearance { - public HumanoidCharacterAppearance(string hairStyleName, + public HumanoidCharacterAppearance(string hairStyleId, Color hairColor, - string facialHairStyleName, + string facialHairStyleId, Color facialHairColor, Color eyeColor, Color skinColor) { - HairStyleName = hairStyleName; + HairStyleId = hairStyleId; HairColor = ClampColor(hairColor); - FacialHairStyleName = facialHairStyleName; + FacialHairStyleId = facialHairStyleId; FacialHairColor = ClampColor(facialHairColor); EyeColor = ClampColor(eyeColor); SkinColor = ClampColor(skinColor); } - public string HairStyleName { get; } + public string HairStyleId { get; } public Color HairColor { get; } - public string FacialHairStyleName { get; } + public string FacialHairStyleId { get; } public Color FacialHairColor { get; } public Color EyeColor { get; } public Color SkinColor { get; } public HumanoidCharacterAppearance WithHairStyleName(string newName) { - return new(newName, HairColor, FacialHairStyleName, FacialHairColor, EyeColor, SkinColor); + return new(newName, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor); } public HumanoidCharacterAppearance WithHairColor(Color newColor) { - return new(HairStyleName, newColor, FacialHairStyleName, FacialHairColor, EyeColor, SkinColor); + return new(HairStyleId, newColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor); } public HumanoidCharacterAppearance WithFacialHairStyleName(string newName) { - return new(HairStyleName, HairColor, newName, FacialHairColor, EyeColor, SkinColor); + return new(HairStyleId, HairColor, newName, FacialHairColor, EyeColor, SkinColor); } public HumanoidCharacterAppearance WithFacialHairColor(Color newColor) { - return new(HairStyleName, HairColor, FacialHairStyleName, newColor, EyeColor, SkinColor); + return new(HairStyleId, HairColor, FacialHairStyleId, newColor, EyeColor, SkinColor); } public HumanoidCharacterAppearance WithEyeColor(Color newColor) { - return new(HairStyleName, HairColor, FacialHairStyleName, FacialHairColor, newColor, SkinColor); + return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, newColor, SkinColor); } public HumanoidCharacterAppearance WithSkinColor(Color newColor) { - return new(HairStyleName, HairColor, FacialHairStyleName, FacialHairColor, EyeColor, newColor); + return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, newColor); } public static HumanoidCharacterAppearance Default() { return new( - "Bald", + HairStyles.DefaultHairStyle, Color.Black, - "Shaved", + HairStyles.DefaultFacialHairStyle, Color.Black, Color.Black, Color.FromHex("#C0967F") @@ -79,12 +78,15 @@ namespace Content.Shared.Preferences public static HumanoidCharacterAppearance Random(Sex sex) { var random = IoCManager.Resolve(); + var prototypes = IoCManager.Resolve(); + var hairStyles = prototypes.AccessoriesForCategory(SpriteAccessoryCategories.HumanHair); + var facialHairStyles = prototypes.AccessoriesForCategory(SpriteAccessoryCategories.HumanHair); - var newHairStyle = random.Pick(HairStyles.HairStylesMap.Keys.ToList()); + var newHairStyle = random.Pick(hairStyles).ID; var newFacialHairStyle = sex == Sex.Female ? HairStyles.DefaultFacialHairStyle - : random.Pick(HairStyles.FacialHairStylesMap.Keys.ToList()); + : random.Pick(facialHairStyles).ID; var newHairColor = random.Pick(HairStyles.RealisticHairColors); newHairColor = newHairColor @@ -108,24 +110,17 @@ namespace Content.Shared.Preferences public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance) { - string hairStyleName; - if (!HairStyles.HairStylesMap.ContainsKey(appearance.HairStyleName)) + var mgr = IoCManager.Resolve(); + var hairStyleId = appearance.HairStyleId; + if (!mgr.IsValidAccessoryInCategory(hairStyleId, SpriteAccessoryCategories.HumanHair)) { - hairStyleName = HairStyles.DefaultHairStyle; - } - else - { - hairStyleName = appearance.HairStyleName; + hairStyleId = HairStyles.DefaultHairStyle; } - string facialHairStyleName; - if (!HairStyles.FacialHairStylesMap.ContainsKey(appearance.FacialHairStyleName)) + var facialHairStyleId = appearance.HairStyleId; + if (!mgr.IsValidAccessoryInCategory(hairStyleId, SpriteAccessoryCategories.HumanFacialHair)) { - facialHairStyleName = HairStyles.DefaultFacialHairStyle; - } - else - { - facialHairStyleName = appearance.FacialHairStyleName; + facialHairStyleId = HairStyles.DefaultFacialHairStyle; } var hairColor = ClampColor(appearance.HairColor); @@ -134,9 +129,9 @@ namespace Content.Shared.Preferences var skinColor = ClampColor(appearance.SkinColor); return new HumanoidCharacterAppearance( - hairStyleName, + hairStyleId, hairColor, - facialHairStyleName, + facialHairStyleId, facialHairColor, eyeColor, skinColor); @@ -145,9 +140,9 @@ namespace Content.Shared.Preferences public bool MemberwiseEquals(ICharacterAppearance maybeOther) { if (maybeOther is not HumanoidCharacterAppearance other) return false; - if (HairStyleName != other.HairStyleName) return false; + if (HairStyleId != other.HairStyleId) return false; if (!HairColor.Equals(other.HairColor)) return false; - if (FacialHairStyleName != other.FacialHairStyleName) return false; + if (FacialHairStyleId != other.FacialHairStyleId) return false; if (!FacialHairColor.Equals(other.FacialHairColor)) return false; if (!EyeColor.Equals(other.EyeColor)) return false; if (!SkinColor.Equals(other.SkinColor)) return false; diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index 1ef4488ce4..6f5832f349 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -21,11 +21,12 @@ namespace Content.Shared.Preferences [Serializable, NetSerializable] public class HumanoidCharacterProfile : ICharacterProfile { + public const int MinimumAge = 18; + public const int MaximumAge = 120; + public const int MaxNameLength = 32; + private readonly Dictionary _jobPriorities; private readonly List _antagPreferences; - public static int MinimumAge = 18; - public static int MaximumAge = 120; - public static int MaxNameLength = 32; private HumanoidCharacterProfile( string name, @@ -85,7 +86,20 @@ namespace Content.Shared.Preferences public static HumanoidCharacterProfile Default() { - return Random(); + return new( + "John Doe", + MinimumAge, + Sex.Male, + Gender.Male, + HumanoidCharacterAppearance.Default(), + ClothingPreference.Jumpsuit, + BackpackPreference.Backpack, + new Dictionary + { + {SharedGameTicker.OverflowJob, JobPriority.High} + }, + PreferenceUnavailableMode.SpawnAsOverflow, + new List()); } public static HumanoidCharacterProfile Random() diff --git a/Content.Shared/SharedContentIoC.cs b/Content.Shared/SharedContentIoC.cs new file mode 100644 index 0000000000..db275a8789 --- /dev/null +++ b/Content.Shared/SharedContentIoC.cs @@ -0,0 +1,13 @@ +using Content.Shared.Preferences.Appearance; +using Robust.Shared.IoC; + +namespace Content.Shared +{ + public static class SharedContentIoC + { + public static void Register() + { + IoCManager.Register(); + } + } +} diff --git a/Content.Tests/ContentUnitTest.cs b/Content.Tests/ContentUnitTest.cs index cc06d7a6bb..0287cfd9bd 100644 --- a/Content.Tests/ContentUnitTest.cs +++ b/Content.Tests/ContentUnitTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Reflection; using Content.Client; using Content.Server; +using Content.Shared; using Robust.UnitTesting; namespace Content.Tests @@ -12,6 +13,8 @@ namespace Content.Tests { base.OverrideIoC(); + SharedContentIoC.Register(); + if (Project == UnitTestProject.Server) { ServerContentIoC.Register(); diff --git a/Resources/Audio/Voice/Vox/shriek1.ogg b/Resources/Audio/Voice/Vox/shriek1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..ae746cd0654714bf471a5561ad6d7e0aaca3b517 GIT binary patch literal 14929 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 XmNklmZ0Zoi)+R&{1ZRto1s9U+%*3oL z|6i3N?}NviG!qd30000006aTv`>M;hp8{W$Zmz?&uL57}>j%Clm5GW%Pb*mzdP-$t z-9#7ldrdFIi7TVQL#Mus1`ml7S1abP>Q@dR@I}oQ#q;UfIHxD&`?E!nM=SVE>VL1F z%{RdI7_3)A?e#B3p{LfXq1_SK>^$x1mrmE7Y<8YeZ0UYE%Ve56Cb5%g?%XeDtNH){ z000000001JJSZaZ0 h2E3{s006+h_XW$Kw~dZe6Egq+002ovPDHLkV1hjUu0sF- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json b/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json index 88e3ebd509..008405ab29 100644 --- a/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json +++ b/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json @@ -1,26 +1 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-HAND", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} +{"version": 1, "license": "CC-BY-SA-3.0", "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", "size": {"x": 32, "y": 32}, "states": [{"name": "icon"}, {"name": "equipped-HAND", "directions": 4}, {"name": "inhand-left", "directions": 4}, {"name": "inhand-right", "directions": 4}, {"name": "equipped-HAND-vox", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Mask/breath.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/breath.rsi/equipped-MASK-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..bc38757ea3c89344153c06679a6f8126b97e9c2f GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEV660XaSW-L^Y*5Fev^X)+lT4P znvJy!-#vNfk@KY~`Lh0{60>8iQ`gR4RCw4eNAvM+<5H7TuM(Ut&A!Ly=EN(@_viAm z^ZATL1@G@Z-SJeBiGiWPiYaa97m0JHf>+HbIG}UdX8I?kDYyM&_xn{(&7M4c>$NAE zs?8@`+WMSbw(K_YHj$fr?beokf@@8G?$hr+`smw+wfEoe-|IH9aK0P2fO_ZE;=89p zuSEsVQJMCUgXgvI#69YsH8;{a=j^F_SZFe-A<`~P`)B!chnsbR-_Ae%z5mb)af>VW z@;YUf&-mfHyLO%~2hgu@AYLZn&wi$N)8SR``(+QBcOC2Kn74R^#D&T4Coi9}=gjl4 z13J#f7f#C+HazXTJzHcp>zShKFE2b#3$A&usT%b<-}F6u^L^3dUt_j=^i8jfvvyqf z>hbc7eVwb5%O%u1xAHm9N|p4zT(X@xE9<72@8v0Jk#4UIY~ugb`;?wDq z_Qu)Q=5N2f^iO5a$MF6`2J%0C&3O8Fr<)y;lLh}~UoQG`>C>0^^zf_aiymH-2+k@{ zYzeG?JL}E{KZ~<`iVO_%&Ofipz7VCpwshwNg%*jg@dquZZ@Kn#lFK{&l|JY7`qO{b zIehD~X1qT$&HuWY`&aH0TYm^J@%_#Px&(@8`@RCt{2n!ir#FcikWAf)UJWFSK)q$&zx?&67|Z@??WqGI6zn0WwqW9}Pt zU}=TKQZZTShPp&ZnHUOEktn`HuXEirrLmiod%6BCZQ{hAeSCcUFM!2ju~;k?i^cL^ z;^@9WDHV*dmG{=&uNq3J0D!Zzv+Um8-5mhHM8EV4QaB7laL$*+D5XN)H!X;cK7dTC z=$?-Lep&H$yS;LcG3Ln1`@Rp~_hoXW-cY3P`#zE+Q8kV9_jJUQB*}!rFoarpHND+# zXDzlZMf&S7(cfqQHS@`2l3n}0k2Fn}T3|AnY%HWHNs@qbj+d90m9)LRMK#hi)z&X% zfOVOAo~QM^DQbRiZ*SRuY5dR6&!uN{^f$(UIF1p=F#upV96GPBuPgl#0PgSaadUIy z5JD<({dM}%wN=lP-oY5t*57D=;c&PTO!C1;wRq9<+n}4D?(?Nafg)t3>+17m^|z&T z5Cni$t0mGj1?L>|`5c#*mzdAz;GE;>=?Se?t5WyR69j<(fL^Z$&iT@>ny!PE2b`Xs zX8*_IF~;L@cI|l{JkP_!!-H-aN<#=i7>3!z=jiAN2L}h)_2J=R7B9+D+5kn9k$f!p zO)XPmN~vfzoA~(nK%>zBuo!kvPENA2c%G*{B{zxzvj3^m(E>x%M!(-*`QL0dvA?fh z9jzDu{26jaqY)Tm&S*3O=X@u@u+eCs)9E+>Fq_T57;|Q`833Tu={P2hplyJkhOq%| zZ*Lv-cNaW9K7OgMrk6#_0MF0Q*}S`my1T*k^|b@6E_da%Os@?>h*&q({3^|2u~;k? zi^XEGSS&w>wb$jP)ddCx>-5oX|--X zS{BQ1jmr&E*LCs!{tlp?k0bJB0FY^_$Me8qm$>$A@jS=J#{jae@!CF>kquC^EpLjp z0pwwb+>b9hDXtsY;<6l^bEt;V!Dv@l3dsQUoyannZpdnTz*laUBuT9?fHCHTVJM0Y zKuo)XmIuhnF~*#tiu%4^>xe)pEv&p+9^D4e?gDuM)%DafySh*{@^1ev^N}D3L=Xgm z5F!SHfvDR927`ehgb1m-ZJt{XgBKSUSyY}*r`u+?k?C}btE(#j3lE5*Xsi4xI~?uz z`#U)yPLib3u4Zh2pRyP-GJv`W`5Q1@2LOhPApnS?$mw>w0@zLT&m%Rv-L8nD$WhCt zgYmGTejy&mG0xA=cd|5=y1iZxK@b#vy}mP4ixWa>9RgKN^%(wdibWQS<=^8M`Fc8v TGX?q)00000NkvXXu0mjfDL)0p literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/Color/grey.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/Color/grey.rsi/meta.json index a0e86f87fd..7bc8075e52 100644 --- a/Resources/Textures/Clothing/Uniforms/Jumpsuit/Color/grey.rsi/meta.json +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/Color/grey.rsi/meta.json @@ -1,26 +1 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-INNERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} +{"version": 1, "license": "CC-BY-SA-3.0", "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039", "size": {"x": 32, "y": 32}, "states": [{"name": "icon"}, {"name": "equipped-INNERCLOTHING", "directions": 4}, {"name": "inhand-left", "directions": 4}, {"name": "inhand-right", "directions": 4}, {"name": "equipped-INNERCLOTHING-vox", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/eyes.rsi/meta.json b/Resources/Textures/Mobs/Customization/eyes.rsi/meta.json index 4c492624ed..f509e81f54 100644 --- a/Resources/Textures/Mobs/Customization/eyes.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/eyes.rsi/meta.json @@ -1 +1 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "states": [{"name": "eyes", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file +{"version": 1, "size": {"x": 32, "y": 32}, "states": [{"name": "eyes", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_eyes_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/eyes.rsi/vox_eyes_s.png b/Resources/Textures/Mobs/Customization/eyes.rsi/vox_eyes_s.png new file mode 100644 index 0000000000000000000000000000000000000000..807e9374c4577407cfb371bf954ac9c304df0d5b GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|%spKkLn`LH zy>*ZisEWn#cYf8|2M+}7C;eI0zLJTdPUYlkMxZhvX!vbb$H>nFW*b~B+{gd1>Ib_8 Oi0kR<=d#Wzp$P!*izAKz literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/meta.json new file mode 100644 index 0000000000..9731760062 --- /dev/null +++ b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/vgstation-coders/vgstation13/blob/02ff588d59b3c560c685d9ca75e882d32a72d8cb/icons/mob/human_face.dmi", "states": [{"name": "vox_beard_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_colonel_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_fu_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_neck_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_ruff_beard_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_ruff_beard_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_beard_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_beard_s.png new file mode 100644 index 0000000000000000000000000000000000000000..8e922e58dea46603f309e325679cf21d0b244dbd GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0L3?#3!&-4XSJOMr-u0UEvnlZ?pJtIi?hU<(X zAfK@$$S;_|;n|HeAji?u#WBR8vOdO4iYz`89D)yBY*0IJ!howyKY=SD zA;Goplca(ZucrgQ%Nqxw2P}e|C)zA}mI-ZQWT;=ks`Eg6=USj)44$rjF6*2UngEV3 BD}(?5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_colonel_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_colonel_s.png new file mode 100644 index 0000000000000000000000000000000000000000..8de4dd68030cd898e7075ce35ef4e821d6541d44 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0L3?#3!&-4XSoB=)|u0UEvnlZ?pT{1u`9LQlT z3GxeOaCmkj4al+fba4!^IGvmzal|2sX;uR>_sKMaMcf94Jxz(s64DKVuNqVs{1lix rn3xIzH3Ap}WjvT<3N8jZ7%?y?KV{NhI5}1wXbgj=tDnm{r-UW|@^K$q5pyS6G>temtEiI)zh%!D&weC&x!7Hw78i z#R(!jJPpt7Vq6=Adloi1H!_B(E3aGRz__fT)4}kFMU+Sn(=A4ZCkq&xS556t0h-C+ M>FVdQ&MBb@0Cn{*Jpcdz literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_neck_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_neck_s.png new file mode 100644 index 0000000000000000000000000000000000000000..9009717cee3adf97989004bd8d8cc7bf3f583f08 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e{s5m4S0Jq-%@}0Qo)IM6RiN^s z<#Gp5h_NKdFPOpM*^M+HC(_f!F+@W0?ZJbb4F&?P2fuG^R1FiD#AITo@N&O~V-r`G zIxD|*bM@66gPu1`7bM&579DYHuvjf7HgAQGjqtgh^`|aoh-ihcYE?^p?AB$nu;BQa e8y<&t_OCJJXVKs2x6T%534^DrpUXO@geCxGqC5@& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s.png new file mode 100644 index 0000000000000000000000000000000000000000..365f134c44f99b419312333cfe4adc530c86c56b GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e=>VS)S0Jq-&1fUX5MIIKME-6!S9|qT^y0Lhlwi})&qrLYzyD<@ad!Qb;&myF>-_g#)Cp*3 z?%v|CIqI(_Yq?R7R?Lo#g>5Zcu1N}MRqR&}toolgV}*Zqwoqi8?e7CeZhl^=yFVdQ I&MBb@04q0iZU6uP literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s2.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_hair.rsi/meta.json new file mode 100644 index 0000000000..15010b1149 --- /dev/null +++ b/Resources/Textures/Mobs/Customization/vox_hair.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/vgstation-coders/vgstation13/blob/02ff588d59b3c560c685d9ca75e882d32a72d8cb/icons/mob/human_face.dmi", "states": [{"name": "vox_afro_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_afro_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_bald_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_cropped_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_cropped_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_horns_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_horns_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_kingly_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_kingly_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_mange_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_mange_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_mohawk_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_mohawk_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_nights_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_nights_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_pony_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_pony_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_rows_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_rows_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_ruff_hawk_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_ruff_hawk_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_shortquills_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_shortquills_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_surf_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_surf_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_yasu_s", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_yasu_s2", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s.png new file mode 100644 index 0000000000000000000000000000000000000000..60b9b18c21ed83a8297754df9f4319909ca98ce2 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e{s5m4S0Ei^&z=z^T$Ui$RiKhR zKW8aWh_NKdFPOpM*^M+H=cK2LV~EG`w^IW7niY5)UO!;CRmH$9zTgP+f{*{wXWi_{ zHvC*2S;48ofA+V5ScCYz>I+xm#H74_zI(vYnRllRdL~s*022UX8e&mXSr5W z^|uY@qO!CiGXa&=p0AWxXHV$ZQ(NMEE`>>@@Cv)PnrG<387Fs%?2vLjv`RqD`0ZWg s39@0U@|yj+_G+9i-FN%`zopr0FotlqW}N^ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_bald_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_bald_s.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s.png new file mode 100644 index 0000000000000000000000000000000000000000..67574355ee4a44f2cefebdffd0a36f6b2740e664 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e(Ey(iS0Jq-%@}0Qo)IKmmLOM= zV&7GuGUec%uRsaLk|4ie28U-i(tw=#o-U3d5|VEZZsa{=AmDIO|8@nFOYXx9(Q3?d z-mnS?M{M}d7ob|sDrow|cAx4*-^Yd*R5;x%WR<(JbrZ8PP7xJgMiq&eVp3- z6=8dy*SJdV;T2Q-ZpS(Q>#bW;c@x)tJ~QoKP1gp+V<+;yzfR)OFk%Zk`SsYN39FA6 zYgr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s.png new file mode 100644 index 0000000000000000000000000000000000000000..dbb4ae8f28e1001efad21da703a81a34acae7330 GIT binary patch literal 236 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|ep#Yx{S0Jq-%@}0Qo)IKmmLS(v zpkgF1UJMjvED7=pW^j0RBMr#u@N{tu@i_i=vLhdpB9E)Q?A^m>SiN>MOxj^S?|{qu zdNFY|wyqsBm)3Gl2(R1qo53Yx-bG8Z@8<677`CrGENpS-x!=X_KP#@?vC4MMnq%## zxIJ#m7Q0OwkIZLuESO`j-cl&G``MI~|G{r(ml$?_xlk9-<83M(ZY*)CcAK=B@P**_ f-P>;$mVIEFJBd>+PQ&dk&`k`Uu6{1-oD!MYgr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s.png new file mode 100644 index 0000000000000000000000000000000000000000..3f35429e14fb9eabc4f12e3e76a0a023067bd45f GIT binary patch literal 309 zcmV-50m}Y~P)qiyE*l&czLmVZWq_8LWl&s2 zs^UYsdfd{B^PG4|%3%iJCdG+PJn0qyylz1vq!{k8p3Kaw$Mk0)YL;2VBsBoq5k#iL zTHgB);d|`b^;3oB?8eZpc7qykAkg?Y(hIp9shI*-iOSP7jLg}796z%DdWclcwneSx zgv+`04&9|YhY-mYaO}n$?WJ5TeN<#l1YU<}gW4b0uK(2?r8yORYgr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s.png new file mode 100644 index 0000000000000000000000000000000000000000..138c58e690aed7b3368ba707eab34d6f022cfde6 GIT binary patch literal 296 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e-2k5uS0Ei|#}Q=D9_3|QmLOM= zV&7GuGP%wcBA5{*TpBMA6o&|&_?htssDYy-$S;`T4+OLy43!6pE%J1643Ut0dvGr& zlc7YzL-CLA?RJ)YGc#}68_EWvEvZbYn{grgr?FA=LEm8i#A(pRi)Ji{7HL@;uDW?t1fhcFtVjJGWFLH={p8S^k@b_w6+ok}gm97^l(o bs9Su^La9RSYgr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s.png new file mode 100644 index 0000000000000000000000000000000000000000..0a5589b0baec8ef0bf45097fb1e5dcdccf6e9bc8 GIT binary patch literal 237 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|ep#Yx{S0Jq-%@}0Qo)IKmmLS(v zpkgF1UJMjvED7=pW^j0RBMr#u^mK6yk&t|Q(2%d$K*06jbN%Jp1-^8s?xobM+V&SUkjD1LTp&Q7!Rb)CyH1&%pN zh<1lrxQISnd${QNhnM$-`=)JuZC19ua8A|ZH`a|pyAw9-vj}En+Rftf*r(OYL}sy) h&0?il&+`8={CmtLa(vh4N}!_{JYD@<);T3K0RXhaR>}YX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s.png new file mode 100644 index 0000000000000000000000000000000000000000..0a587eafceb8c9180e6e6d31fedd4cf28e47471b GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|ep#Yx{S0Jq-%@}0Qo)IKmmLS(v zpkgF1UJMjvED7=pW^j0RBMr!zHZzrXvE z;os4{P>o~X-NqwZ?mNG`ZfB)mn{fOpAKU)VEUOmq2P_Ocdj{xE22WQ%mvv4FO#sGV BVdww= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s.png new file mode 100644 index 0000000000000000000000000000000000000000..a9ff211389f32a0a183c7b8e263eb84a6217bc4b GIT binary patch literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!j01c^T!D01f?SY2dwhI6kkM73 zq9V-*=QcDn07WL(*{aGg1=?|x#>;o+t3K=M(FAJaEeY}qW;pp92>w98lm7TDpu~Gm z7srr@!*4@l`I{AZTv)TN8~ypezl`{M z;Y{b|bH!^^Hyu+~QSgy^zhR}WQL_X?x@lr?^d0@?-Dv`|Zz&nR-9FbMlkLhCG4|7P z?oS>+51y8{pu_k(3uEG|MT!@vGyAU3s+~Fg)@AUJh%Y9r8Z!LZl zU$QTH>HcT2Zj4?nPpe)&v-~Y4xj1=E)AT=ccgyTcsGKa#!`A$8{|5%y)vULB)Xk0o Pz0Tn2>gTe~DWM4fhYg{v literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s.png new file mode 100644 index 0000000000000000000000000000000000000000..cee8b9a103008f6260c30a6ef29bf30f522691ae GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|ep#Yx{S0Ei^&z=z^T$Ui$RiHAt z&USwHCm*0FV@Z%-FoVOh8)-mJy{C&~h=k7%!pDj~Yx&ps WG5_Q|!J!9q3WKMspUXO@geCymaaDu> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s.png new file mode 100644 index 0000000000000000000000000000000000000000..41c3cb6decc1a40fac2318c2b4d486769604b072 GIT binary patch literal 402 zcmV;D0d4+?P)L;&MWS9>5&HqJ=J91bXe35~nlP<^;aSKnMvJ zB0>=t4toNPB{a_nOfy1jLttwO38BI;t}u)d3M2fAV<3+C)gSs3o((WDoXK5PRU5&1 z=oLKlinG4^w#P}HUx+tL&ZNxCynMt_#X;R4jpAQPUDr!SsG{8(#fW6RW|WFi+}t>V z#t}3ZbgC^*Dpm-!^X3WXFnh}hNYhTIdj@xlMLyH`-gA(QL8PI5#U~bs7-T@I@l7ok z(gnU`c_J_=3?8XgwZW4dcb&$w?79zwlYCZHfhS7yRd>Xxt6gg|0%=(p21&QI{LyTW w4C->m6|+sokEn0BMl6F=b5+D3Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s.png new file mode 100644 index 0000000000000000000000000000000000000000..c83ef673a5451e518e9f223c2167862216fd8316 GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0J3?w7mbKU|e{s5m4S0J6}FIkl=Uze`XRiM%< z{jv-w#8?vK7tG-B>_!@pGt<+>F+@W0?ZJbEhZO`IF7hvAI1+GRlQW|xdl=#GF4SYwf!;xt;gjl3T6Op%pg!=KM~Wd?#{8R(kTPbE-#6(##g}N%}1RgTe~DWM4fJwIV> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s.png new file mode 100644 index 0000000000000000000000000000000000000000..df2191cacd2ec1db6393fa414993ee7005ff65e2 GIT binary patch literal 377 zcmV-<0fzpGP)WWfPji{Bp)#~cK`qY0d!JMQvg8b*k%9#0TM|>K~xwS?ZGi?gfJKe z;P)evIo~DCejId;)jAs#_d?q_K`;ORClu_RNe}AKvG_b#k)Ys^2{;H8daY-rki{4S z3eQi zu#!#p61i0<(7^UGHvucj=QNrgh02fV!~v_wklgkT1yKzgz!rCj@qiP42zVfIIQ&;% XHq0oar8OXH00000NkvXXu0mjfu>6)e literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s.png new file mode 100644 index 0000000000000000000000000000000000000000..6461305e85e744b44ee1c304fbc8308c583d5748 GIT binary patch literal 356 zcmV-q0h|7bP)3Du(%1827%DE2mQ@$}Da9{U2IkXg5_o} literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s2.png new file mode 100644 index 0000000000000000000000000000000000000000..0858c19f0521b74f4a058fbddc280ea48a5751bb GIT binary patch literal 96 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=>Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_f.png new file mode 100644 index 0000000000000000000000000000000000000000..15c0ed8d66f08c6af2988432a3b0ed3b8628feb3 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU}W`laSW-L^Y)f~_8|v};~$s* z;CIY;=q22;XF-qVjwu#tr)Nxm_~P2tyBqaaDDZ}C5SaSweWAuhG2N%W*Zb#OUvs^m*SeBamE>pZWmoRIaWyygreB9}{PFePnP%F%Z`JG*D~_Ig z@NxIo|1m8SFNS5;m$`17wEW=>&D)g+=da(L{X_Ggl|00HAbH?_QBkm=U(Mc~>pbV_ zANl<1(tF$aTLWjNHBO71y#47>t4sEJuY~%Qy%JOSW*Zb#OUvs^m*SeBamE>pZWmoRIaWyygreB9}{PFePnP%F%Z`JG*D~_Ig z@NxIo|1m8SFNS5;m$`17wEW=>&D)g+=da(L{X_Ggl|00HAbH?_QBkm=U(Mc~>pbV_ zANl<1(tF$aTLWjNHBO71y#47>t4sEJuY~%Qy%JOSBjE6bJCXgk>2cu!{o%J42}!;d}-gy47UzkTH-CkvU^NN1$T^o{GB_+#yTI=*>+D zj)_33Z4kk>jMYK8tJKp_cRCrL07Cw2n#@V9b|wC?t=kEtuJyO$ z3!l_#S7OV`!M5}8yahjo;c_QMVDZg@hWRY!N7?wgOmLPo0A2*k%B>xl=afz!0Bk!C z05A)hbbO%#u%Ik?$8-UFFTyUcIOURo$uvT_WMtY!2^ZkjI7RPb$dh+W7rl!iZjDo^ z4v0!8ojy*ck<|5s3s4-Mqj|Cq0H{@00D$JnK8nM0sSb#m&*GnwolGOlXL5I+Z~@GM z2FG-H^0n#;j_LCIa@)*;mKkw2BV^+X6`*W8dYhY~lclJG?+X=KVT=FTe@(2VZzX$=zBk9GwzSHChA%qY@ z2qA9J5Djvmfoj( zu0pWH*|u2PVDP9^1f`7;$0=^yl`WSHc-}&}2uH_uY}@%?#!)Fk?)M-0bAcbN{aZyC zF8Oq4DtpF;Pm2@Y8%$%P68I4UKZ0fDpu1BjE6bJCXgk>2cu!{o%J42}!;d}-gy47UzkTH-CkvU^NN1$T^o{GB_+#yTI=*>+D zj)_33Z4kk>jMYK8tJKp_cRCrL07Cw2n#@V9b|wC?t=kEtuJyO$ z3!l_#S7OV`!M5}8yahjo;c_QMVDZg@hWRY!N7?wgOmLPo0A2*k%B>xl=afz!0Bk!C z05A)hbbO%#u%Ik?$8-UFFTyUcIOURo$uvT_WMtY!2^ZkjI7RPb$dh+W7rl!iZjDo^ z4v0!8ojy*ck<|5s3s4-Mqj|Cq0H{@00D$JnK8nM0sSb#m&*GnwolGOlXL5I+Z~@GM z2FG-H^0n#;j_LCIa@)*;mKkw2BV^+X6`*W8dYhY~lclJG?+X=KVT=FTe@(2VZzX$=zBk9GwzSHChA%qY@ z2qA9J5Djvmfoj( zu0pWH*|u2PVDP9^1f`7;$0=^yl`WSHc-}&}2uH_uY}@%?#!)Fk?)M-0bAcbN{aZyC zF8Oq4DtpF;Pm2@Y8%$%P68I4UKZ0fDpu16WIYBS3-CDVtf5yeLb`GC8{P^@*?*tgRytuI7iHz4l$0Kq79EdqNpMnwy2pL4XY+HFpZPV0}1c8#H-ZONSR+n}tyzn~4l(C@ULrCYef*E@Z zRplo8x+{Iw{>ao&%b9!e#N>N(`4@be=rQe-yF^>KQsjNhiF|7|F&eFAI8n=HwD^L4 z8-rQWO!i0G3X#j^Ze3|GH{#6W!nI=0KHl(C7t0P-j9m8U_kKhE?;BslJ6QF1z`=^6 zujV*!doJ*vJ*xejYDJ*K$8Yaqn#5VBSic5QUw*wi-u7tu;rfMl-p2o$xwq|&92`pG=EX{;?}fZmNC~JmxgBf?VNtW sWwrM8^?aB46*Tv^sIq^2H|Mud{QJ!ow-v1}9tRoV>FVdQ&MBb@09$}zu>b%7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_hand.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_hand.png new file mode 100644 index 0000000000000000000000000000000000000000..0d1048e090b6e59e3c03f2d8182feba8b8dd5348 GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEV3hE5aSW-L^Y)fu-XRBp)`uHC zP?JUbN8`yKrzRv7^U(Be$IRc#PU`w@S3XjP(qGt){>4zYxZh;|Cyh1 zvv+=)`{lD;Ktn-5;!s&|_G7KLlP~V@+CF<%__6p;5({5X4bHZTJY&q6>-1PF_Kfky zWs|?2a?N&{!uIA~%{4jKH7}ctzx`9VR&q%$zmj>{_ruO>9`v8T{rQW;yp7eOnf`Sf zW=)!PPVLvp4-87PXap*?%7JX87BATe7A;+!FWf zQ|Za(cS(iOZCLa2$)9zbzPD$5=lG}kl*K1qSeJYG;#+FVb<);+=Liy8yuarD f)ZMlg3=8_TFEja1ocmGaH^>rCS3j3^P6AX`kImDu#2nSax{^jMk8ICiPZaxLnF=9)KlgsGdtbf%51)b(49p6)-W|De_p+6{ANVfb%J|jI z@mQhvfgj&CZ`ZvtXU?@>oU*Q2etx&UG5tz+mVNq9WAZizp1|UwPe(udxAo0B#o3X! z=eqQtI|(&4|Ap4a)wSj7XZ)7aFjtuB_2AJX>$HgtHUGpI96AJ6PMP*$mHC4Y2h4vh zYAV{);&bcJrv;0W%~6Q?_bfGp3yJn z^D4TmNRBsNoN6Q@YxnNqizQWy6~2E9pCYszDw2_sZmxa(+N7vib&G`s*8cwC8E1EA z-+zD43zr%q)f0+hMNjc&m@+H>Fq%`zRP+Cn*X8MAs*6N&a>JJUHE;X)#t_99sBvyoI@}vbXp>7dEgdb9bGS=%BQ7jS5C=0K6eaFVi3s{j^8cKV6{qh zxsa*VM%|~!c6IXa73|u^d0jeobzc!vOn%Le%j=E=?iT+2*54|tyyx;dmy2c>>x{eJ f{%2YA{|bNMgCi!K={L3lQwxKqtDnm{r-UW|U+N2{ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json new file mode 100644 index 0000000000..1ed5e8a33c --- /dev/null +++ b/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb", "states": [{"name": "groin_f", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "groin_m", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "head_f", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "head_m", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "l_arm", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "l_foot", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "l_hand", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "l_leg", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "overlay_husk", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "r_arm", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "r_foot", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "r_hand", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "r_leg", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "torso_f", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "torso_m", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "vox_m", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/overlay_husk.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/overlay_husk.png new file mode 100644 index 0000000000000000000000000000000000000000..79082542b887abfe5e9b90b11aa5dbc1d7c0d3e4 GIT binary patch literal 542 zcmV+(0^$9MP)0)C$c&sUh9nV!RArVulA)2U#gX*-|?|41LXe z`5%{%+$9GHf*`n%NsBW{)@Q1$eWtW~OVHYF^I-yk}kuF~P=Z zQIp*<+j+bo2tsI3CPl#|V75V7;Wtt<{Rig+gYPI!?k5C65ClfX_Fu|CsPBK-Cb^*W z{DNBZDn$XlgUW?Yr{-Oc+cm>=8Id?5D|A;PYwDI}IKtflAsvaa+G1adQttv>7qaa2 z0SnsTULU}8Kd+S1&C~0tR39L%QMiUHN0+k!Auv`N2`&TUE|kkmjD0&07*qoM6N<$f@4Mf_y7O^ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_arm.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_arm.png new file mode 100644 index 0000000000000000000000000000000000000000..0c1f703efdfb13c67b3bca21caa9bb6cd41ba72a GIT binary patch literal 391 zcmV;20eJq2P))C##!a|C2&)kO~z#v?w_z z!Kul`m^ShInUC;$@9wzaMFao<007nqLQiixLy{o$v}sN|?S~zwmMv9*9H%C}?;34Z zVgtU5cXv|tYNPH(ua;6Pqb8)Pstm&V&uaS>T^({>NVo^?{KO|`X=vL%kn z(S*jlEs;upV%M%5c6)lz*D_VHjK&k|*Xar{8c(dLie=E(GVJ#9dAY7Gx?BGQ{#3TS z0000000000U`qv|r*Cc#Dl>R68v6#Jr+wd*`TK`lUhh?+37O~K^+qX1g^7$BV9z?T zJ3o@uQp;*ti34DM0$R;j{Q8M37N38Sr*N6BK&u(cUPu|}_Nd+PODENpjzue5xg-|e%;>1Sr{W8ScA>bLf& zNn%@TUrv5r=6_{NP~;I_Mwm$q3?I(!PVla%)$LBW*L(ir?|O&uc}r(4`WbMK_4H=P oi^pI4{3{iHCUa!>^APR|20j*>+sjHEQb5{0UHx3vIVCg!0Kw*8-~a#s literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_hand.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_hand.png new file mode 100644 index 0000000000000000000000000000000000000000..d794c608bdafba81341f53d123f98b8e720e4c6d GIT binary patch literal 354 zcmV-o0iFJdP)9J)&saSjc|ZYWi%n_2YVUZJ89B0m`+~8J21PH1C)WKlbt%bRA;>auY)l$ zCeVODq5gjhB#@8idjivo2mk;80001hZ=vyZwG8ysIjUGK0}YLTH2Wa$LTG%QPAqZk zOcry~s}dG-qmG@)bYjV|5^@U=5pnEH(yd4oCsw@?n-#^0m2SWCuaiyTy%&WGJ=Gbj zT~VCK%fVD%U^E`;&tu>GIe%X_{@c0i0{{R3000000N{V|-1?`~h120Yj}JyYcXk#d zr_u$4#@E-kf!yDI$lc9VYbAKD(e%0gF@5O**2%`&?Ntu%mvv_;6kJz&S(`B$57l#L z+UDf7iSNI%Q~W#7r7^eWoVWShPUu`9007GQ1jpe|(V>2=LI3~&07*qoM6N<$f&tQ; Aq5uE@ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_leg.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_leg.png new file mode 100644 index 0000000000000000000000000000000000000000..37417e28157c046d126fc7722ed3e20a533a73e2 GIT binary patch literal 591 zcmV-V0JZQ4&q7ES+##npRnq?rYLrAk_icoQhVvGIv2Vt+L4GR1^!E^jfI^iUkdW z!303K^Ol5qqa<{F39ny%hBul@ua^qI8%?3>OSr!Nj(k2N{jenD^BFkK7yy#(fR%}f zVnIVKTZQMCINTp9(oajk;r>wZ923u(Q-IC6IQM^Z@WQW?h=_=Yh=_=Yh=^$6wb~W&uj?@8W4;xTg6|UQ2<&WciF?Mo zSl>iYw>!YSj2=QP9gwEDJ0NfX8|$;d=+5?*Sk8&xiWv^S#!^fW{^s4wDLO}PPx&$Vo&&RCt{2n!j(`I26afaxGht1=zKWbI{_tXbkd4crrYC=$4MzI`+@#cw5G1 zyCGw6Q~!v=jb3uF5dl`40J3CTmf1liO({wp5|NPt@3SPLNxdI>d?fe?5ClOG1VIo4 z@f6;F=rfh}=Vml^OXWP)z7IoHxZ~8(vVh5(PE|ZDlP8r6A=MizAnm1 zV=(M8J_k9`VvFy=24DaAR%rs{@=s1%!U;eY0n?kcmVD(1uxtZyoaP)5$0;nka@zp_ zuibiS1Vrw3&&YDLrhwZs#WdjI7tE7Aqn?L1Z<;^<+eJX9Ew`(ov{=P){1VIo4K@bE%5ClOG#P7

N!ouCx~0EFORo`@>Z$!V)nC&+cdPCJ_d+zGlUJK*{% zFv4(?6I?8pSB+eq<{v`$cFKd=VA&TetGeZI$t22Mf#JyrfQW#}B&vKbFdDne^K2;svWWQa--YO7+1aY(`|Hx& zAlth4en8VQ;QMQMo}Fvw-j(|t3U0he!pK&jvOdMBQKa~_Sh0=oy5uWy@?T(=5IxVv zU!VW4Gy*<;`jbs25%^w&%P-UIk=<#|#^N&gK>6#dzzF6E!f;b6=&xVYvC#*4%jXVIRev)=Mc%zf`>lf*=TjAYL>-005OFzJkMrT>t<807*qo IM6N<$g7{$bMgRZ+ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_m.png new file mode 100644 index 0000000000000000000000000000000000000000..75bb51ed37878ba7f48261aa3929dd750f6d3a8d GIT binary patch literal 1038 zcmV+p1o8WcP)Px&$Vo&&RCt{2n!j(`I26afaxGht1=zKWbI{_tXbkd4crrYC=$4MzI`+@#cw5G1 zyCGw6Q~!v=jb3uF5dl`40J3CTmf1liO({wp5|NPt@3SPLNxdI>d?fe?5ClOG1VIo4 z@f6;F=rfh}=Vml^OXWP)z7IoHxZ~8(vVh5(PE|ZDlP8r6A=MizAnm1 zV=(M8J_k9`VvFy=24DaAR%rs{@=s1%!U;eY0n?kcmVD(1uxtZyoaP)5$0;nka@zp_ zuibiS1Vrw3&&YDLrhwZs#WdjI7tE7Aqn?L1Z<;^<+eJX9Ew`(ov{=P){1VIo4K@bE%5ClOG#P7

N!ouCx~0EFORo`@>Z$!V)nC&+cdPCJ_d+zGlUJK*{% zFv4(?6I?8pSB+eq<{v`$cFKd=VA&TetGeZI$t22Mf#JyrfQW#}B&vKbFdDne^K2;svWWQa--YO7+1aY(`|Hx& zAlth4en8VQ;QMQMo}Fvw-j(|t3U0he!pK&jvOdMBQKa~_Sh0=oy5uWy@?T(=5IxVv zU!VW4Gy*<;`jbs25%^w&%P-UIk=<#|#^N&gK>6#dzzF6E!f;b6=&xVYvC#*4%jXVIRev)=Mc%zf`>lf*=TjAYL>-005OFzJkMrT>t<807*qo IM6N<$g7{$bMgRZ+ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/vox_m.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/vox_m.png new file mode 100644 index 0000000000000000000000000000000000000000..31f75a79964689e15b75cf96838ebfd3f18823a4 GIT binary patch literal 2545 zcmVR%AwslP76gU7RGTF$6Y-Ris8V?73u>jlRQ(6~oX7qH{Rb*V z;w6=c8YP6jAg~%M5vkOCpytEt6>Hqi#s;Gr8)H0oABHo&;}7s1+o`mhpA?Z9=HA~q z=bn4cxgP*;@fQErU``s%&V_jWyQRgPqrU!Ze(6TDb0O~cyAg?;g03G}KMRG!H(~_h zSG)}6eQy19%I|VQPD%r?jNtdXn~qF3Au105k;o|kfZ}D2`K1g%q@;XQ83j-?!kYl` z1O`0F?^X~P@YvqVLfQZ+&(~P{E^R3vRYtM)T^cFR*Ny~`g{ZXnGrwDL)St8g)bux) z{^BeEU{Esv0MlQbg_{1xkpQwN@AC#_^Sc$4_npl?X#*%;hNv=XDL<$gh$^GjyzDg; zFSCs}d4yAbDFZAm=2$LU!Dhy=z2D3j$Ym=%&jQ3xF^Hh+2afrrJ;3jGV@KIQV%>aB ztOGmB2K;`vY*&s^C>&ZYPbttT+O`;_7)nFAYz4vc70vqKAfEk@&5ik06<@#*`&S@sa9)2s8p(U)d;h5As&sY$Yjdc z$sHmXazpjGEJFaW-fNnIWU|;c|A|w8lvjN&luA`ptK3$A0JR)kDpjHSTsnD% zul)Fg&r)9XxhyXj96E)a+#xcVGNMtnZT_|M+`A5{@w)xx20$UjujIDE6S>9&kW+KQvSC+S#v2_kx8R_J5BEL63f|ccM_Uy?X z0s|gv8Wi^oruoDOvr1mTjL4LS#Zt7mXCM^z*dp(sW?*83Irf59{8R7N~J17VGlG-!R#FP(qfLK z(m*N=oE~s&11#JE5|85+KY3q$>02lqf@GVW3-P7J99y^>M=BjVk)x#n9=%N9wO(as zB7K$%QNStg8MZ*!-{04;CV!>hZ)h)rGm$>|4NFRT#n_QIt0oaT{$_EBKRxE1P zz8Ox;7q9iI<$i$yk1Yj?eV4Fyp<{B2hZ!SWaa z10Ia1!^kJcaPx-F0N~~go#m5b7*U7Kd|V!Dw@WDm%VT)-<1ns&b+IY`^{+1C(T~H@ z{B0W`l{QOE+6SmdV%_|GDlNs|Hd1L|{u++upT7oa{u+oA)0MGR$9->CGAb*lW(;>itP*+W_BQkMUOSM@X!j-#L<` z4gTXs9{}DzE6?Aq0r*ix2B6W+=y~C8oaSg(jWB=3G(L@TEB-(Bm>CPM^kxv=;w}CM z(Q(QWx627sq;wmfejc&rcDJ_RJ8Dcjwj#uHx^5YQ6sKb`5i(og&EU8pDc|Z;me%Q= z8sXE=BRmp0bu3ROM(FB!mbfiezeVO0g~DOO`acwIT=Y0aN87hFD!FV0xoib~zZ-hQm-_6dm;~i~`UX4w2+TQ;8``_Ujy$-+MZSjdRI7P=XAQUz?A!t-cuxM0;KmP#+ zH3Ron81BT^q_}8Dcq`*VA@EOY$t&^@cPBBR<0(+y=awLVsW<>^Zw$k)b+$W9`}^A) z!-$Uk3jl0}aC#|1gyShd=}(-WON%*{Ocs$$7O|sjU^8Ph+$E3!wck-TK>doNP28QF zLpt(+`m1W6=JIJi zKH;;1AIab}9ZKI5tXDpltynw4;}bs2Tt3~im6)hJ?EsSp|KJH-40xUw98c^Y(_ zE(DtaW-g!R;lI?B5N=;`YB;DFKxP!bY-L>7|II8> z>7sHps=})>OilJ~J8Eh&#=R;tt4!h2^!{(-*vhzYZ-t?#KDB~%vs>g#i#a9^=!tcJ z;$_hF1FOPIJ*b`fQV^tX-W16F#rlKXUvzuL%TOpB-&ei6^7?mF?^Cqh`Sq`u7%@Lt zeP|$h;iWYvBau@`CX2`?$GUz#Ff|$Df#?RJQPtwg?^cj}a1NLLW;*hd=N!S&7q%4L zq%N@OSf2(Pgr@7MG#!GYFYx3!x4eMX0Afi@0(BE&pTtGn=IGayFBA@sTO_s40<9nh zkU{}ifAJHxcQ4|Vejgu216C12>1p+$^ZLIPRv#J&MA5+YO23bVTNm+4{|O(312%cv zf%Ii*>iq2a7uNgw`$Dhu`!e0O1?sb&OO!>FuU$CtRsQ$Ue*ggJ;sFUnqjKDZ1gAKO z>qw^F{mBfaw@)rj;~gKz%^NyC`|@2xqbhRQh6|Ius0A2M^MG8|oC=?P`7UnW(D9Cs z$M{{#gc&3^1g*Y=Nf! zx!0JQjB(N3>z{jy`71Ggq%1!=hi`c9A$?2EsmU03axdV&bmRruP=F!s00000NkvXX Hu0mjf1AW{Q literal 0 HcmV?d00001