From 642043f5ccd46983b84ff843e751c843cc3d55c0 Mon Sep 17 00:00:00 2001 From: KashRas2 <140270505+KashRas2@users.noreply.github.com> Date: Fri, 6 Sep 2024 23:31:43 +0300 Subject: [PATCH] Kerfus is real (#419) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Описание PR Легендарный фикс вендоматов, возвращение причесок слаймов, а также... Керфус? **Медиа** Да что такое фотопленка. **Проверки** - [ ] PR полностью завершён и мне не нужна помощь чтобы его закончить. - [ ] Я внимательно просмотрел все свои изменения и багов в них не нашёл. - [ ] Я запускал локальный сервер со своими изменениями и всё протестировал. - [ ] Я добавил скриншот/видео демонстрации PR в игре, **или** этот PR этого не требует. **Изменения** :cl: KashRas2 - add: Возвращена возможность менять прически слаймам. - add: Отдел разработок Нанотрейзен представляет новую модель боргов для командования - Керфус. - fix: Починены цены в вендоматах после апстрима. - fix: Спрайт голограммы банкомата сбоку получило недостающие пиксели. --------- Co-authored-by: KashRas2 --- .../SlimeHair/SlimeHairBoundUserInterface.cs | 66 ++++ .../ADT/SlimeHair/SlimeHairWindow.xaml | 9 + .../ADT/SlimeHair/SlimeHairWindow.xaml.cs | 48 +++ .../UI/VendingMachineMenu.xaml.cs | 8 +- .../ADT/SlimeHair/SlimeHairComponent.cs | 61 ++++ .../SlimeHair/SlimeHairSystem.Abilities.cs | 30 ++ .../ADT/SlimeHair/SlimeHairSystem.cs | 307 ++++++++++++++++++ .../ADT/SlimeHair/SharedSlimeHairSystem.cs | 147 +++++++++ .../ADT/Ambience/Objects/minecraft_cat.ogg | Bin 0 -> 9608 bytes Resources/Audio/ADT/slime-hair.ogg | Bin 0 -> 18353 bytes .../interaction-popup-component.ftl | 2 + .../Objects/Specific/Robotics/borg_parts.ftl | 2 + Resources/Locale/ru-RU/ADT/actions/slime.ftl | 4 + .../prototypes/Entities/Mobs/Cyborgs/borg.ftl | 2 + Resources/Prototypes/ADT/Actions/slime.yml | 13 + .../Entities/Mobs/Cyborgs/borg_chassis.yml | 67 ++++ .../Objects/Specific/Robotics/borg_parts.yml | 31 ++ .../ADT/Recipes/Lathes/robotics.yml | 18 + Resources/Prototypes/ADT/tags.yml | 6 + .../Entities/Mobs/Species/slime.yml | 5 + .../Specific/Robotics/endoskeleton.yml | 15 + .../Entities/Structures/Machines/lathe.yml | 4 + .../Construction/Graphs/machines/cyborg.yml | 34 ++ .../Actions/actions_slime.rsi/hair.png | Bin 0 -> 712 bytes .../Actions/actions_slime.rsi/meta.json | 14 + .../Borgs/cyborg_kerfus.rsi/kerfus.png | Bin 0 -> 2485 bytes .../Borgs/cyborg_kerfus.rsi/kerfusNT.png | Bin 0 -> 1587 bytes .../Borgs/cyborg_kerfus.rsi/kerfusNT_e.png | Bin 0 -> 2583 bytes .../Borgs/cyborg_kerfus.rsi/kerfusNT_l.png | Bin 0 -> 1877 bytes .../Borgs/cyborg_kerfus.rsi/kerfus_e.png | Bin 0 -> 1292 bytes .../Borgs/cyborg_kerfus.rsi/kerfus_e_r.png | Bin 0 -> 598 bytes .../Borgs/cyborg_kerfus.rsi/kerfus_l.png | Bin 0 -> 694 bytes .../Silicon/Borgs/cyborg_kerfus.rsi/meta.json | 207 ++++++++++++ .../ADT/Structures/Machines/atm.rsi/atm.png | Bin 4471 -> 4453 bytes .../cyborg_parts.rsi/kerfusNT_head+o.png | Bin 0 -> 318 bytes .../cyborg_parts.rsi/kerfusNT_head.png | Bin 0 -> 317 bytes .../cyborg_parts.rsi/kerfusNT_torso+o.png | Bin 0 -> 285 bytes .../cyborg_parts.rsi/kerfusNT_torso.png | Bin 0 -> 287 bytes .../Robotics/cyborg_parts.rsi/meta.json | 12 + 39 files changed, 1109 insertions(+), 3 deletions(-) create mode 100644 Content.Client/ADT/SlimeHair/SlimeHairBoundUserInterface.cs create mode 100644 Content.Client/ADT/SlimeHair/SlimeHairWindow.xaml create mode 100644 Content.Client/ADT/SlimeHair/SlimeHairWindow.xaml.cs create mode 100644 Content.Server/ADT/SlimeHair/SlimeHairComponent.cs create mode 100644 Content.Server/ADT/SlimeHair/SlimeHairSystem.Abilities.cs create mode 100644 Content.Server/ADT/SlimeHair/SlimeHairSystem.cs create mode 100644 Content.Shared/ADT/SlimeHair/SharedSlimeHairSystem.cs create mode 100644 Resources/Audio/ADT/Ambience/Objects/minecraft_cat.ogg create mode 100644 Resources/Audio/ADT/slime-hair.ogg create mode 100644 Resources/Locale/ru-RU/ADT/Interaction/interaction-popup-component.ftl create mode 100644 Resources/Locale/ru-RU/ADT/actions/slime.ftl create mode 100644 Resources/Prototypes/ADT/Actions/slime.yml create mode 100644 Resources/Textures/ADT/Interface/Actions/actions_slime.rsi/hair.png create mode 100644 Resources/Textures/ADT/Interface/Actions/actions_slime.rsi/meta.json create mode 100644 Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfus.png create mode 100644 Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfusNT.png create mode 100644 Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfusNT_e.png create mode 100644 Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfusNT_l.png create mode 100644 Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfus_e.png create mode 100644 Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfus_e_r.png create mode 100644 Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfus_l.png create mode 100644 Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_head+o.png create mode 100644 Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_head.png create mode 100644 Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_torso+o.png create mode 100644 Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_torso.png diff --git a/Content.Client/ADT/SlimeHair/SlimeHairBoundUserInterface.cs b/Content.Client/ADT/SlimeHair/SlimeHairBoundUserInterface.cs new file mode 100644 index 00000000000..b8c3a8fad37 --- /dev/null +++ b/Content.Client/ADT/SlimeHair/SlimeHairBoundUserInterface.cs @@ -0,0 +1,66 @@ +using Content.Shared.Humanoid.Markings; +using Content.Shared.ADT.SlimeHair; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; + +namespace Content.Client.ADT.SlimeHair; + +public sealed class SlimeHairBoundUserInterface : BoundUserInterface +{ + [ViewVariables] + private SlimeHairWindow? _window; + + public SlimeHairBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + protected override void Open() + { + base.Open(); + + _window = this.CreateWindow(); + + _window.OnHairSelected += tuple => SelectHair(SlimeHairCategory.Hair, tuple.id, tuple.slot); + _window.OnHairColorChanged += args => ChangeColor(SlimeHairCategory.Hair, args.marking, args.slot); + _window.OnHairSlotAdded += delegate () { AddSlot(SlimeHairCategory.Hair); }; + _window.OnHairSlotRemoved += args => RemoveSlot(SlimeHairCategory.Hair, args); + + _window.OnFacialHairSelected += tuple => SelectHair(SlimeHairCategory.FacialHair, tuple.id, tuple.slot); + _window.OnFacialHairColorChanged += + args => ChangeColor(SlimeHairCategory.FacialHair, args.marking, args.slot); + _window.OnFacialHairSlotAdded += delegate () { AddSlot(SlimeHairCategory.FacialHair); }; + _window.OnFacialHairSlotRemoved += args => RemoveSlot(SlimeHairCategory.FacialHair, args); + } + + private void SelectHair(SlimeHairCategory category, string marking, int slot) + { + SendMessage(new SlimeHairSelectMessage(category, marking, slot)); + } + + private void ChangeColor(SlimeHairCategory category, Marking marking, int slot) + { + SendMessage(new SlimeHairChangeColorMessage(category, new(marking.MarkingColors), slot)); + } + + private void RemoveSlot(SlimeHairCategory category, int slot) + { + SendMessage(new SlimeHairRemoveSlotMessage(category, slot)); + } + + private void AddSlot(SlimeHairCategory category) + { + SendMessage(new SlimeHairAddSlotMessage(category)); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (state is not SlimeHairUiState data || _window == null) + { + return; + } + + _window.UpdateState(data); + } +} diff --git a/Content.Client/ADT/SlimeHair/SlimeHairWindow.xaml b/Content.Client/ADT/SlimeHair/SlimeHairWindow.xaml new file mode 100644 index 00000000000..580d4509365 --- /dev/null +++ b/Content.Client/ADT/SlimeHair/SlimeHairWindow.xaml @@ -0,0 +1,9 @@ + + + + + + diff --git a/Content.Client/ADT/SlimeHair/SlimeHairWindow.xaml.cs b/Content.Client/ADT/SlimeHair/SlimeHairWindow.xaml.cs new file mode 100644 index 00000000000..4a31fa7639a --- /dev/null +++ b/Content.Client/ADT/SlimeHair/SlimeHairWindow.xaml.cs @@ -0,0 +1,48 @@ +using Content.Shared.Humanoid.Markings; +using Content.Shared.ADT.SlimeHair; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.ADT.SlimeHair; + +[GenerateTypedNameReferences] +public sealed partial class SlimeHairWindow : DefaultWindow +{ + public Action<(int slot, string id)>? OnHairSelected; + public Action<(int slot, Marking marking)>? OnHairColorChanged; + public Action? OnHairSlotRemoved; + public Action? OnHairSlotAdded; + + public Action<(int slot, string id)>? OnFacialHairSelected; + public Action<(int slot, Marking marking)>? OnFacialHairColorChanged; + public Action? OnFacialHairSlotRemoved; + public Action? OnFacialHairSlotAdded; + + public SlimeHairWindow() + { + RobustXamlLoader.Load(this); + + HairPicker.OnMarkingSelect += args => OnHairSelected!(args); + HairPicker.OnColorChanged += args => OnHairColorChanged!(args); + HairPicker.OnSlotRemove += args => OnHairSlotRemoved!(args); + HairPicker.OnSlotAdd += delegate { OnHairSlotAdded!(); }; + + FacialHairPicker.OnMarkingSelect += args => OnFacialHairSelected!(args); + FacialHairPicker.OnColorChanged += args => OnFacialHairColorChanged!(args); + FacialHairPicker.OnSlotRemove += args => OnFacialHairSlotRemoved!(args); + FacialHairPicker.OnSlotAdd += delegate { OnFacialHairSlotAdded!(); }; + } + + public void UpdateState(SlimeHairUiState state) + { + HairPicker.UpdateData(state.Hair, state.Species, state.HairSlotTotal); + FacialHairPicker.UpdateData(state.FacialHair, state.Species, state.FacialHairSlotTotal); + + if (!HairPicker.Visible && !FacialHairPicker.Visible) + { + AddChild(new Label { Text = Loc.GetString("magic-mirror-component-activate-user-has-no-hair") }); + } + } +} diff --git a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs index 9cb89e94418..47f98ff728f 100644 --- a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs +++ b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs @@ -93,6 +93,7 @@ public void Populate(EntityUid entityUid, List inv }; var vendComp = _entityManager.GetComponent(entityUid); //ADT-Economy //ADT-Economy-End + if (inventory.Count == 0 && VendingContents.Visible) { SearchBar.Visible = false; @@ -123,6 +124,7 @@ public void Populate(EntityUid entityUid, List inv if (!_prototypeManager.TryIndex(entry.ID, out var prototype)) continue; + //ADT-Economy-Start var price = 0; if (!vendComp.AllForFree) @@ -142,12 +144,12 @@ public void Populate(EntityUid entityUid, List inv } var itemName = Identity.Name(dummy, _entityManager); - var itemText = $"{itemName} [{entry.Amount}]"; + var itemText = $" [{price}$] {itemName} [{entry.Amount}]"; //ADT-Economy if (itemText.Length > longestEntry.Length) longestEntry = itemText; - listData.Add(new VendorItemsListData(prototype.ID, itemText, i, price)); + listData.Add(new VendorItemsListData(prototype.ID, itemText, i)); } VendingContents.PopulateList(listData); @@ -163,4 +165,4 @@ private void SetSizeAfterUpdate(int longestEntryLength, int contentCount) } } -public record VendorItemsListData(EntProtoId ItemProtoID, string ItemText, int ItemIndex, int price) : ListData; +public record VendorItemsListData(EntProtoId ItemProtoID, string ItemText, int ItemIndex) : ListData; diff --git a/Content.Server/ADT/SlimeHair/SlimeHairComponent.cs b/Content.Server/ADT/SlimeHair/SlimeHairComponent.cs new file mode 100644 index 00000000000..65b602e7af0 --- /dev/null +++ b/Content.Server/ADT/SlimeHair/SlimeHairComponent.cs @@ -0,0 +1,61 @@ +using Content.Shared.DoAfter; +using Robust.Shared.Prototypes; +using Robust.Shared.Audio; + +namespace Content.Server.ADT.SlimeHair; + +/// +/// Allows humanoids to change their appearance mid-round. +/// +[RegisterComponent] +public sealed partial class SlimeHairComponent : Component +{ + [DataField] + public DoAfterId? DoAfter; + + /// + /// Magic mirror target, used for validating UI messages. + /// + [DataField] + public EntityUid? Target; + + /// + /// doafter time required to add a new slot + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public TimeSpan AddSlotTime = TimeSpan.FromSeconds(2); + + /// + /// doafter time required to remove a existing slot + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public TimeSpan RemoveSlotTime = TimeSpan.FromSeconds(2); + + /// + /// doafter time required to change slot + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public TimeSpan SelectSlotTime = TimeSpan.FromSeconds(2); + + /// + /// doafter time required to recolor slot + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public TimeSpan ChangeSlotTime = TimeSpan.FromSeconds(1); + + /// + /// Sound emitted when slots are changed + /// + [DataField] + public SoundSpecifier ChangeHairSound = new SoundPathSpecifier("/Audio/ADT/slime-hair.ogg") + { + Params = AudioParams.Default.WithVolume(-1f), + }; + + [DataField("hairAction")] + public EntProtoId Action = "ActionSlimeHair"; + + [DataField, AutoNetworkedField] + public EntityUid? ActionEntity; + +} diff --git a/Content.Server/ADT/SlimeHair/SlimeHairSystem.Abilities.cs b/Content.Server/ADT/SlimeHair/SlimeHairSystem.Abilities.cs new file mode 100644 index 00000000000..c284a13220c --- /dev/null +++ b/Content.Server/ADT/SlimeHair/SlimeHairSystem.Abilities.cs @@ -0,0 +1,30 @@ +using Content.Shared.ADT.SlimeHair; +using Robust.Shared.Player; + +namespace Content.Server.ADT.SlimeHair; + +/// +/// Allows humanoids to change their appearance mid-round. +/// +public sealed partial class SlimeHairSystem +{ + private void InitializeSlimeAbilities() + { + SubscribeLocalEvent(SlimeHairAction); + } + + private void SlimeHairAction(EntityUid uid, SlimeHairComponent comp, SlimeHairActionEvent args) + { + if (args.Handled) + return; + + if (!TryComp(uid, out var actor)) + return; + + _uiSystem.TryOpenUi(uid, SlimeHairUiKey.Key, actor.Owner); + + UpdateInterface(uid, comp); + + args.Handled = true; + } +} diff --git a/Content.Server/ADT/SlimeHair/SlimeHairSystem.cs b/Content.Server/ADT/SlimeHair/SlimeHairSystem.cs new file mode 100644 index 00000000000..472d0c4e71a --- /dev/null +++ b/Content.Server/ADT/SlimeHair/SlimeHairSystem.cs @@ -0,0 +1,307 @@ +using System.Linq; +using Content.Server.DoAfter; +using Content.Server.Humanoid; +using Content.Shared.UserInterface; +using Content.Shared.DoAfter; +using Content.Shared.Humanoid; +using Content.Shared.Humanoid.Markings; +using Content.Shared.Interaction; +using Content.Shared.ADT.SlimeHair; +using Robust.Server.GameObjects; +using Robust.Shared.Audio.Systems; +using Content.Server.Actions; + +namespace Content.Server.ADT.SlimeHair; + +/// +/// Allows humanoids to change their appearance mid-round. +/// + +// TODO: Исправить проблему с генокрадом +public sealed partial class SlimeHairSystem : EntitySystem +{ + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly MarkingManager _markings = default!; + [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!; + [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; + [Dependency] private readonly ActionsSystem _action = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnOpenUIAttempt); + + Subs.BuiEvents(SlimeHairUiKey.Key, subs => + { + subs.Event(OnUIClosed); + subs.Event(OnSlimeHairSelect); + subs.Event(OnTrySlimeHairChangeColor); + subs.Event(OnTrySlimeHairAddSlot); + subs.Event(OnTrySlimeHairRemoveSlot); + }); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShutdown); + + SubscribeLocalEvent(OnSelectSlotDoAfter); + SubscribeLocalEvent(OnChangeColorDoAfter); + SubscribeLocalEvent(OnRemoveSlotDoAfter); + SubscribeLocalEvent(OnAddSlotDoAfter); + + InitializeSlimeAbilities(); + + } + + private void OnOpenUIAttempt(EntityUid uid, SlimeHairComponent mirror, ActivatableUIOpenAttemptEvent args) + { + if (!HasComp(uid)) + args.Cancel(); + } + + private void OnSlimeHairSelect(EntityUid uid, SlimeHairComponent component, SlimeHairSelectMessage message) + { + if (component.Target is not { } target) + return; + + _doAfterSystem.Cancel(component.DoAfter); + component.DoAfter = null; + + var doAfter = new SlimeHairSelectDoAfterEvent() + { + Category = message.Category, + Slot = message.Slot, + Marking = message.Marking, + }; + + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, component.Owner, component.SelectSlotTime, doAfter, uid, target: target, used: uid) + { + DistanceThreshold = SharedInteractionSystem.InteractionRange, + BreakOnDamage = true, + }, out var doAfterId); + + component.DoAfter = doAfterId; + } + + private void OnSelectSlotDoAfter(EntityUid uid, SlimeHairComponent component, SlimeHairSelectDoAfterEvent args) + { + if (args.Handled || args.Target == null || args.Cancelled) + return; + + if (component.Target != args.Target) + return; + + MarkingCategories category; + + switch (args.Category) + { + case SlimeHairCategory.Hair: + category = MarkingCategories.Hair; + break; + case SlimeHairCategory.FacialHair: + category = MarkingCategories.FacialHair; + break; + default: + return; + } + + _humanoid.SetMarkingId(uid, category, args.Slot, args.Marking); + + UpdateInterface(uid, component); + } + + private void OnTrySlimeHairChangeColor(EntityUid uid, SlimeHairComponent component, SlimeHairChangeColorMessage message) + { + if (component.Target is not { } target) + return; + + _doAfterSystem.Cancel(component.DoAfter); + component.DoAfter = null; + + var doAfter = new SlimeHairChangeColorDoAfterEvent() + { + Category = message.Category, + Slot = message.Slot, + Colors = message.Colors, + }; + + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, component.Owner, component.ChangeSlotTime, doAfter, uid, target: target, used: uid) + { + BreakOnDamage = true, + }, out var doAfterId); + + component.DoAfter = doAfterId; + } + private void OnChangeColorDoAfter(EntityUid uid, SlimeHairComponent component, SlimeHairChangeColorDoAfterEvent args) + { + if (args.Handled || args.Target == null || args.Cancelled) + return; + + if (component.Target != args.Target) + return; + + MarkingCategories category; + switch (args.Category) + { + case SlimeHairCategory.Hair: + category = MarkingCategories.Hair; + break; + case SlimeHairCategory.FacialHair: + category = MarkingCategories.FacialHair; + break; + default: + return; + } + + _humanoid.SetMarkingColor(uid, category, args.Slot, args.Colors); + + // using this makes the UI feel like total ass + // que + // UpdateInterface(uid, component.Target, message.Session); + } + + private void OnTrySlimeHairRemoveSlot(EntityUid uid, SlimeHairComponent component, SlimeHairRemoveSlotMessage message) + { + if (component.Target is not { } target) + return; + + _doAfterSystem.Cancel(component.DoAfter); + component.DoAfter = null; + + var doAfter = new SlimeHairRemoveSlotDoAfterEvent() + { + Category = message.Category, + Slot = message.Slot, + }; + + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, component.Owner, component.RemoveSlotTime, doAfter, uid, target: target, used: uid) + { + DistanceThreshold = SharedInteractionSystem.InteractionRange, + BreakOnDamage = true, + }, out var doAfterId); + + component.DoAfter = doAfterId; + } + + private void OnRemoveSlotDoAfter(EntityUid uid, SlimeHairComponent component, SlimeHairRemoveSlotDoAfterEvent args) + { + if (args.Handled || args.Target == null || args.Cancelled) + return; + + if (component.Target != args.Target) + return; + + MarkingCategories category; + + switch (args.Category) + { + case SlimeHairCategory.Hair: + category = MarkingCategories.Hair; + break; + case SlimeHairCategory.FacialHair: + category = MarkingCategories.FacialHair; + break; + default: + return; + } + + _humanoid.RemoveMarking(component.Target.Value, category, args.Slot); + + _audio.PlayPvs(component.ChangeHairSound, uid); + UpdateInterface(uid, component); + } + + private void OnTrySlimeHairAddSlot(EntityUid uid, SlimeHairComponent component, SlimeHairAddSlotMessage message) + { + if (component.Target == null) + return; + + if (message.Actor == null) + return; + + _doAfterSystem.Cancel(component.DoAfter); + component.DoAfter = null; + + var doAfter = new SlimeHairAddSlotDoAfterEvent() + { + Category = message.Category, + }; + + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.AddSlotTime, doAfter, uid, target: component.Target.Value, used: uid) + { + BreakOnDamage = true, + }, out var doAfterId); + + component.DoAfter = doAfterId; + _audio.PlayPvs(component.ChangeHairSound, uid); + } + private void OnAddSlotDoAfter(EntityUid uid, SlimeHairComponent component, SlimeHairAddSlotDoAfterEvent args) + { + if (args.Handled || args.Target == null || args.Cancelled || !TryComp(component.Target, out HumanoidAppearanceComponent? humanoid)) + return; + + MarkingCategories category; + + switch (args.Category) + { + case SlimeHairCategory.Hair: + category = MarkingCategories.Hair; + break; + case SlimeHairCategory.FacialHair: + category = MarkingCategories.FacialHair; + break; + default: + return; + } + + var marking = _markings.MarkingsByCategoryAndSpecies(category, humanoid.Species).Keys.FirstOrDefault(); + + if (string.IsNullOrEmpty(marking)) + return; + + _audio.PlayPvs(component.ChangeHairSound, uid); + _humanoid.AddMarking(uid, marking, Color.Black); + + UpdateInterface(uid, component); + + } + + private void UpdateInterface(EntityUid uid, SlimeHairComponent component) + { + if (!TryComp(uid, out var humanoid)) + return; + + var hair = humanoid.MarkingSet.TryGetCategory(MarkingCategories.Hair, out var hairMarkings) + ? new List(hairMarkings) + : new(); + + var facialHair = humanoid.MarkingSet.TryGetCategory(MarkingCategories.FacialHair, out var facialHairMarkings) + ? new List(facialHairMarkings) + : new(); + + var state = new SlimeHairUiState( + humanoid.Species, + hair, + humanoid.MarkingSet.PointsLeft(MarkingCategories.Hair) + hair.Count, + facialHair, + humanoid.MarkingSet.PointsLeft(MarkingCategories.FacialHair) + facialHair.Count); + + component.Target = uid; + _uiSystem.SetUiState(uid, SlimeHairUiKey.Key, state); + } + + private void OnUIClosed(Entity ent, ref BoundUIClosedEvent args) + { + ent.Comp.Target = null; + } + + private void OnMapInit(EntityUid uid, SlimeHairComponent component, MapInitEvent args) + { + _action.AddAction(uid, ref component.ActionEntity, component.Action); + } + private void OnShutdown(EntityUid uid, SlimeHairComponent component, ComponentShutdown args) + { + _action.RemoveAction(uid, component.ActionEntity); + } + +} diff --git a/Content.Shared/ADT/SlimeHair/SharedSlimeHairSystem.cs b/Content.Shared/ADT/SlimeHair/SharedSlimeHairSystem.cs new file mode 100644 index 00000000000..cb06ae60152 --- /dev/null +++ b/Content.Shared/ADT/SlimeHair/SharedSlimeHairSystem.cs @@ -0,0 +1,147 @@ +using Content.Shared.DoAfter; +using Content.Shared.Humanoid.Markings; +using Robust.Shared.Serialization; +using Content.Shared.Actions; + +namespace Content.Shared.ADT.SlimeHair; + +[Serializable, NetSerializable] +public enum SlimeHairUiKey : byte +{ + Key +} + +[Serializable, NetSerializable] +public enum SlimeHairCategory : byte +{ + Hair, + FacialHair +} + +[Serializable, NetSerializable] +public sealed class SlimeHairSelectMessage : BoundUserInterfaceMessage +{ + public SlimeHairSelectMessage(SlimeHairCategory category, string marking, int slot) + { + Category = category; + Marking = marking; + Slot = slot; + } + + public SlimeHairCategory Category { get; } + public string Marking { get; } + public int Slot { get; } +} + +[Serializable, NetSerializable] +public sealed class SlimeHairChangeColorMessage : BoundUserInterfaceMessage +{ + public SlimeHairChangeColorMessage(SlimeHairCategory category, List colors, int slot) + { + Category = category; + Colors = colors; + Slot = slot; + } + + public SlimeHairCategory Category { get; } + public List Colors { get; } + public int Slot { get; } +} + +[Serializable, NetSerializable] +public sealed class SlimeHairRemoveSlotMessage : BoundUserInterfaceMessage +{ + public SlimeHairRemoveSlotMessage(SlimeHairCategory category, int slot) + { + Category = category; + Slot = slot; + } + + public SlimeHairCategory Category { get; } + public int Slot { get; } +} + +[Serializable, NetSerializable] +public sealed class SlimeHairSelectSlotMessage : BoundUserInterfaceMessage +{ + public SlimeHairSelectSlotMessage(SlimeHairCategory category, int slot) + { + Category = category; + Slot = slot; + } + + public SlimeHairCategory Category { get; } + public int Slot { get; } +} + +[Serializable, NetSerializable] +public sealed class SlimeHairAddSlotMessage : BoundUserInterfaceMessage +{ + public SlimeHairAddSlotMessage(SlimeHairCategory category) + { + Category = category; + } + + public SlimeHairCategory Category { get; } +} + +[Serializable, NetSerializable] +public sealed class SlimeHairUiState : BoundUserInterfaceState +{ + public SlimeHairUiState(string species, List hair, int hairSlotTotal, List facialHair, int facialHairSlotTotal) + { + Species = species; + Hair = hair; + HairSlotTotal = hairSlotTotal; + FacialHair = facialHair; + FacialHairSlotTotal = facialHairSlotTotal; + } + + public NetEntity Target; + + public string Species; + + public List Hair; + public int HairSlotTotal; + + public List FacialHair; + public int FacialHairSlotTotal; +} + +[Serializable, NetSerializable] +public sealed partial class SlimeHairRemoveSlotDoAfterEvent : DoAfterEvent +{ + public override DoAfterEvent Clone() => this; + public SlimeHairCategory Category; + public int Slot; +} + +[Serializable, NetSerializable] +public sealed partial class SlimeHairAddSlotDoAfterEvent : DoAfterEvent +{ + public override DoAfterEvent Clone() => this; + public SlimeHairCategory Category; +} + +[Serializable, NetSerializable] +public sealed partial class SlimeHairSelectDoAfterEvent : DoAfterEvent +{ + public SlimeHairCategory Category; + public int Slot; + public string Marking = string.Empty; + + public override DoAfterEvent Clone() => this; +} + +[Serializable, NetSerializable] +public sealed partial class SlimeHairChangeColorDoAfterEvent : DoAfterEvent +{ + public override DoAfterEvent Clone() => this; + public SlimeHairCategory Category; + public int Slot; + public List Colors = new List(); +} + +public sealed partial class SlimeHairActionEvent : InstantActionEvent +{ +} diff --git a/Resources/Audio/ADT/Ambience/Objects/minecraft_cat.ogg b/Resources/Audio/ADT/Ambience/Objects/minecraft_cat.ogg new file mode 100644 index 0000000000000000000000000000000000000000..340015e3f2da1c760ff01ff95dcd221fdbafed45 GIT binary patch literal 9608 zcmb7p2{_c<_xPPL_N5U?5<|AJ@0qek7=&T0udHLqnz1GsYa)`6WK9#YgiyAc7L+9< z46>A>Rf|F)zf14?e!sux`9II^`QPWx=W{;io^$TG=bm%#xpyqQy{!Qf{9RDdztLNu z>R*W#2q8pxP>8!Pc?*FssNQ-3K+!;KzwaO{wmAPSTbx@hO{R{1=*`Wc&HpNK41WZ1 z!ge#aa4$8SypkfUid+zZg+GrFl3S>6P@qewZvaV4Sy5RWVe(q7BB#dzoIn+1MTNXoh3nyWe)xQvPV#e=YJ%4 z{z1rldn>4@hJ{-PhY;`w;7AP&tq&7SENx6Ij{g4`Nf@${0zHB}Ng-O$S3S0TRdvf( zG5)^pf7}?s_~$LEf7liQbO8_}^GhG0lKB$R0{WJF<^=Vh`hDD^Z^j)jsBGrcD^AW7 zxmKc|;v^L}m`Ma%3}^Hrc@tChSVR)Vwd}JJB()%vf`d5UEgV|^pNApN2e#_5>`RXqp>QOXo#~%L)=?T;tu^g`3coHNGzsiY?;7>dn=guKvpU>{*mGxzC@Io)VcWA zijSWsu^fqBM?0I1!`j zxeH_hP;yl&^{NybTA+aqJO%)*YsK4rLh#82!6)^C>@1uPjBsH9ERfDP^_p?UYvU|2 zhb-~!I)C11A5gI^~k~Y_mffqM!MCRWhY0GVEd6o(HG~g*#R85#=8vQ~2>* zS6ORtGX--c4qW;8dfdJOUXgCpoXg zOu@Pu=4PKua`<2M&(PtngMrTeXCT-vesUk~tynhtpJBoY1;M;V+x}+KAZGeZtpAy; z#geK8kCqj$;jk)kXqU6qfdDIY(y*GdwYoFWHoz`7z^OTG@)BusC1&Qosx$NU5O)G_ zFl#?HOB9A6sib{9l!Q+rh=)vM**7B4$JoGbBJ@+qx8v zE$a$CR1z}`k?nn^`e%$oJX+A8cAh<3l`8y9(mmarNbOuxq6A& zjL>K(U9Nuy!H}mW@5KzC;-vRcyKqL8WzVhf_17H_;i=6wescxzvqy^RXj-+8 zYU6jK9x?%D_+u{}%-n_0UC1Q#;N}J0Q*q@59#3&nh1oqg$-;{} zu~hhpT`0(YYBFDN@tKJf^bZ;W{`93(Jq-a`63hk*nqO2k=M^{SF|^=y9^)|_$x-cB zRkN}on)8~E*bp7~%!#?;<|^jqyhLjrL*g!?b*?$Fi8P=ZFm6Mf;v~h1V zRLsY>K4EJZ{B&*(n7Z_@DB_q6aZ(+&s#%3PTMPhRwDV8ZodU zn%gx6Sce5T@feQnB97!5T8BX?F)m@G@iBv;FhgPvX{*Z|l5+&f?lxozAcn`xggQH4 z3Ujvia#~3m4hwV6A1X=9vTmK$=N0Bqdj~fLAEMpIC6% zOfQ8u0WJmD#7x2?{=_~Ub`P1LkF8815YqS)GI0{(|oYQ+;a4`!fNzLAF=)*}DCcq^WE_9Bv*iL(#q_#Ng*OwY@*kG2&&hU&4RlBUmd-q~6ty!8?=McZcQV5@^OG~SI+xt;oZ3Vn_~noZ zP!x#^FAYWE@k&rDD2huT4@Ftyp;qoP*b#gD@p>rARB6Js-Ji zJ3XYtyZAh6YnlWOWB+tM!sk)bvDLYFR~9~ftMl|0xEvm>f0OT6-O@?-3uyU~Padpn zaH(8?2AGc{B(mdR+#|Q*9wmZTVk*^3QChgB z%Az!1ke#ZufVoCcniotYC@)~Lvj|%dfsJ}Ci{Mw9O&}bvfpL%Aiu=8);(W|7Y{fw) z8*mL4?ER)`rAizRmwmEiFr*42Yu`2oMqfbhA52)-)HV$<%-MOxz)B4|Fm!M&$OSPD z%Q3??+nDAg7geGi#N?7@?47r0n!}v!oyNkZR+8Ls2X6;{X#KqQ;On7o z0KTA@K?!oNt&s*+fL(T5E10;!xz#fkNkGG`l!_+c;o8U_4AT zxJ9OCZ|##?5H)+}zq#3evb6sNF@jYK4X~<1FTvJp=$4AeASh5Mjh~tq!f}ult9A~@ zRGOU)E#-DjiG_OYxuat7s!@DC17)!%g41QVEo3Ti-C<=2zkL*#QSW8E!8 z+4f&u0C*qSTAwY{>r?Ws6k$=SsMN<}la&tlV6J1W*+h~=$f+X8(oS2`PPnn7QGf-S zKvCCHkpXaUp|zRyBz1!uVRozUnQW{oi#o%c1GtrT0Wk@w*GS!@PQ!^##?U>p@$!oY z(fa6k^rKgR&6swd^?>HrWXTt^sKToR=IxU*oPBsa>}EuB4+$Pg?qV`J)6HxQvtd{s z0~#}+i69LORL@)}t-n9?@+)E|Oj7Okn$jYbD*&dx93%CRmuIHhqf%A%AU5hHO-xFnxK#DJ?*VuCWNox=h1Mx zA$wQA(xc7ttQiaClj!9~2B&_A@OuIo|1&c`Z>ellGP?R+y8Zh#Q-Y8;nE z8|7Ua88(g4+;?@FL$I~hPxUxPMazQE6o9&gXWx!Z7wbe@t3+RX9z@j*$}W7vWz|JZ zaOXPlt>#KFe?L)mU}ER_&;gMLW%c?phv@7mVK=r*QR9yj5>@Uatzve* zym|J0c^b?0h@=1}RPuER2JW51NCOtGj{N50q?oMDEq{Md3gnPLgs(CKfSYMLZ`-OgdKb^ap z17Yg!ZB=Qn@Zx6ICgYI2)0h0q_vF{B%wp@L7W4W9z<0WZ9KM$<8ezr)qcL>D+Q~6y zSobb-s_VA~bxB_N03`T0J#Yix8_^cU2;N&pAQ=FC(}qEbO{(#ftwM0wV9erJX*>8h zJ5ZC`xc<7qU7Vt=e{>N>k*CmERxJc&?Z%=*YFcr_M*9O{BBYzSnq9Oq`MQ##7(IQ6?jPw3cZ=Pn*q+XpIyURIi-0WEJ#LhFu(uFrUMG~%yG?hO`+YlwBa-zjNz zOCAOw@o?~hF3@G=N2H)0A4)p-`Qiid?E9;a%jVXYf&u|*$}cjz=i@+Q0AiKRR~G=e z<|r6=y$kh2~GD9@+WCk=vK^Tl7(3jF05RVnx)i2=Nx^@}~t z8vcv1suQ}{lV|4(TTlLyes6MEzD*{97fSba zRL#?kT!)bKYlrqCz(MTO#vcl`wZ*k|Cx4GW4r0l%M*uWs?Gb&@VIL^HjJN`j@nXF2 zq9ef4r`=`3r)KIQK%c*50+(w5&sd)KHtd>LYZUm*+rtX2PXctuJtM!Y5%9Vf0L5Z7 z0IR6a{FH1D0A{^W;3NYASe5~JQ`yesL(`gFKR}s5O$20&MFy#n7nk6r<>Ig`@9CfY zcT8U4yEE?pL@)2wTJ`uPVay2VV3{p1Zh#dmGIQHlLdnqXx_&~4lFA-`Ht;AR{OPcb z&crU}Mf0DvC!7XMiA%pxfU*&XplsZ`&o~>%dVBLMD?lGR-3_$HA0oip^4lJOGLUp# zj={Am!now{SuP9zGyQ1wd5l$^H}{)63Z@}ij`AD}O^PRT*gvh8v4>wP;{~Iu`!b2j zyNlCpZ$(`0W-=F9Vgs43_uZLjD8UqCc!kBnS;4|04k)&Ml&Evl154*BMNhxd{X7xZ zs*ng0b&Z`qzzaEe(0o7>&~RMIBjAP{?rfwrrI9W=cCHMf5ODk+Miqib-&5o3%QMFIC~(Ky#YS4B^*MLfz@b6R z$%*OF(`zV>sZN@TLc`50iZ=p`CQVCix$je(bNI|EugWp7Bio|4D zK*3J4_4WgVv)@GPnQmNdrTGW|!Ko_#<GxtVL02@F-sm~&O{MqHC_JT~CiIBwit!1Iq8whX@MnK2yQ2|{ZslB^E z#@_U??tz#q$JU!g09||VyF8$r-w7SC(h?k-Ma?ek1Q%=dLDzmPLo}1wEW7Ko*lZq9 z@VuB$aG!15ke`Wzsj6R)7NXI2{wLeurH`S1iLOPQ1Vwv}(2WmX8LE9WBjmRE)$x4) zjMXWb+x-mFI?Ujd8w35b`5Dgk=KwV+iV;QX7WA4G1^yKMeFXo~3AnRf1_u-3(W=A(G>fW!b3 zDJB^E;`omdF78#uXHsneIF13dAF&9KcNS)lk~XbeKR)KZ{CIRf-LLDJ4Jg?ISBGMF z5`=t_r;xOzYhZO2tr*<-q<7_}N8FK;Sr3Y3T_Q{3=3A9;{@Zxt)e%PBfU~z29r+AY)vT^I4*TS9Q&QY3PHmC!G zbal~4eyGYI@mTW5WNGI%9|oXlcH$Z$@vZoPm!5#F0Fv(!3-ir zp_;uMx)z5(`)!uGd+e;4k=)`~P~0j#D?}G@mo`D#?>m+S!z z>#aJLv1<0qe0%RrZQDH@KnQ26*P^1m-~8Tb=VK;U;>&^9PyaxnmM^6{KY;m1bl06= zvNkmx1xO>;^U!NIPoO@9oom8USR8dfiy(nzH|X1ez(|5XA(${9gtK}Plqjr$I==;k zbQ74ZLIUX-xPVygWB3-rJnF6&)UjDkDZUp$lT=ieW|v4DIrQ^T;-}(@F~^#zu(7SfQ>^75c>FC~CB_GyZAX}`S4ozrs1o_yU`x~l-~SMx&#!R}9T_xER@Ee9YE z<3RAY-3g^$SAK1jYwvq$t+%EguWMKZ7iBP;ill+;nLWVuw|X)H%pO#r1(u*_Sqzw? z0e~U|cLICc2`s~x0tAIC4@{+Nj(Qkd$G=;=^rYk1QN<6rgV)=t=*Pzn7VbVL(bZM* zDneR2qieL*i5V2Ja9x-=^Zi1`OsrOW)?fJPB-i~; zcaXObqBTc1QkL=kVmNHzK^!h|~1`gkQbWy+ztOZ?AsZSaO|z&52kn7h}=z8hlpF0FLc5 zJaPgBiv2oNU4BG2>r_&6^Cpbdc9%SKnpjAMivMgwgV|VHkg~&^NuH@{B~cd4Px=Bd z@ncA$s`FJ0Z{*T3mbkkI#y@v{ zQENE1yykh&iP%r7W6Gw|-d!EY9r&mFV|!{OxRXGU(UeranAs-D|LfS*w380>55A0W zySHKSd4~dX`&FeRpyU6g`L_b&hc_Arqa41US%Sp1s$xoTJz+jG}p^Q^cIILpQ3^%s4A{WhSQhfGwjsj!m zzQCu>v-JxpqN}-1!?<>Gox?Zl?=o5T?v{IF?LC?nulDt$z;xFORCHEwUZ>ReOUC?H zE(#s$)?FjJl1sfym^<>^SrOod=gYNC%9a3H9)I2UB5d?ibc;`vRN=D z4Zl}KpW{Uet_E4>n_aWCE?npk?5#Oa%{V@KY(iI`M={N=JY1*jJo0Y%i^nC|Qbl#@ zn#U{lxW5j)vfnFI3CDcIV>fFj5)?iOiNw@=?xDQ=iDAlA@N+8MrMY1(UA5QMu|r+q zQ@6j^v1CnqKpyiu;^%dS!}PsQfMnz&q|@rsg}Qulrd*Yfbhr4e(*v$GQ=EmrsJZ2L zAAjB0G=A_^IL_xs%(oqLlJRG>d@^-p!Zn`RS}Y&TFJB_Kww0CH$K4DRakl+s#L5Py zNiQPPrlZiSyJ&%Q?#rSwPXITKbyXtoX`Lki?{actBV&C!YS+w~p3iAIN`=TXos^`t z+?GGZ_!C>iTP>LvQm(+Usi6ZX-!6$!Y9*~`Q^`vjhv^ot8Wf6E+IZUnb`7ldxVLvi z&Nzgp)~~G-&N7)^En!uA@JZxUG-Fo+SFpZwUaU4_{QLwL6KBD#1nHD=@+mhC3GkaF zSeN(OpDllN{KG|~qp^9V%?hqObTE){*&Y7ZFfqolV%2bl_F+FkDbbS!w3+)$pEORt zjc-&5V!@hv-hB8?%i>Zhao7C}y;oSJx`Kkb>{-mglcT@a7g!nmma*6o=V2N55}t{R z+IKc|10N{1zfj=5x8s-44jJV1lbh@`TXW6E+5=|0ZDxm}Iz5rGIl3*xC+c>|Xi}k!W1@%}n8JX@~#d+vO1!H&oKKuwTWTyGvO5cr- z{yp)Iu8^^;Q4O<@5PoN2MTZ2UFmEd3jfbyY=^Tdg@^R2b&h7CjM*v<0c;uD;FajDwGjdRD1nMZ0Ad&|D2b@NnR zlFbnB@%^%QSLT{js!htqGk3%pLqXhvqY-+gD2i<^T9~-+#E>xSVm{68yZD7*Wd!Ge ztOtS_g)<)M-+mt7d*(yOj&6~$N0^DhBgMzrZ3R%KWykqsK@rJDsqM9Not$OCPkM%2 zn!^|koMb8%9AyKZLN>5%t%giCZBsSS8-E>U!jL&tgkLRnads@6oKXxnQ zW-kWD8!en|XXIdNrrPGv-pmW$x6t6rl?`?wAC{*UX8H^yW1$CrAKLsOmVW)gDjnCS zD8VdyWRZhVZ<-~m2o#4$vmY`!xCFV>>|a!H@EVM#zWp38X8 z1?^YlF9{$0$pRd`j@b%%GirXWtFH4)lZc#62xn{KxCt&zykoTo+PUj3=X7lDBNTnF z@?@i!0OVYkzk&Ez`fEvtWTL@SbM?I%L1$5!tFHZH)TXhkjkg>N62uQU(vVf$OWH4E zOlArPir9i%+>WWwbY7$xA(tGBB^r$|I&?K4EG{gJT!tz8p}1xa+S-|i%9^aSwFhYo P@KDY^9}NH(7uWv)sks3~ literal 0 HcmV?d00001 diff --git a/Resources/Audio/ADT/slime-hair.ogg b/Resources/Audio/ADT/slime-hair.ogg new file mode 100644 index 0000000000000000000000000000000000000000..b41cbf52bc39606e76b61ebebcc23232fc08c102 GIT binary patch literal 18353 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfusNT.png b/Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfusNT.png new file mode 100644 index 0000000000000000000000000000000000000000..947504f98c4e4b4e56d9092ff6374eb005b6949a GIT binary patch literal 1587 zcmV-32F&@1P)W3iS_B-2i zJ@4H;_niCB@$$Yu*zSGrJyTLVJtwyhV|*b z{=L`5)qbJ)jRhDQI!4ux)}%{Ttx&d^oH$E3k1g6q37MaHy!uIKukuj>MNYKG=k5Ea;ZML0dS)oUP%#Z$=2V3TseUj~T z{8|BqPyCq1HjyZ&=_~(|Wo43p9Dp+{!sMBhXwUYQ_um^>ggw3c(|?Sgw)>NLWPaHv z_7`@rZ)&Vp@@ob7?bO+f-v~|xt7uuqc{t#-_lu!J-^~24roR49=<&MsGy9js2ur0d zDQ$3}z8=_11A|BB?A6c;zz(3((-XfNJHB$&9U^$013FYaTy5{CE}SEp5m^V(PO|@C zcZagARseJmGzi$~9MEBP*$N>fM$_=|qvERSP*?kqXwUXu&i02D<~x&`rp$_MSaANCe#0u})XG7Wr9 z0bUS+Uw;{;$;m(MbGSF(S$!MwEM%IcAHHvZL!+|e&*pq zBG4kpf$ivckFp)U)&Rb$y4%pTxcYAEOAt<@cL8U|y4#S>Q9p3w=VLE!+DQG$8)-w^ z73%8lQMUDh(UYL+it27dQH%tyr$7Y#x7eE7IAJ^jbRqye4dnK5i~tkJi?J890(|x5 zXGBju=Q<7C_GJe^F6=|VjbA0K+wj-%YXvy@^T_PZoD-OLQ&ZDaSXdyogS(5V_T}^T zZ)|x!g50(b2$>(?AiYKfi(|sC6<}oa1iq%E*@>;KZ&OG68+Nc*faKtDUJicFJ}@%) z=X}tCueu4p(QS~OK!F}W+#P8brbxNB!L_nWj=Z_p76Wb@Bt`)wnZrL17ZjeU+6BON2oN=D7fSbcn ziJ%Hz=4QY4eK9Duue4A!Bfv@E#7ILsRrIyGo{M5lKp(19oEx{wPZdHx2dIJv;CL7j zyn@$pnGMzbi2bUnwKGG0zCA{US0F0D2DXQ}U*7`&Kl5rXl`Hi0c40M>jUEE l&WiegIJvW`J|GV6{{e=Vr7m7cp@9GZ002ovPDHLkV1gXT53B$H literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfusNT_e.png b/Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfusNT_e.png new file mode 100644 index 0000000000000000000000000000000000000000..fe93ea025bc1d81988e3e456abe9f56e7c26a92d GIT binary patch literal 2583 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 SeXsvsK>K}z_tpBuvwjC=_N1f$ literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfus_e.png b/Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfus_e.png new file mode 100644 index 0000000000000000000000000000000000000000..436ab0f07189a4ff7f920136264691123e1ff03c GIT binary patch literal 1292 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSoCO|{#S9F5M?jcysy3fA0|U!G zPZ!6KiaBrR+WLn$O0=d6S8o$`c64MuckHX&GR4bO@DTC=jH=r`jY+oVq1Q%myg|B_UVttnjD|QCHc8Y@3m_;{9ncI z7hhYn`o58U-o(<+NB6G2{$}Iec~SP>4X2f4xgOT>9Js@7vhCkhZH@ zyLq98NZLNT9`}qIr8gA@e;#ggt-WAm?`K(}*EY5u)i&(+tj&hLE?YQHZxwEo)3>(9>r zd?L+#mNBdC%-a3cJ03^fZ=UpXdX|vJCrH?-Fj!&>QoO>k@(p|Tt>bryi@(mUuztNI z8Af2lA%=yTdJJXjboQE9vFE($;hnSh)&KmT-CPN`r&XCU9ZD8{8nwHe-*DO=%de~F zFxf~S{4j|D7$UYU!LP(c8Cu0}?%yVI!}a&U$7colVo&XUzMXf?MZT5C140_=_-{u( zj#i$sFW{1Zm{f1W!h$jzUw6j$e-iS-KOg+#%IXk!`&vz1@N=;R55vut{Z&6;7M8bj z`-bv5hM$U#S^pL>Mf|9!{ya^#;oSDb3yYcee7=36{g;L8(kJ^jGR(+%U^cHnXV>(< zN(s-pZ~s``?|C6f&*0df7k~a46>|Q}*Kv@M`TllwfcB#YJNnr+eoo*%HsgM-5XU38 z4?m>DydMPC^ZfiMD)Bw|RrpU^2C0L5hnjZ?+I%?I-{-$J{%t;E-2Rrpzk7cDN){kJ z+Q4D1?#*z%zMO5||98C84C^;Bh{Ia|jj?2pg)YqPF@KiB^&;#;Uy{UnBu zS>o%t>>2U`Oda@aAawY5us}8bg`}3m4hbj9> ze2UNw@h>xYqbu%w|6%rEs{K5cY3J-U7|vO5W`6PLgKp<^tLl zr;B4q#hkaZ4E+x|h#dc~;-|N!>mm1!LysOkNpU))UU22^$<_&Ntta>T9Pv*`I`rhp zBc|2y4IOKA4Cd{d)*arl%>6#=tnYQ++~qs({asg^`T3q;%VH)48BvCZD;PN3S)aW9 zQ4wqUeX*-*$p6|{`|S;hpRj0o zW>K9{cK+7$+2>DgtPVc@Ky*#HgT@|~3y(4jzulSY&|Q9;ZL8I(20JFZxtYiRSF!xd zwoci@vL^1lLU-V>ElewTinjZcFk$X0IZ zlAWQEcZ5q%=j%Max3jYPzstp_BZrtKajtp&QRCHa!P!}Cm$v+TcR}Lw*PXxn4u-ZJ zmt$VT!qqf2BdB7Mh|Bc5i5tY%D70u2$r3U_xQ=boFyt=akR{0P)ZQs{jB1 literal 0 HcmV?d00001 diff --git a/Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfus_l.png b/Resources/Textures/ADT/Mobs/Silicon/Borgs/cyborg_kerfus.rsi/kerfus_l.png new file mode 100644 index 0000000000000000000000000000000000000000..b78dc822b064a7f8229efee52a86263704b2a4d2 GIT binary patch literal 694 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 A;s5{u diff --git a/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_head+o.png b/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_head+o.png new file mode 100644 index 0000000000000000000000000000000000000000..694b84caa7eab8415724aaad566de869e47814ab GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCilo1AIbULxKYh{^T@n-H-@SX+#3g31^_jAg+Uc_wP0j6=uH2THQvy`$ z{@{ofkm4-~@(cct1Q={zD7674I14-?iy0XB4ude`@%$AjK*4rT7sn6_|F`GP@*PqT zV0n=0byvRP|MSwRx?98^JNhpxp2ZVy7VvjMJ#+Q0*NfG3bR#AteJ+_GoDuud&8KHd zvaEyAl&BdZkxB0luvjr|ykV`eEYoG}5j(vp%o@wNKNUUv(jL!nxp&1ao{s;UmsZSY w6i-O|@ten{mGQ&pez|J){Nl!G`HpMLOD1bsFW)%78t5bjPgg&ebxsLQ0A{jzF8}}l literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_head.png b/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_head.png new file mode 100644 index 0000000000000000000000000000000000000000..7d2d2d1c951e0af20635ba784b359935501fc33a GIT binary patch literal 317 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCilo1AIbULxKYh{^T@n-H-@SX+#3g31^_jAg+Uc_wP0j6=uH2THQvy`$ z{@{ofkm4-~@(cct1Q={zD7674I14-?iy0XB4ude`@%$AjK*2Uo7sn6_|F`G7`3@`a zuml(@er11Ge=n*jVNyWp#dWLBoszPTT=q+CKU+tmUly!A~6MA_h-aKbLh*2~7Y*TXcp1 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_torso+o.png b/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_torso+o.png new file mode 100644 index 0000000000000000000000000000000000000000..b0e4c65613b39d659ed481ff4fdccc3f9039a3bc GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCil21AIbUPoKTGbmcbt%7cNO=VD`13=NExmDKKSvjxhpHR#*}q&Q20{DS{O z0Yk8Vg%C)vz$3Dlfr0NZ2s0kfUy%Y7Ec0}646*Qkd*&ctg8~oph1`Ir|M%bM^F4O( z$ZB?J&kePX$GqzVemXw!c5qpGsQR09LiRNmot$sn8y-JbYDkOMf5DQJ%T!x&@cz>b zF{R(EyWWewy{XT@C1c?ySK$7Qdq+UtgNwQP1`T!WTk{Wis{Kzd`!K;!Z_ykX*OHwP RIY1XMc)I$ztaD0e0sx^pX|(_V literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_torso.png b/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/kerfusNT_torso.png new file mode 100644 index 0000000000000000000000000000000000000000..660c2be7a9bb1c91d94783fc1f5ebf1170171068 GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCil21AIbUPoKTGbmcbt%7cNO=VD`13=NExmDKKSvjxhpHR#*}q&Q20{DS{O z0Yk8Vg%C)vz$3Dlfr0N32s4Umcr^e8D?D8sLoEE?o;k?Zpuod?Avfsh|NS@me2*PG z(kz#&a_}4LOa7mZPplOd1wFL=&AP$#wu?^AH{lJBpDQ(_#p}OdNV?5X^|@*P>5Dop z--J!>Yv0;5pF!ltMtPeDeQ(qY7T!6q_;lO?=C@o~@ePxG{`IeUU}oR3hjs7#i$7&t USMTQE1#|<0r>mdKI;Vst0OLJx0RR91 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/meta.json b/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/meta.json index 16f24bd30c2..f65b87fa3d2 100644 --- a/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/meta.json +++ b/Resources/Textures/Objects/Specific/Robotics/cyborg_parts.rsi/meta.json @@ -214,6 +214,18 @@ { "name": "service_r_leg+o" }, + { + "name": "kerfusNT_head" + }, + { + "name": "kerfusNT_head+o" + }, + { + "name": "kerfusNT_torso" + }, + { + "name": "kerfusNT_torso+o" + }, { "name": "security_l_arm" },