From f74d5487b61bb0dbe373be87fdb7e59eb0127a36 Mon Sep 17 00:00:00 2001
From: to4no_fix <156101927+chavonadelal@users.noreply.github.com>
Date: Thu, 15 Aug 2024 17:30:39 +0300
Subject: [PATCH] Adding shock collar and electropack (#30529)
---
.../Components/ShockOnTriggerComponent.cs | 37 +++++++++++++++++
.../Explosion/EntitySystems/TriggerSystem.cs | 22 ++++++++++
.../Item/ShockCollar/ShockCollarComponent.cs | 12 ------
.../Item/ShockCollar/ShockCollarSystem.cs | 39 ------------------
Content.Server/Strip/StrippableSystem.cs | 8 ++--
.../Clothing/Components/ClothingComponent.cs | 7 ++++
.../SelfUnremovableClothingComponent.cs | 18 ++++++++
.../Clothing/EntitySystems/ClothingSystem.cs | 8 ++++
.../SelfUnremovableClothingSystem.cs | 36 ++++++++++++++++
.../EntitySystems/ToggleableClothingSystem.cs | 2 +-
.../Strip/Components/StrippableComponent.cs | 9 ++++
.../Strip/SharedStrippableSystem.cs | 18 +++++---
.../self-unremovable-clothing-component.ftl | 1 +
.../Locale/en-US/research/technologies.ftl | 1 +
Resources/Migrations/eeMigration.yml | 3 ++
.../Catalog/Fills/Lockers/security.yml | 10 ++++-
.../Entities/Clothing/Back/backpacks.yml | 23 +++++++++++
.../Entities/Objects/Devices/shock_collar.yml | 36 ++++++++++++++++
.../Entities/Structures/Machines/lathe.yml | 9 ++--
.../Markers/Spawners/Random/devices.yml | 2 +-
.../Entities/Objects/Devices/shock_collar.yml | 24 -----------
.../Nyanotrasen/Recipes/Lathes/security.yml | 12 ------
.../Prototypes/Objectives/objectiveGroups.yml | 27 ++++++------
.../Objectives/stealTargetGroups.yml | 7 ++++
Resources/Prototypes/Objectives/thief.yml | 11 +++++
.../Prototypes/Recipes/Lathes/security.yml | 9 ++++
Resources/Prototypes/Research/arsenal.yml | 12 ++++++
.../electropack.rsi/equipped-BACKPACK.png | Bin 0 -> 594 bytes
.../Back/Backpacks/electropack.rsi/icon.png | Bin 0 -> 457 bytes
.../Backpacks/electropack.rsi/inhand-left.png | Bin 0 -> 432 bytes
.../electropack.rsi/inhand-right.png | Bin 0 -> 441 bytes
.../Back/Backpacks/electropack.rsi/meta.json | 33 +++++++++++++++
.../Misc/shock_collar.rsi/equipped-NECK.png | Bin 0 -> 465 bytes
.../Neck/Misc/shock_collar.rsi/icon.png | Bin 0 -> 800 bytes
.../Neck/Misc/shock_collar.rsi/meta.json | 19 +++++++++
.../Neck/Misc/shock.rsi/equipped-NECK.png | Bin 323 -> 0 bytes
.../Clothing/Neck/Misc/shock.rsi/icon.png | Bin 573 -> 0 bytes
.../Clothing/Neck/Misc/shock.rsi/meta.json | 19 ---------
38 files changed, 336 insertions(+), 138 deletions(-)
create mode 100644 Content.Server/Explosion/Components/ShockOnTriggerComponent.cs
delete mode 100644 Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarComponent.cs
delete mode 100644 Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarSystem.cs
create mode 100644 Content.Shared/Clothing/Components/SelfUnremovableClothingComponent.cs
create mode 100644 Content.Shared/Clothing/EntitySystems/SelfUnremovableClothingSystem.cs
create mode 100644 Resources/Locale/en-US/clothing/components/self-unremovable-clothing-component.ftl
create mode 100644 Resources/Prototypes/Entities/Objects/Devices/shock_collar.yml
delete mode 100644 Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml
create mode 100644 Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/equipped-BACKPACK.png
create mode 100644 Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/icon.png
create mode 100644 Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-left.png
create mode 100644 Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/inhand-right.png
create mode 100644 Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/meta.json
create mode 100644 Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/equipped-NECK.png
create mode 100644 Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/icon.png
create mode 100644 Resources/Textures/Clothing/Neck/Misc/shock_collar.rsi/meta.json
delete mode 100644 Resources/Textures/Nyanotrasen/Clothing/Neck/Misc/shock.rsi/equipped-NECK.png
delete mode 100644 Resources/Textures/Nyanotrasen/Clothing/Neck/Misc/shock.rsi/icon.png
delete mode 100644 Resources/Textures/Nyanotrasen/Clothing/Neck/Misc/shock.rsi/meta.json
diff --git a/Content.Server/Explosion/Components/ShockOnTriggerComponent.cs b/Content.Server/Explosion/Components/ShockOnTriggerComponent.cs
new file mode 100644
index 0000000000..a553cc047a
--- /dev/null
+++ b/Content.Server/Explosion/Components/ShockOnTriggerComponent.cs
@@ -0,0 +1,37 @@
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+using Content.Server.Explosion.EntitySystems;
+
+namespace Content.Server.Explosion.Components;
+
+///
+/// A component that electrocutes an entity having this component when a trigger is triggered.
+///
+[RegisterComponent, AutoGenerateComponentPause]
+[Access(typeof(TriggerSystem))]
+public sealed partial class ShockOnTriggerComponent : Component
+{
+ ///
+ /// The force of an electric shock when the trigger is triggered.
+ ///
+ [DataField]
+ public int Damage = 5;
+
+ ///
+ /// Duration of electric shock when the trigger is triggered.
+ ///
+ [DataField]
+ public TimeSpan Duration = TimeSpan.FromSeconds(2);
+
+ ///
+ /// The minimum delay between repeating triggers.
+ ///
+ [DataField]
+ public TimeSpan Cooldown = TimeSpan.FromSeconds(4);
+
+ ///
+ /// When can the trigger run again?
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ [AutoPausedField]
+ public TimeSpan NextTrigger = TimeSpan.Zero;
+}
diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs
index 1fde61cada..be47585f5a 100644
--- a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs
+++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs
@@ -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(OnAnchorTrigger);
SubscribeLocalEvent(OnSoundTrigger);
+ SubscribeLocalEvent(HandleShockTrigger);
SubscribeLocalEvent(HandleRattleTrigger);
}
@@ -120,6 +124,24 @@ namespace Content.Server.Explosion.EntitySystems
}
}
+ private void HandleShockTrigger(Entity 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);
diff --git a/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarComponent.cs b/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarComponent.cs
deleted file mode 100644
index 1dcbc48676..0000000000
--- a/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarComponent.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Content.Server.ShockCollar;
-
-[RegisterComponent]
-public sealed partial class ShockCollarComponent : Component
-{
- [DataField]
- public int ShockDamage = 1;
-
- [DataField]
- public TimeSpan ShockTime = TimeSpan.FromSeconds(2);
-}
-
diff --git a/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarSystem.cs b/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarSystem.cs
deleted file mode 100644
index eeb0f59d42..0000000000
--- a/Content.Server/Nyanotrasen/Item/ShockCollar/ShockCollarSystem.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using Content.Shared.Mobs.Components;
-using Content.Shared.Timing;
-using Content.Server.Explosion.EntitySystems; // Why is trigger under explosions by the way? Even doors already use it.
-using Content.Server.Electrocution;
-using Robust.Shared.Containers;
-
-namespace Content.Server.ShockCollar;
-
-public sealed partial class ShockCollarSystem : EntitySystem
-{
- [Dependency] private readonly SharedContainerSystem _container = default!;
- [Dependency] private readonly ElectrocutionSystem _electrocutionSystem = default!;
- [Dependency] private readonly UseDelaySystem _useDelay = default!;
-
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent(OnTrigger);
- }
-
- private void OnTrigger(EntityUid uid, ShockCollarComponent component, TriggerEvent args)
- {
- if (!_container.TryGetContainingContainer(uid, out var container)) // Try to get the entity directly containing this
- return;
-
- var containerEnt = container.Owner;
-
- if (!HasComp(containerEnt)) // If it's not a mob we don't care
- return;
-
- // DeltaV: prevent clocks from instantly killing people
- if (TryComp(uid, out var useDelay)
- && !_useDelay.TryResetDelay((uid, useDelay), true))
- return;
-
- _electrocutionSystem.TryDoElectrocution(containerEnt, null, component.ShockDamage, component.ShockTime, true, ignoreInsulation: true);
- }
-}
-
diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs
index 4a03bfba9e..7f00c63c4f 100644
--- a/Content.Server/Strip/StrippableSystem.cs
+++ b/Content.Server/Strip/StrippableSystem.cs
@@ -219,7 +219,7 @@ namespace Content.Server.Strip
return;
}
- var (time, stealth) = GetStripTimeModifiers(user, target, slotDef.StripTime);
+ var (time, stealth) = GetStripTimeModifiers(user, target, held, slotDef.StripTime);
bool hidden = stealth == ThievingStealth.Hidden;
@@ -309,7 +309,7 @@ namespace Content.Server.Strip
return;
}
- var (time, stealth) = GetStripTimeModifiers(user, target, slotDef.StripTime);
+ var (time, stealth) = GetStripTimeModifiers(user, target, item, slotDef.StripTime);
bool hidden = stealth == ThievingStealth.Hidden;
@@ -416,7 +416,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);
bool hidden = stealth == ThievingStealth.Hidden;
@@ -517,7 +517,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);
bool hidden = stealth == ThievingStealth.Hidden;
diff --git a/Content.Shared/Clothing/Components/ClothingComponent.cs b/Content.Shared/Clothing/Components/ClothingComponent.cs
index 02a0181eb5..bf52720fe6 100644
--- a/Content.Shared/Clothing/Components/ClothingComponent.cs
+++ b/Content.Shared/Clothing/Components/ClothingComponent.cs
@@ -71,6 +71,13 @@ public sealed partial class ClothingComponent : Component
[DataField]
public TimeSpan UnequipDelay = TimeSpan.Zero;
+ ///
+ /// Offset for the strip time for an entity with this component.
+ /// Only applied when it is being equipped or removed by another player.
+ ///
+ [DataField]
+ public TimeSpan StripDelay = TimeSpan.Zero;
+
///
/// These functions are called when an entity equips an item with this component.
///
diff --git a/Content.Shared/Clothing/Components/SelfUnremovableClothingComponent.cs b/Content.Shared/Clothing/Components/SelfUnremovableClothingComponent.cs
new file mode 100644
index 0000000000..1d624516ec
--- /dev/null
+++ b/Content.Shared/Clothing/Components/SelfUnremovableClothingComponent.cs
@@ -0,0 +1,18 @@
+using Content.Shared.Clothing.EntitySystems;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Clothing.Components;
+
+///
+/// The component prohibits the player from taking off clothes on them that have this component.
+///
+///
+/// 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.
+///
+[NetworkedComponent]
+[RegisterComponent]
+[Access(typeof(SelfUnremovableClothingSystem))]
+public sealed partial class SelfUnremovableClothingComponent : Component
+{
+
+}
diff --git a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs
index b97348bf11..2d4c073e0c 100644
--- a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs
+++ b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs
@@ -8,6 +8,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;
@@ -36,6 +37,8 @@ public abstract class ClothingSystem : EntitySystem
SubscribeLocalEvent(OnEquipDoAfter);
SubscribeLocalEvent(OnUnequipDoAfter);
+
+ SubscribeLocalEvent(OnItemStripped);
}
private void OnUseInHand(Entity ent, ref UseInHandEvent args)
@@ -227,6 +230,11 @@ public abstract class ClothingSystem : EntitySystem
_handsSystem.TryPickup(args.User, ent);
}
+ private void OnItemStripped(Entity 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
index 0000000000..ab0c41c5c7
--- /dev/null
+++ b/Content.Shared/Clothing/EntitySystems/SelfUnremovableClothingSystem.cs
@@ -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;
+
+///
+/// A system for the operation of a component that prohibits the player from taking off his own clothes that have this component.
+///
+public sealed class SelfUnremovableClothingSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnUnequip);
+ SubscribeLocalEvent(OnUnequipMarkup);
+ }
+
+ private void OnUnequip(Entity selfUnremovableClothing, ref BeingUnequippedAttemptEvent args)
+ {
+ if (TryComp(selfUnremovableClothing, out var clothing) && (clothing.Slots & args.SlotFlags) == SlotFlags.NONE)
+ return;
+
+ if (args.UnEquipTarget == args.Unequipee)
+ {
+ args.Cancel();
+ }
+ }
+
+ private void OnUnequipMarkup(Entity selfUnremovableClothing, ref ExaminedEvent args)
+ {
+ args.PushMarkup(Loc.GetString("comp-self-unremovable-clothing"));
+ }
+}
diff --git a/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs
index 63f817f9bb..4b9db83722 100644
--- a/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs
+++ b/Content.Shared/Clothing/EntitySystems/ToggleableClothingSystem.cs
@@ -106,7 +106,7 @@ public sealed class ToggleableClothingSystem : EntitySystem
if (comp.StripDelay == null)
return;
- var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, comp.StripDelay.Value);
+ var (time, stealth) = _strippable.GetStripTimeModifiers(user, wearer, toggleable, comp.StripDelay.Value);
bool hidden = stealth == ThievingStealth.Hidden;
diff --git a/Content.Shared/Strip/Components/StrippableComponent.cs b/Content.Shared/Strip/Components/StrippableComponent.cs
index 0072580829..551fdfda67 100644
--- a/Content.Shared/Strip/Components/StrippableComponent.cs
+++ b/Content.Shared/Strip/Components/StrippableComponent.cs
@@ -44,6 +44,15 @@ namespace Content.Shared.Strip.Components
public SlotFlags TargetSlots { get; } = SlotFlags.GLOVES;
}
+ ///
+ /// Used to modify strip times. Raised directed at the item being stripped.
+ ///
+ ///
+ /// This is also used by some stripping related interactions, i.e., interactions with items that are currently equipped by another player.
+ ///
+ [ByRefEvent]
+ public sealed class BeforeItemStrippedEvent(TimeSpan initialTime, ThievingStealth stealth = ThievingStealth.Obvious) : BaseBeforeStripEvent(initialTime, stealth);
+
///
/// Used to modify strip times. Raised directed at the user.
///
diff --git a/Content.Shared/Strip/SharedStrippableSystem.cs b/Content.Shared/Strip/SharedStrippableSystem.cs
index 3897c6cc7d..e402a00341 100644
--- a/Content.Shared/Strip/SharedStrippableSystem.cs
+++ b/Content.Shared/Strip/SharedStrippableSystem.cs
@@ -26,20 +26,26 @@ public abstract class SharedStrippableSystem : EntitySystem
private void OnActivateInWorld(EntityUid uid, StrippableComponent component, ActivateInWorldEvent args)
{
- if (args.Handled || args.Target == args.User)
+ if (args.Handled || !args.Complex || args.Target == args.User)
return;
if (TryOpenStrippingUi(args.User, (uid, component)))
args.Handled = true;
}
- public (TimeSpan Time, ThievingStealth Stealth) GetStripTimeModifiers(EntityUid user, EntityUid target, TimeSpan initialTime)
+ ///
+ /// Modify the strip time via events. Raised directed at the item being stripped, the player stripping someone and the player being stripped.
+ ///
+ public (TimeSpan Time, ThievingStealth Stealth) GetStripTimeModifiers(EntityUid user, EntityUid targetPlayer, EntityUid? targetItem, TimeSpan initialTime)
{
- var userEv = new BeforeStripEvent(initialTime);
+ var itemEv = new BeforeItemStrippedEvent(initialTime);
+ 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
index 0000000000..bb7ff0206f
--- /dev/null
+++ b/Resources/Locale/en-US/clothing/components/self-unremovable-clothing-component.ftl
@@ -0,0 +1 @@
+comp-self-unremovable-clothing = This cannot be removed without outside help.
diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl
index 620d9bfcdf..55a255ac62 100644
--- a/Resources/Locale/en-US/research/technologies.ftl
+++ b/Resources/Locale/en-US/research/technologies.ftl
@@ -27,6 +27,7 @@ research-technology-basic-weapons = Basic 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-practice-ammunition = Practice Ammunition
research-technology-shrapnel-munitions = Shrapnel Munitions
research-technology-advanced-weapons = Advanced Weapons
diff --git a/Resources/Migrations/eeMigration.yml b/Resources/Migrations/eeMigration.yml
index 30884009d6..9810f61b62 100644
--- a/Resources/Migrations/eeMigration.yml
+++ b/Resources/Migrations/eeMigration.yml
@@ -143,3 +143,6 @@ SpeedLoaderRifleHeavyRubber: SpeedLoaderRifleHeavy
WeaponRifleGestioRubber: WeaponRifleGestio
WeaponRifleNovaliteC1Rubber: WeaponRifleNovaliteC1
WeaponSniperRepeaterNonlethal: WeaponSniperRepeater
+
+# 2025-06-09
+ShockCollar: ClothingNeckShockCollar
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/security.yml b/Resources/Prototypes/Catalog/Fills/Lockers/security.yml
index b5678fd72a..9a50363ec4 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/security.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/security.yml
@@ -21,7 +21,10 @@
- id: ClothingOuterHardsuitCombatWarden # WD EDIT: ClothingOuterHardsuitCombatWarden -> ClothingOuterHardsuitWarden
- id: HoloprojectorSecurity
- id: BookSpaceLaw
- # - id: ClothingEyesHudSecurity - WD EDIT
+ - id: ClothingNeckShockCollar
+ amount: 2
+ - id: RemoteSignaller
+ amount: 2
- id: BoxPDAPrisoner
- id: ClothingShoesBootsWinterWarden
- id: BoxEncryptionKeyPrisoner
@@ -56,7 +59,10 @@
- id: DoorRemoteArmory
- id: HoloprojectorSecurity
- id: BookSpaceLaw
- # - id: ClothingEyesHudSecurity - WD EDIT
+ - id: ClothingNeckShockCollar
+ amount: 2
+ - id: RemoteSignaller
+ amount: 2
- id: BoxPDAPrisoner
- id: ClothingShoesBootsWinterWarden
- id: BoxEncryptionKeyPrisoner
diff --git a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml
index 645e9db503..c4f090c2b6 100644
--- a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml
+++ b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml
@@ -348,6 +348,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
diff --git a/Resources/Prototypes/Entities/Objects/Devices/shock_collar.yml b/Resources/Prototypes/Entities/Objects/Devices/shock_collar.yml
new file mode 100644
index 0000000000..22f2d097fc
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Devices/shock_collar.yml
@@ -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
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 74adc977ec..c378bbf044 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -1000,8 +1000,7 @@
- WeaponFlareGunSecurity
- WeaponLaserCarbinePractice
- Zipties
- - GrenadeFlashBang # Goobstation
- - ShockCollar
+ - GrenadeFlashBang
# # DeltaV - .38 special ammo - Add various .38 special ammo to security techfab # WWDP disable "special"
# - MagazineBoxSpecial
# - MagazineBoxSpecialPractice
@@ -1101,9 +1100,8 @@
- WeaponLaserCannon
- WeaponLaserCarbine
- ClothingEyesNightVisionSecurityGoggles
- - ClothingHeadHelmetInsulated # Nyanotrasen - Insulative headgear
- - ClothingHeadCage # Nyanotrasen - Insulative headgear
- - ShockCollar # Nyanotrasen - Shock Collar
+ - ClothingHeadHelmetInsulated
+ - ClothingHeadCage
- WeaponXrayCannon
- WeaponEnergyGun
- WeaponEnergyGunMini
@@ -1166,6 +1164,7 @@
- MagazineUniversalMagnumIncendiary
- MagazineUniversalMagnumShrapnel
- WeaponPistolUniversal
+ - ClothingBackpackElectropack
# WD EDIT START
- MagazineShotgunLaser
- BoxLaser
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Random/devices.yml b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Random/devices.yml
index fde726ed03..2a334ef5e6 100644
--- a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Random/devices.yml
+++ b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/Random/devices.yml
@@ -115,7 +115,7 @@
- TelecomServerCircuitboard
- MiniGravityGeneratorCircuitboard
- Portafib
- - ShockCollar
+ - ClothingNeckShockCollar
- GlimmerMonitorCartridge
- PotatoAIChip
- CargoTelepadMachineCircuitboard
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml
deleted file mode 100644
index 1266a721fe..0000000000
--- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/shock_collar.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-- type: entity
- parent: ClothingNeckBase
- id: ShockCollar
- name: shock collar
- description: Shocking. # DeltaV: sprite is fine
- components:
- - type: Sprite
- sprite: Nyanotrasen/Clothing/Neck/Misc/shock.rsi
- - type: Clothing
- sprite: Nyanotrasen/Clothing/Neck/Misc/shock.rsi
- equipDelay: 1
- unequipDelay: 10 # It's a collar meant to be used on prisoners (or not), so it probably has some sort of safety.
- - type: ShockCollar
- - type: UseDelay
- delay: 3 # DeltaV: prevent clocks instakilling people
- - type: TriggerOnSignal
- - type: DeviceNetwork
- deviceNetId: Wireless
- receiveFrequencyId: BasicDevice
- - type: WirelessNetworkConnection
- range: 200
- - type: DeviceLinkSink
- ports:
- - Trigger
diff --git a/Resources/Prototypes/Nyanotrasen/Recipes/Lathes/security.yml b/Resources/Prototypes/Nyanotrasen/Recipes/Lathes/security.yml
index 34aa7e7ce8..ac6a9395b3 100644
--- a/Resources/Prototypes/Nyanotrasen/Recipes/Lathes/security.yml
+++ b/Resources/Prototypes/Nyanotrasen/Recipes/Lathes/security.yml
@@ -17,18 +17,6 @@
Steel: 400
Bluespace: 20
-- type: latheRecipe
- id: ShockCollar
- icon:
- sprite: Nyanotrasen/Clothing/Neck/Misc/shock.rsi
- state: icon
- result: ShockCollar
- completetime: 2
- materials:
- Steel: 300
- Glass: 100
- Plastic: 100
-
- type: latheRecipe
id: ShellSoulbreaker
icon:
diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml
index 4db5b4e54e..9c61d0a803 100644
--- a/Resources/Prototypes/Objectives/objectiveGroups.yml
+++ b/Resources/Prototypes/Objectives/objectiveGroups.yml
@@ -17,14 +17,14 @@
NukeDiskStealObjective: 1
MagbootsStealObjective: 1
CorgiMeatStealObjective: 1
- MantisKnifeStealObjective: 1 # Nyanotrasen - ForensicMantis steal objective, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml
+ MantisKnifeStealObjective: 1
ClipboardStealObjective: 1
CaptainGunStealObjective: 0.5
NTRepGunStealObjective: 0.5
CaptainJetpackStealObjective: 0.5
HandTeleporterStealObjective: 0.5
- LOLuckyBillStealObjective: 0.5 # DeltaV - LO steal objective, see Resources/Prototypes/DeltaV/Objectives/traitor.yml
- HoPBookIanDossierStealObjective: 1 # DeltaV - HoP steal objective, see Resources/Prototypes/DeltaV/Objectives/traitor.yml
+ LOLuckyBillStealObjective: 0.5
+ HoPBookIanDossierStealObjective: 1
HoSGunStealObjective: 0.5
StealSupermatterSliverObjective: 0.5
EnergyShotgunStealObjective: 0.5
@@ -47,7 +47,7 @@
weights:
# RandomTraitorAliveObjective: 1 # WWDP - disabled because it was very boring
RandomTraitorProgressObjective: 1
- # RaiseGlimmerObjective: 0.5 # Nyanotrasen - Raise glimmer to a target amount, see Resources/Prototypes/Nyanotrasen/Objectives/traitor.yml
+ # RaiseGlimmerObjective: 0.5
#Thief groups
- type: weightedRandom
@@ -65,32 +65,33 @@
- type: weightedRandom
id: ThiefObjectiveGroupCollection
weights:
- HeadCloakStealCollectionObjective: 1 #command
+ HeadCloakStealCollectionObjective: 1 #command
HeadBedsheetStealCollectionObjective: 1
StampStealCollectionObjective: 1
DoorRemoteStealCollectionObjective: 1
- TechnologyDiskStealCollectionObjective: 1 #rnd
- FigurineStealCollectionObjective: 0.3 #service
+ TechnologyDiskStealCollectionObjective: 1 #rnd
+ FigurineStealCollectionObjective: 0.3 #service
IDCardsStealCollectionObjective: 1
LAMPStealCollectionObjective: 2 #only for moth
- type: weightedRandom
id: ThiefObjectiveGroupItem
weights:
- ForensicScannerStealObjective: 1 #sec
+ ForensicScannerStealObjective: 1 #sec
FlippoEngravedLighterStealObjective: 0.5
ClothingHeadHatWardenStealObjective: 1
- ClothingOuterHardsuitVoidParamedStealObjective: 1 #med
+ ClothingNeckShockCollarStealObjective: 1
+ ClothingOuterHardsuitVoidParamedStealObjective: 1 #med
MedicalTechFabCircuitboardStealObjective: 1
ClothingHeadsetAltMedicalStealObjective: 1
- FireAxeStealObjective: 1 #eng
+ FireAxeStealObjective: 1 #eng
AmePartFlatpackStealObjective: 1
- ExpeditionsCircuitboardStealObjective: 1 #sup
+ ExpeditionsCircuitboardStealObjective: 1 #sup
CargoShuttleCircuitboardStealObjective: 1
SalvageShuttleCircuitboardStealObjective: 1
- ClothingEyesHudBeerStealObjective: 1 #srv
+ ClothingEyesHudBeerStealObjective: 1 #srv
BibleStealObjective: 1
- ClothingNeckGoldmedalStealObjective: 1 #other
+ ClothingNeckGoldmedalStealObjective: 1 #other
ClothingNeckClownmedalStealObjective: 0.5
- type: weightedRandom
diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml
index dfd3481c96..b614558f3f 100644
--- a/Resources/Prototypes/Objectives/stealTargetGroups.yml
+++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml
@@ -279,6 +279,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
diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml
index 2a26ec2d7b..aef30d1b58 100644
--- a/Resources/Prototypes/Objectives/thief.yml
+++ b/Resources/Prototypes/Objectives/thief.yml
@@ -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
diff --git a/Resources/Prototypes/Recipes/Lathes/security.yml b/Resources/Prototypes/Recipes/Lathes/security.yml
index 9f35cb9490..5d5e2e238d 100644
--- a/Resources/Prototypes/Recipes/Lathes/security.yml
+++ b/Resources/Prototypes/Recipes/Lathes/security.yml
@@ -125,6 +125,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
diff --git a/Resources/Prototypes/Research/arsenal.yml b/Resources/Prototypes/Research/arsenal.yml
index 9883965a01..bbe87369ad 100644
--- a/Resources/Prototypes/Research/arsenal.yml
+++ b/Resources/Prototypes/Research/arsenal.yml
@@ -128,6 +128,18 @@
- BoxFrag
# TODO: Add "Explosive Ammunition" to this tech to make it waaaay more interesting.
+- 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
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
index 0000000000000000000000000000000000000000..3ea6cdc4b05c396229eb4d75f858c4747ac93525
GIT binary patch
literal 594
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9
z?C1WI$O`0#1o(uwCM6|hWMr6`nc3Od$;im$w_w@9fIB{Zlc(}8(vzC^Y
zzrX+V>C;V3)n?8pb#TzHu8MA%oui_nvTN5aFE6i(iV8nJzo@7v6%{FzjtmPI}P7M|h_-a5foPGHl3=T%mYvlE{k_8vg>s
zU$1A(_{kSFm)-B)9*O!>OdQvu9AvXkzTr6XJAB?J_YKeMHvE(|S<++vO7g<~Z(^Sr
z)_>P|!r-*}{4J%UQInW9*>M=@IH$BHZkWPaQ~dJYF7G_%Kkf?qT&nu7&XC-o&Z^+%K(?wqq<139DE3;I@oly48C>m*L0tIg=+E
zGx~8en6KQlvvUK}ht;-BLAIVOZxlkAjwruj&)L)L8_D?2p7mX!Rjkt4`G22#&Qedv
z=L%?;P|siSpV6Rq-j072Qi8xx=1Yz6O!M_+&;qhKfEWZW1y2T1p00i_>zopr0MD@O
AUH||9
literal 0
HcmV?d00001
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
index 0000000000000000000000000000000000000000..b4b755e0082d7d553160ab8724fc32aefea508b8
GIT binary patch
literal 457
zcmeAS@N?(olHy`uVBq!ia0vp^2|%pC!3-pC$@QiIDaPU;cPEB*=VV?2Ic5PqA+Ba-
zX12Dr6%`e&t*x%EuF=uaE0vWOF)^8%s;Q_*&74tMT@~%%pucL@tbk?sjx=&p~iu?XPed^+;7Anq3*n*)4W*aj>`(Q4Ii@_3L3qq_1NF4lCGCf
zU}o%`(^IqN;;HE7pvKdpFF1YnNHG+wJJ4z0FzLXF-?AGrs)80ahBrToQJJd2*|W#A
zA;^*Mvha+G{mlAYM!P0+@$Q+oFUGOQaA{1VH2>5fBl~A#0=&?Rk11!ob4>u@o}F@AM8D-6RQxt
zWHSp}9Pf;8{ZBflvbgQ5=XRNk44ofy`glX(f`u%tWsIx;Y9
z?C1WI$O`1E1o(uw#>K_i+1cgf*p+6*>Rw~(KSghd%>YEF%Fw_F7+oioDvZ*SbO`=Gv0`AcR88z10tW*v3=cR
zyP~y4o?9zl`ugexM)qPaew6NJn#Q+4!HFwq!4d^lFRnU)8@!2)zU(SHJUf}E^JQGy
zcCf*pUExFNN7g0G0yoSg7+x~4Y~y8fuwrP;ZDyRn_k-s{`;PiWwN?xEC)`S404lnZ
z7an89;Mg<0>6%?f^vc`TB^m#K-sMY;@J#ddWdH>i2M~k6rQpdR%G1@)Wt~$(69D&y
Bn{xmF
literal 0
HcmV?d00001
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
index 0000000000000000000000000000000000000000..26901ce4c9aa65f2f2b4376e79e529f822edfb4a
GIT binary patch
literal 441
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9
z?C1WI$O`1E1o(uw#>K_i+1V{(V#>+MnK*HxkEf@psakba^voHh4i5TST3SGbiRXD%
z0x6!7Aiv=M2*4n8|J*sCIA?)JWHAE+-(e7DJf6QI1t|E&)5S3)!u{>E(?ZP#9IlE9
zYft|FpTAT{_1Z~i^Vov0>y2|d^Y%=Td&DHpp;yrOA-sw4`cX}f4k_z~YUQ$SpirYexCX3?7e
zzqd{*Fx6o-uh8$$ZXe<*OH~qyvEd=1Yz6O!M_+0EHU|5QD&_;K?A$)78&qol`;+
E0L)3E*8l(j
literal 0
HcmV?d00001
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
index 0000000000..4e7738117e
--- /dev/null
+++ b/Resources/Textures/Clothing/Back/Backpacks/electropack.rsi/meta.json
@@ -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
index 0000000000000000000000000000000000000000..ffca3249f13d35ed449938c85fc67b5c0e740977
GIT binary patch
literal 465
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z3q4&NLn`LH
zy=9o!Y#_q+z&=!8U}f>7IE~{c9L(|#xQUx7RlYeSI6=TYA>q`4mg@^R+WKVgEHvDD
zY1Jdig*yM$T{$Fw+Ugkn+B?BCg0+=pp`3Mb4eyNykE#G-Cus!bxue(n@Yoc
z4I3WjWdGlvw}nl!G@HG)#Czi5e;wPubJ#ZUr)xZVC|E1wer&E}gqH-H+b?@{VAz1c
uqKo2e_qlSq7pxNo#spt#glC$sFM}44%>l$9a4C2)i1Kvxb6Mw<&;$VGYr@(9
literal 0
HcmV?d00001
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
index 0000000000000000000000000000000000000000..f8e0a9cb8e4fab549dd7fe5de64098076d68774a
GIT binary patch
literal 800
zcmV+*1K<3KP)Px%z)3_wR9J=Wls{u6bN2Al~8x^Rx*@e4^4vUpo=M?7D666cDN4F2`Tzxr=ifn-y+?+cklb&
zy>}1hm}8E=fUehM()yp1ce}?@k=|V27WZZ$^#2!&TL@tWe1tG57PmsacNU-sb-gAf
zNJR#a$*iI4HJQn*;kQeW{&Uj=+@D6S0-w30lZoy5q*BY?dTHq)J4TC_dd(A5EN%fv
z!)PtU@k}iNz>d-4%e#G#Ow-mwU$v)hWL889(Dj-ejV=+w^aA@c7sAA{#(}TGWMX?a
zC4|Y2(Ml{uNPw=_WTmp}1=F;3J~rQwt2eN$F_txEI6MOgd~@{%2k!N&bCZe96;P?{
z#)^pT0e`lB3Z5DwQU@5akzyB48o_7Ad
zMIU*mbC}q`v2#F)c;>Djr&k#c&(wSmA)Q{O+x>{9t@GWreQ?R+I1&XY5jnR99{2`Q
zyS~W%#HwsLSFjc^-XkUxbiy*P$J^?Zc9GL9RCIW0O(JZ+iLn{RsaA14rN$LW=%~1
eDgXcg2mk;800000(o>TF0000b~XebB*P+WhH^I)PTN`TF4>cfG6CslN9%`SH&jmQ&Y{{&B9^a;hwT
z|D^4=kNb&e?VT6v;*w%rm~!W}$+jOp)AW^$=4@O0e50Nf*VVmGXT|+df5Hqj9RmI@
zSh=`Bxc9nb@?P)ljA7=|BnY21WFjY1q;i;y8w2L1zG*xHdlP^L;OEJ$5g89E~&b)tWOfuY?{CNi-H
zMS#=>#UW0jM6Ft!*fK-pQ`6XKVj&@c-{qwH?t9<&?!NC1V*CsEoX>lI)j(0xA{$Wt
zq+r*wR_0qN!O#mHfa5AW-`Saoy*)lAA*R0Co!-*CiDg9r9zM_k_4*dJClyy0uO0AR0WH|fL2|bBW1HM2uEu`qGsFZc@{L-Bnt@5FVfHyvt?NE@F)t)WnFI-Iz{Cgu!uElb%J0)V|E
zK{hQSi)YhygCBu-hl3`%mBh;jdJ+|co6@-PmGW3F%&t;^EmN}q#-~_I%?k8ld
zx}U&5y}|He;bRoo1wPuHo-!C-V0QbM-M*ZE{lN_!0lvPRYMI^st>Uo6Q+%DEsA*oU
zq44R8O|5!&W(0Lw@sAy-i>3dAmHRBLpRd