]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Adding shock collar and electropack (#30529)
authorto4no_fix <156101927+chavonadelal@users.noreply.github.com>
Thu, 15 Aug 2024 14:30:39 +0000 (17:30 +0300)
committerGitHub <noreply@github.com>
Thu, 15 Aug 2024 14:30:39 +0000 (10:30 -0400)
* Adding shock collar with the new ShockOnTrigger

* Cleaning and updating the shock collar

* Add StripDelay datafield to ClothingComponent

* Adding SelfUnremovableClothingComponent

* ShockCollar Update

* Correction of the shock collar

* Correction of the shock collar 2

* Renaming the DamageSpecifier DataField to Damage

* Fixing the damage field in ShockCollar

* Cleaning the ShockCollar

* Renaming ShockCollar to ClothingNeckShockCollar

* Adding ClothingNeckShockCollar as a stealTarget to a thief

* Fixing a typo of the sprite path in ClothingNeckShockCollar

* Cleaning the ShockOnTriggerComponent

* Revision of SelfUnremovableClothing

* Adding a ClothingBackpackElectropack

* Sprite fix

* Code review

* Shock Collar sprite update

* add commit hash

---------

Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
29 files changed:
Content.Server/Explosion/Components/ShockOnTriggerComponent.cs [new file with mode: 0644]
Content.Server/Explosion/EntitySystems/TriggerSystem.cs
Content.Server/Strip/StrippableSystem.cs
Content.Shared/Clothing/Components/ClothingComponent.cs
Content.Shared/Clothing/Components/SelfUnremovableClothingComponent.cs [new file with mode: 0644]
Content.Shared/Clothing/EntitySystems/ClothingSystem.cs
Content.Shared/Clothing/EntitySystems/SelfUnremovableClothingSystem.cs [new file with mode: 0644]
Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs
Content.Shared/Strip/Components/StrippableComponent.cs
Content.Shared/Strip/SharedStrippableSystem.cs
Resources/Locale/en-US/clothing/components/self-unremovable-clothing-component.ftl [new file with mode: 0644]
Resources/Locale/en-US/research/technologies.ftl
Resources/Prototypes/Catalog/Fills/Lockers/security.yml
Resources/Prototypes/Entities/Clothing/Back/backpacks.yml
Resources/Prototypes/Entities/Objects/Devices/shock_collar.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Structures/Machines/lathe.yml
Resources/Prototypes/Objectives/objectiveGroups.yml
Resources/Prototypes/Objectives/stealTargetGroups.yml
Resources/Prototypes/Objectives/thief.yml
Resources/Prototypes/Recipes/Lathes/security.yml
Resources/Prototypes/Research/arsenal.yml
Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/equipped-BACKPACK.png [new file with mode: 0644]
Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-left.png [new file with mode: 0644]
Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-right.png [new file with mode: 0644]
Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/meta.json [new file with mode: 0644]
Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/equipped-NECK.png [new file with mode: 0644]
Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/meta.json [new file with mode: 0644]

diff --git a/Content.Server/Explosion/Components/ShockOnTriggerComponent.cs b/Content.Server/Explosion/Components/ShockOnTriggerComponent.cs
new file mode 100644 (file)
index 0000000..a553cc0
--- /dev/null
@@ -0,0 +1,37 @@
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+using Content.Server.Explosion.EntitySystems;
+
+namespace Content.Server.Explosion.Components;
+
+/// <summary>
+/// A component that electrocutes an entity having this component when a trigger is triggered.
+/// </summary>
+[RegisterComponent, AutoGenerateComponentPause]
+[Access(typeof(TriggerSystem))]
+public sealed partial class ShockOnTriggerComponent : Component
+{
+    /// <summary>
+    /// The force of an electric shock when the trigger is triggered.
+    /// </summary>
+    [DataField]
+    public int Damage = 5;
+
+    /// <summary>
+    /// Duration of electric shock when the trigger is triggered.
+    /// </summary>
+    [DataField]
+    public TimeSpan Duration = TimeSpan.FromSeconds(2);
+
+    /// <summary>
+    /// The minimum delay between repeating triggers.
+    /// </summary>
+    [DataField]
+    public TimeSpan Cooldown = TimeSpan.FromSeconds(4);
+
+    /// <summary>
+    /// When can the trigger run again?
+    /// </summary>
+    [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+    [AutoPausedField]
+    public TimeSpan NextTrigger = TimeSpan.Zero;
+}
index 92e065bf4ce6984ec7af0ae99c8d117df1f4b3ed..1208cd1771bf08e029ddb7702b96e2b25ac288dc 100644 (file)
@@ -3,6 +3,7 @@ using Content.Server.Body.Systems;
 using Content.Server.Chemistry.Containers.EntitySystems;
 using Content.Server.Explosion.Components;
 using Content.Server.Flash;
+using Content.Server.Electrocution;
 using Content.Server.Pinpointer;
 using Content.Shared.Flash.Components;
 using Content.Server.Radio.EntitySystems;
@@ -33,6 +34,7 @@ using Robust.Shared.Random;
 using Robust.Shared.Player;
 using Content.Shared.Coordinates;
 using Robust.Shared.Utility;
+using Robust.Shared.Timing;
 
 namespace Content.Server.Explosion.EntitySystems
 {
@@ -75,6 +77,7 @@ namespace Content.Server.Explosion.EntitySystems
         [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
         [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
         [Dependency] private readonly InventorySystem _inventory = default!;
+        [Dependency] private readonly ElectrocutionSystem _electrocution = default!;
 
         public override void Initialize()
         {
@@ -104,6 +107,7 @@ namespace Content.Server.Explosion.EntitySystems
 
             SubscribeLocalEvent<AnchorOnTriggerComponent, TriggerEvent>(OnAnchorTrigger);
             SubscribeLocalEvent<SoundOnTriggerComponent, TriggerEvent>(OnSoundTrigger);
+            SubscribeLocalEvent<ShockOnTriggerComponent, TriggerEvent>(HandleShockTrigger);
             SubscribeLocalEvent<RattleComponent, TriggerEvent>(HandleRattleTrigger);
         }
 
@@ -120,6 +124,24 @@ namespace Content.Server.Explosion.EntitySystems
             }
         }
 
+        private void HandleShockTrigger(Entity<ShockOnTriggerComponent> shockOnTrigger, ref TriggerEvent args)
+        {
+            if (!_container.TryGetContainingContainer(shockOnTrigger, out var container))
+                return;
+
+            var containerEnt = container.Owner;
+            var curTime = _timing.CurTime;
+
+            if (curTime < shockOnTrigger.Comp.NextTrigger)
+            {
+                // The trigger's on cooldown.
+                return;
+            }
+
+            _electrocution.TryDoElectrocution(containerEnt, null, shockOnTrigger.Comp.Damage, shockOnTrigger.Comp.Duration, true);
+            shockOnTrigger.Comp.NextTrigger = curTime + shockOnTrigger.Comp.Cooldown;
+        }
+
         private void OnAnchorTrigger(EntityUid uid, AnchorOnTriggerComponent component, TriggerEvent args)
         {
             var xform = Transform(uid);
index 194df7b3d0792fe3b2d525eb65aa60c44ed584cc..6d728df9d67bfbb5794bf40e1b528479c62a48ad 100644 (file)
@@ -218,7 +218,7 @@ namespace Content.Server.Strip
                 return;
             }
 
-            var (time, stealth) = GetStripTimeModifiers(user, target, slotDef.StripTime);
+            var (time, stealth) = GetStripTimeModifiers(user, target, held, slotDef.StripTime);
 
             if (!stealth)
                 _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-insert", ("user", Identity.Entity(user, EntityManager)), ("item", user.Comp.ActiveHandEntity!.Value)), target, target, PopupType.Large);
@@ -306,7 +306,7 @@ namespace Content.Server.Strip
                 return;
             }
 
-            var (time, stealth) = GetStripTimeModifiers(user, target, slotDef.StripTime);
+            var (time, stealth) = GetStripTimeModifiers(user, target, item, slotDef.StripTime);
 
             if (!stealth)
             {
@@ -411,7 +411,7 @@ namespace Content.Server.Strip
             if (!CanStripInsertHand(user, target, held, handName))
                 return;
 
-            var (time, stealth) = GetStripTimeModifiers(user, target, targetStrippable.HandStripDelay);
+            var (time, stealth) = GetStripTimeModifiers(user, target, null, targetStrippable.HandStripDelay);
 
             if (!stealth)
                 _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner-insert-hand", ("user", Identity.Entity(user, EntityManager)), ("item", user.Comp.ActiveHandEntity!.Value)), target, target, PopupType.Large);
@@ -510,7 +510,7 @@ namespace Content.Server.Strip
             if (!CanStripRemoveHand(user, target, item, handName))
                 return;
 
-            var (time, stealth) = GetStripTimeModifiers(user, target, targetStrippable.HandStripDelay);
+            var (time, stealth) = GetStripTimeModifiers(user, target, null, targetStrippable.HandStripDelay);
 
             if (!stealth)
                 _popupSystem.PopupEntity(Loc.GetString("strippable-component-alert-owner", ("user", Identity.Entity(user, EntityManager)), ("item", item)), target, target);
index 581125d4fe31ee443e4f204d647d61a0f9e31c57..4f8058dbf5a03e77e8f449e018de3e9295fc4b2e 100644 (file)
@@ -69,6 +69,13 @@ public sealed partial class ClothingComponent : Component
 
     [DataField, ViewVariables(VVAccess.ReadWrite)]
     public TimeSpan UnequipDelay = TimeSpan.Zero;
+
+    /// <summary>
+    /// Offset for the strip time for an entity with this component.
+    /// Only applied when it is being equipped or removed by another player.
+    /// </summary>
+    [DataField]
+    public TimeSpan StripDelay = TimeSpan.Zero;
 }
 
 [Serializable, NetSerializable]
diff --git a/Content.Shared/Clothing/Components/SelfUnremovableClothingComponent.cs b/Content.Shared/Clothing/Components/SelfUnremovableClothingComponent.cs
new file mode 100644 (file)
index 0000000..1d62451
--- /dev/null
@@ -0,0 +1,18 @@
+using Content.Shared.Clothing.EntitySystems;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Clothing.Components;
+
+/// <summary>
+///     The component prohibits the player from taking off clothes on them that have this component.
+/// </summary>
+/// <remarks>
+///     See also ClothingComponent.EquipDelay if you want the clothes that the player cannot take off by himself to be put on by the player with a delay.
+///</remarks>
+[NetworkedComponent]
+[RegisterComponent]
+[Access(typeof(SelfUnremovableClothingSystem))]
+public sealed partial class SelfUnremovableClothingComponent : Component
+{
+
+}
index 082b040a32051ec00257c92ca760a3164e8ca072..3b26360f10795065ea4e3e9a620fdb53f5a2616b 100644 (file)
@@ -6,6 +6,7 @@ using Content.Shared.Interaction.Events;
 using Content.Shared.Inventory;
 using Content.Shared.Inventory.Events;
 using Content.Shared.Item;
+using Content.Shared.Strip.Components;
 using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
 
@@ -32,6 +33,8 @@ public abstract class ClothingSystem : EntitySystem
 
         SubscribeLocalEvent<ClothingComponent, ClothingEquipDoAfterEvent>(OnEquipDoAfter);
         SubscribeLocalEvent<ClothingComponent, ClothingUnequipDoAfterEvent>(OnUnequipDoAfter);
+
+        SubscribeLocalEvent<ClothingComponent, BeforeItemStrippedEvent>(OnItemStripped);
     }
 
     private void OnUseInHand(Entity<ClothingComponent> ent, ref UseInHandEvent args)
@@ -192,6 +195,11 @@ public abstract class ClothingSystem : EntitySystem
             _handsSystem.TryPickup(args.User, ent);
     }
 
+    private void OnItemStripped(Entity<ClothingComponent> ent, ref BeforeItemStrippedEvent args)
+    {
+        args.Additive += ent.Comp.StripDelay;
+    }
+
     private void CheckEquipmentForLayerHide(EntityUid equipment, EntityUid equipee)
     {
         if (TryComp(equipment, out HideLayerClothingComponent? clothesComp) && TryComp(equipee, out HumanoidAppearanceComponent? appearanceComp))
diff --git a/Content.Shared/Clothing/EntitySystems/SelfUnremovableClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/SelfUnremovableClothingSystem.cs
new file mode 100644 (file)
index 0000000..ab0c41c
--- /dev/null
@@ -0,0 +1,36 @@
+using Content.Shared.Clothing.Components;
+using Content.Shared.Examine;
+using Content.Shared.Inventory;
+using Content.Shared.Inventory.Events;
+
+namespace Content.Shared.Clothing.EntitySystems;
+
+/// <summary>
+///     A system for the operation of a component that prohibits the player from taking off his own clothes that have this component.
+/// </summary>
+public sealed class SelfUnremovableClothingSystem : EntitySystem
+{
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<SelfUnremovableClothingComponent, BeingUnequippedAttemptEvent>(OnUnequip);
+        SubscribeLocalEvent<SelfUnremovableClothingComponent, ExaminedEvent>(OnUnequipMarkup);
+    }
+
+    private void OnUnequip(Entity<SelfUnremovableClothingComponent> selfUnremovableClothing, ref BeingUnequippedAttemptEvent args)
+    {
+        if (TryComp<ClothingComponent>(selfUnremovableClothing, out var clothing) && (clothing.Slots & args.SlotFlags) == SlotFlags.NONE)
+            return;
+
+        if (args.UnEquipTarget == args.Unequipee)
+        {
+            args.Cancel();
+        }
+    }
+
+    private void OnUnequipMarkup(Entity<SelfUnremovableClothingComponent> selfUnremovableClothing, ref ExaminedEvent args)
+    {
+        args.PushMarkup(Loc.GetString("comp-self-unremovable-clothing"));
+    }
+}
index c828b22481afe8f372d32fa64fa1c2627702d64d..aa3381c6bf936c8fab3e61af6f1bd9087317a586 100644 (file)
@@ -95,7 +95,7 @@ public sealed class ToggleableClothingSystem : EntitySystem
         if (component.StripDelay == null)
             return;
 
-        var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, component.StripDelay.Value);
+        var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, item, component.StripDelay.Value);
 
         var args = new DoAfterArgs(EntityManager, user, time, new ToggleClothingDoAfterEvent(), item, wearer, item)
         {
index 4faca4d8f21c45a6d514fad17f1c785978b489c5..5191b3f3f9440131bdbdc34d4bfc48c32b36091e 100644 (file)
@@ -44,6 +44,15 @@ namespace Content.Shared.Strip.Components
         public SlotFlags TargetSlots { get; } = SlotFlags.GLOVES;
     }
 
+    /// <summary>
+    ///     Used to modify strip times. Raised directed at the item being stripped.
+    /// </summary>
+    /// <remarks>
+    ///     This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player.
+    /// </remarks>
+    [ByRefEvent]
+    public sealed class BeforeItemStrippedEvent(TimeSpan initialTime, bool stealth = false) : BaseBeforeStripEvent(initialTime, stealth);
+
     /// <summary>
     ///     Used to modify strip times. Raised directed at the user.
     /// </summary>
index e42f6e3aa783960fe5d43485ba2b927dda3d1f9c..935dc33540eef34d933043f38f9550b8f0e28f4e 100644 (file)
@@ -28,13 +28,19 @@ public abstract class SharedStrippableSystem : EntitySystem
             args.Handled = true;
     }
 
-    public (TimeSpan Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, TimeSpan initialTime)
+    /// <summary>
+    /// Modify the strip time via events. Raised directed at the item being stripped, the player stripping someone and the player being stripped.
+    /// </summary>
+    public (TimeSpan Time, bool Stealth) GetStripTimeModifiers(EntityUid user, EntityUid targetPlayer, EntityUid? targetItem, TimeSpan initialTime)
     {
-        var userEv = new BeforeStripEvent(initialTime);
+        var itemEv = new BeforeItemStrippedEvent(initialTime, false);
+        if (targetItem != null)
+            RaiseLocalEvent(targetItem.Value, ref itemEv);
+        var userEv = new BeforeStripEvent(itemEv.Time, itemEv.Stealth);
         RaiseLocalEvent(user, ref userEv);
-        var ev = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth);
-        RaiseLocalEvent(target, ref ev);
-        return (ev.Time, ev.Stealth);
+        var targetEv = new BeforeGettingStrippedEvent(userEv.Time, userEv.Stealth);
+        RaiseLocalEvent(targetPlayer, ref targetEv);
+        return (targetEv.Time, targetEv.Stealth);
     }
 
     private void OnDragDrop(EntityUid uid, StrippableComponent component, ref DragDropDraggedEvent args)
diff --git a/Resources/Locale/en-US/clothing/components/self-unremovable-clothing-component.ftl b/Resources/Locale/en-US/clothing/components/self-unremovable-clothing-component.ftl
new file mode 100644 (file)
index 0000000..bb7ff02
--- /dev/null
@@ -0,0 +1 @@
+comp-self-unremovable-clothing = This cannot be removed without outside help.
index 4fbb0e1bd3718c3ccea9269b560e62dbdaa64d03..0b0970ec08f10cd1977cfcb3e97cd6ed3a98ae9a 100644 (file)
@@ -26,6 +26,7 @@ research-technology-salvage-weapons = Salvage Weapons
 research-technology-draconic-munitions = Draconic Munitions
 research-technology-uranium-munitions = Uranium Munitions
 research-technology-explosive-technology = Explosive Technology
+research-technology-special-means = Special Means
 research-technology-weaponized-laser-manipulation = Weaponized Laser Manipulation
 research-technology-nonlethal-ammunition = Nonlethal Ammunition
 research-technology-practice-ammunition = Practice Ammunition
index 2d012128e6cd278b3b2ff8a43de2163d2647099b..b72fce11075c4fe4df4997369254535df4e9a275 100644 (file)
       - id: ClothingOuterHardsuitWarden
       - id: HoloprojectorSecurity
       - id: BookSpaceLaw
+      - id: ClothingNeckShockCollar
+        amount: 2
+      - id: RemoteSignaller
+        amount: 2
 
 - type: entity
   id: LockerWardenFilled
       - id: DoorRemoteArmory
       - id: HoloprojectorSecurity
       - id: BookSpaceLaw
+      - id: ClothingNeckShockCollar
+        amount: 2
+      - id: RemoteSignaller
+        amount: 2
 
 - type: entity
   id: LockerSecurityFilled
index 2d5bf424667206728e6be29fb1389b59df7412b8..f94b773886d23dabdab405c054214097507695a2 100644 (file)
   - type: Unremoveable
     deleteOnDrop: false
 
+- type: entity
+  parent: ClothingBackpack
+  id: ClothingBackpackElectropack
+  name: electropack
+  suffix: SelfUnremovable
+  description: Shocks on the signal. It is used to keep a particularly dangerous criminal under control.
+  components:
+  - type: Sprite
+    sprite: Clothing/Back/Backpacks/electropack.rsi
+    state: icon
+  - type: Clothing
+    stripDelay: 10
+    equipDelay: 5 # to avoid accidentally falling into the trap associated with SelfUnremovableClothing
+  - type: SelfUnremovableClothing
+  - type: ShockOnTrigger
+    damage: 5
+    duration: 3
+    cooldown: 4
+  - type: TriggerOnSignal
+  - type: DeviceLinkSink
+    ports:
+      - Trigger
+
 # Debug
 - type: entity
   parent: ClothingBackpack
diff --git a/Resources/Prototypes/Entities/Objects/Devices/shock_collar.yml b/Resources/Prototypes/Entities/Objects/Devices/shock_collar.yml
new file mode 100644 (file)
index 0000000..22f2d09
--- /dev/null
@@ -0,0 +1,36 @@
+- type: entity
+  parent: Clothing
+  id: ClothingNeckShockCollar
+  name: shock collar
+  suffix: SelfUnremovable
+  description: An electric collar that shocks on the signal.
+  components:
+  - type: Item
+    size: Small
+  - type: Sprite
+    sprite: Clothing/Neck/Misc/shock_collar.rsi
+    state: icon
+  - type: Clothing
+    sprite: Clothing/Neck/Misc/shock_collar.rsi
+    stripDelay: 10
+    equipDelay: 5 # to avoid accidentally falling into the trap associated with SelfUnremovableClothing
+    quickEquip: true
+    slots:
+    - neck
+  - type: SelfUnremovableClothing
+  - type: ShockOnTrigger
+    damage: 5
+    duration: 3
+    cooldown: 4
+  - type: TriggerOnSignal
+  - type: DeviceLinkSink
+    ports:
+      - Trigger
+  - type: GuideHelp
+    guides:
+      - Security
+  - type: StealTarget
+    stealGroup: ClothingNeckShockCollar
+  - type: Tag
+    tags:
+    - WhitelistChameleon
index 98d5440e3ed8b086b7be068698c41767bf60b2cf..e795a5836e1351e35815c4b3c4605fc708041dda 100644 (file)
@@ -16,7 +16,7 @@
         mask:
         - MachineMask
         layer:
-          - MachineLayer  
+          - MachineLayer
   - type: Lathe
   - type: MaterialStorage
   - type: Destructible
       - WeaponLaserCannon
       - WeaponLaserCarbine
       - WeaponXrayCannon
+      - ClothingBackpackElectropack
   - type: MaterialStorage
     whitelist:
       tags:
index e62aa9fdf6b3eeca393cab4710d6abbe6fe92b75..c692c85dff842231c9e4e752075b411949e324cf 100644 (file)
@@ -73,6 +73,7 @@
     ForensicScannerStealObjective: 1                    #sec
     FlippoEngravedLighterStealObjective: 0.5
     ClothingHeadHatWardenStealObjective: 1
+    ClothingNeckShockCollarStealObjective: 1
     ClothingOuterHardsuitVoidParamedStealObjective: 1   #med
     MedicalTechFabCircuitboardStealObjective: 1
     ClothingHeadsetAltMedicalStealObjective: 1
index 1a9b4223cb0c1676210734d88cb39d89333cfd23..e818442b4c452ceb929b628c5fc071f0de0e67fa 100644 (file)
     sprite: Clothing/Neck/Medals/clownmedal.rsi
     state: icon
 
+- type: stealTargetGroup
+  id: ClothingNeckShockCollar
+  name: shock collar
+  sprite:
+    sprite: Clothing/Neck/Misc/shock_collar.rsi
+    state: icon
+
 #Thief structures
 
 - type: stealTargetGroup
index 672f9b2ba7c1ef09201785f85968e393adc48b02..092a724da2dde79437575c7d4b6a36030da756a0 100644 (file)
   - type: Objective
     difficulty: 1
 
+- type: entity
+  parent: BaseThiefStealObjective
+  id: ClothingNeckShockCollarStealObjective
+  components:
+  - type: NotJobRequirement
+    job: Warden
+  - type: StealCondition
+    stealGroup: ClothingNeckShockCollar
+  - type: Objective
+    difficulty: 1
+
 # Structures
 
 - type: entity
index 1e6b70f943664b9c0bc13479c8578ce6d62d08c8..a54d5b62356344f895faad8d5a03ab8973ca1b79 100644 (file)
@@ -38,7 +38,7 @@
   materials:
     Steel: 250
     Plastic: 100
-    
+
 - type: latheRecipe
   id: WeaponLaserCarbine
   result: WeaponLaserCarbine
     Plastic: 250
     Gold: 100
 
+- type: latheRecipe
+  id: ClothingBackpackElectropack
+  result: ClothingBackpackElectropack
+  completetime: 4
+  materials:
+    Steel: 500
+    Plastic: 250
+    Cloth: 500
+
 - type: latheRecipe
   id: ForensicPad
   result: ForensicPad
     Steel: 1000
     Glass: 500
     Plastic: 500
-     
+
 - type: latheRecipe
   id: MagazineGrenadeEmpty
   result: MagazineGrenadeEmpty
   materials:
      Steel: 150
      Plastic: 50
-     
+
 - type: latheRecipe
   id: GrenadeEMP
   result: GrenadeEMP
      Steel: 150
      Plastic: 100
      Glass: 20
-     
+
 - type: latheRecipe
   id: GrenadeBlast
   result: GrenadeBlast
      Steel: 450
      Plastic: 300
      Gold: 150
-     
+
 - type: latheRecipe
   id: GrenadeFlash
   result: GrenadeFlash
index 1cfa1fec80f28b0a1db3d1d003c57f823ddba2fc..553258fdb3f45fab4a19ab909c787caa69655d17 100644 (file)
@@ -58,8 +58,8 @@
   cost: 5000
   recipeUnlocks:
   - MagazineShotgunBeanbag
-  - BoxShellTranquilizer 
-  - BoxBeanbag 
+  - BoxShellTranquilizer
+  - BoxBeanbag
   - WeaponDisabler
 
 - type: technology
   - ExplosivePayload
   - ChemicalPayload
 
+- type: technology
+  id: SpecialMeans
+  name: research-technology-special-means
+  icon:
+    sprite: Clothing/Back/Backpacks/electropack.rsi
+    state: icon
+  discipline: Arsenal
+  tier: 1
+  cost: 5000
+  recipeUnlocks:
+  - ClothingBackpackElectropack
+
 # Tier 2
 
 - type: technology
 - type: technology
   id: BasicShuttleArmament
   name: research-technology-basic-shuttle-armament
-  icon: 
+  icon:
     sprite: Structures/Power/cage_recharger.rsi
     state: full
   discipline: Arsenal
   cost: 15000
   recipeUnlocks:
   - WeaponLaserSvalinn
-  
+
 - type: technology
   id: AdvancedShuttleWeapon
   name: research-technology-advanced-shuttle-weapon
-  icon: 
+  icon:
     sprite: Objects/Weapons/Guns/Ammunition/Magazine/Grenade/grenade_cartridge.rsi
     state: icon
   discipline: Arsenal
diff --git a/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/equipped-BACKPACK.png b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/equipped-BACKPACK.png
new file mode 100644 (file)
index 0000000..3ea6cdc
Binary files /dev/null and b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/equipped-BACKPACK.png differ
diff --git a/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/icon.png b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/icon.png
new file mode 100644 (file)
index 0000000..b4b755e
Binary files /dev/null and b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/icon.png differ
diff --git a/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-left.png b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-left.png
new file mode 100644 (file)
index 0000000..49f6243
Binary files /dev/null and b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-left.png differ
diff --git a/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-right.png b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-right.png
new file mode 100644 (file)
index 0000000..26901ce
Binary files /dev/null and b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-right.png differ
diff --git a/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/meta.json b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/meta.json
new file mode 100644 (file)
index 0000000..4e77381
--- /dev/null
@@ -0,0 +1,33 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/2d26ce62c273d025bed77a0e6c4bdc770b789bb0",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon",
+      "delays": [
+        [
+          0.1,
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-BACKPACK",
+      "directions": 4
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/equipped-NECK.png b/Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/equipped-NECK.png
new file mode 100644 (file)
index 0000000..ffca324
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/equipped-NECK.png differ
diff --git a/Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/icon.png b/Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/icon.png
new file mode 100644 (file)
index 0000000..f8e0a9c
Binary files /dev/null and b/Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/icon.png differ
diff --git a/Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/meta.json b/Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/meta.json
new file mode 100644 (file)
index 0000000..3119a51
--- /dev/null
@@ -0,0 +1,19 @@
+{
+    "version": 1,
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Drawn by EmoGarbage404 (github) for Space Station 14",
+    "size": {
+      "x": 32,
+      "y": 32
+    },
+
+    "states": [
+      {
+        "name": "equipped-NECK",
+        "directions": 4
+      },
+      {
+        "name": "icon"
+      }
+    ]
+  }