Adding shock collar and electropack (#30529)
* 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>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
comp-self-unremovable-clothing = This cannot be removed without outside help.
|
||||
@@ -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
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
- id: ClothingOuterHardsuitWarden
|
||||
- id: HoloprojectorSecurity
|
||||
- id: BookSpaceLaw
|
||||
- id: ClothingNeckShockCollar
|
||||
amount: 2
|
||||
- id: RemoteSignaller
|
||||
amount: 2
|
||||
|
||||
- type: entity
|
||||
id: LockerWardenFilled
|
||||
@@ -42,6 +46,10 @@
|
||||
- id: DoorRemoteArmory
|
||||
- id: HoloprojectorSecurity
|
||||
- id: BookSpaceLaw
|
||||
- id: ClothingNeckShockCollar
|
||||
amount: 2
|
||||
- id: RemoteSignaller
|
||||
amount: 2
|
||||
|
||||
- type: entity
|
||||
id: LockerSecurityFilled
|
||||
|
||||
@@ -314,6 +314,29 @@
|
||||
- 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
|
||||
|
||||
@@ -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
|
||||
@@ -808,6 +808,7 @@
|
||||
- WeaponLaserCannon
|
||||
- WeaponLaserCarbine
|
||||
- WeaponXrayCannon
|
||||
- ClothingBackpackElectropack
|
||||
- type: MaterialStorage
|
||||
whitelist:
|
||||
tags:
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
ForensicScannerStealObjective: 1 #sec
|
||||
FlippoEngravedLighterStealObjective: 0.5
|
||||
ClothingHeadHatWardenStealObjective: 1
|
||||
ClothingNeckShockCollarStealObjective: 1
|
||||
ClothingOuterHardsuitVoidParamedStealObjective: 1 #med
|
||||
MedicalTechFabCircuitboardStealObjective: 1
|
||||
ClothingHeadsetAltMedicalStealObjective: 1
|
||||
|
||||
@@ -272,6 +272,13 @@
|
||||
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
|
||||
|
||||
@@ -316,6 +316,17 @@
|
||||
- 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
|
||||
|
||||
@@ -89,6 +89,15 @@
|
||||
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
|
||||
|
||||
@@ -115,6 +115,18 @@
|
||||
- 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
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 594 B |
Binary file not shown.
|
After Width: | Height: | Size: 457 B |
Binary file not shown.
|
After Width: | Height: | Size: 432 B |
Binary file not shown.
|
After Width: | Height: | Size: 441 B |
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 465 B |
BIN
Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/icon.png
Normal file
BIN
Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 800 B |
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user