From d8ae58efa903749314e334278c1a47c0fddd2b16 Mon Sep 17 00:00:00 2001
From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Wed, 28 Aug 2024 10:57:12 +1000
Subject: [PATCH 01/38] Station AI (#30944)

* Station AI overlay

* implement

* Bunch of ports

* Fix a heap of bugs and basic scouting

* helldivers

* Shuffle interactions a bit

* navmap stuff

* Revert "navmap stuff"

This reverts commit d1f89dd4be83233e22cf5dd062b2581f3c6da062.

* AI wires implemented

* Fix examines

* Optimise the overlay significantly

* Back to old static

* BUI radial working

* lots of work

* Saving work

* thanks fork

* alright

* pc

* AI upload console

* AI upload

* stuff

* Fix copy-paste shitcode

* AI actions

* navmap work

* Fixes

* first impressions

* a

* reh

* Revert "navmap work"

This reverts commit 6f63fea6e9245e189f368f97be3e32e9b210580e.

* OD

* radar

* weh

* Fix examines

* scoop mine eyes

* fixes

* reh

* Optimise

* Final round of optimisations

* Fixes

* fixes
---
 Content.Client/Chat/UI/EmotesMenu.xaml.cs     |  13 +-
 .../Laws/SiliconLawEditUi/SiliconLawEui.cs    |   2 +-
 .../StationAi/StationAiBoundUserInterface.cs  |  28 ++
 .../Silicons/StationAi/StationAiMenu.xaml     |  13 +
 .../Silicons/StationAi/StationAiMenu.xaml.cs  | 128 ++++++
 .../Silicons/StationAi/StationAiOverlay.cs    |  23 +-
 .../StationAi/StationAiSystem.Airlock.cs      |  30 ++
 .../StationAi/StationAiSystem.Light.cs        |  32 ++
 .../Silicons/StationAi/StationAiSystem.cs     |   6 +-
 Content.Client/Verbs/VerbSystem.cs            |   5 +-
 .../Administration/Systems/AdminVerbSystem.cs |   1 +
 .../CommunicationsConsoleSystem.cs            |   4 -
 .../DeviceNetworkRequiresPowerSystem.cs       |   1 -
 .../Light/EntitySystems/LitOnPoweredSystem.cs |   1 -
 .../Light/EntitySystems/PoweredLightSystem.cs |   1 -
 Content.Server/Mind/MindSystem.cs             |   4 +-
 .../Power/EntitySystems/ChargerSystem.cs      |  35 +-
 .../Power/EntitySystems/PowerNetSystem.cs     |   1 -
 .../Power/Generation/Teg/TegSystem.cs         |   1 -
 .../Power/Generator/GasPowerReceiverSystem.cs |   1 -
 .../Silicons/Laws/SiliconLawSystem.cs         |  35 +-
 .../StationAi/AiInteractWireAction.cs         |  37 ++
 .../Silicons/StationAi/AiVisionWireAction.cs  |  40 ++
 .../Silicons/StationAi/StationAiSystem.cs     |  76 ++++
 .../Sound/SpamEmitSoundRequirePowerSystem.cs  |   1 -
 .../Station/Systems/StationSpawningSystem.cs  |  23 +
 .../Melee/EnergySword/EnergySwordSystem.cs    |   2 +-
 .../ArtifactElectricityTriggerSystem.cs       |   2 +-
 .../ActionBlocker/ActionBlockerSystem.cs      |  15 +
 .../Climbing/Systems/ClimbSystem.cs           |  20 +
 .../Configurable/ConfigurationComponent.cs    |   3 +-
 Content.Shared/Doors/AirlockWireStatus.cs     |   2 +-
 Content.Shared/Examine/ExamineSystemShared.cs |  34 +-
 .../Interaction/SharedInteractionSystem.cs    |  67 ++-
 .../LightOnCollideColliderComponent.cs        |  13 +
 .../Components/LightOnCollideComponent.cs     |  11 +
 .../Light/EntitySystems/LightCollideSystem.cs |  82 ++++
 .../EntitySystems/SlimPoweredLightSystem.cs   |   1 -
 Content.Shared/Mind/SharedMindSystem.cs       |   4 +
 .../Components/SiliconLawBoundComponent.cs    |  15 +-
 .../Components/SiliconLawUpdaterComponent.cs  |  17 +
 .../Laws/SharedSiliconLawSystem.Updater.cs    |  17 +
 .../Silicons/Laws/SharedSiliconLawSystem.cs   |   3 +-
 .../SharedStationAiSystem.Airlock.cs          |  25 ++
 .../StationAi/SharedStationAiSystem.Held.cs   | 187 ++++++++
 .../StationAi/SharedStationAiSystem.Light.cs  |  28 ++
 .../StationAi/SharedStationAiSystem.cs        | 412 ++++++++++++++++++
 .../StationAi/StationAiCoreComponent.cs       |  32 ++
 .../StationAi/StationAiHeldComponent.cs       |   9 +
 .../StationAi/StationAiHolderComponent.cs     |  16 +
 .../StationAi/StationAiVisionComponent.cs     |   5 +-
 .../StationAi/StationAiVisionSystem.cs        | 131 ++----
 .../StationAi/StationAiWhitelistComponent.cs  |  13 +
 .../Station/SharedStationSpawningSystem.cs    |   3 +
 .../UserInterface/ActivatableUIComponent.cs   |   8 +-
 .../UserInterface/ActivatableUISystem.cs      |  25 +-
 Content.Shared/Verbs/SharedVerbSystem.cs      |  17 +-
 Content.Shared/Verbs/VerbEvents.cs            |   8 +-
 Content.Shared/Wires/SharedWiresSystem.cs     |  20 +-
 .../Audio/Effects/Footsteps/attributions.yml  |   2 +-
 .../Audio/Effects/Footsteps/borgwalk2.ogg     | Bin 20233 -> 9052 bytes
 .../administration/ui/silicon-law-ui.ftl      |   2 +
 .../Locale/en-US/job/department-desc.ftl      |   1 +
 Resources/Locale/en-US/job/department.ftl     |   1 +
 .../Locale/en-US/job/job-description.ftl      |   1 +
 Resources/Locale/en-US/job/job-names.ftl      |   2 +
 .../Locale/en-US/silicons/station-ai.ftl      |  14 +
 Resources/Maps/Test/dev_map.yml               |   7 +
 Resources/Prototypes/Datasets/Names/ai.yml    |   2 +-
 .../Mobs/Cyborgs/base_borg_chassis.yml        |   3 +
 .../Entities/Mobs/Cyborgs/borg_chassis.yml    |   6 +
 .../Entities/Mobs/NPCs/revenant.yml           |   9 +-
 .../Entities/Mobs/NPCs/simplemob.yml          |   1 +
 .../Entities/Mobs/Player/observer.yml         |  53 ++-
 .../Entities/Mobs/Player/silicon.yml          | 303 +++++++++++++
 .../Prototypes/Entities/Mobs/Species/base.yml |   1 +
 Resources/Prototypes/Entities/Mobs/base.yml   |   7 +
 .../Fun/Instruments/base_instruments.yml      |   2 +-
 .../Entities/Objects/Misc/paper.yml           |   4 +-
 .../Objects/Specific/Robotics/mmi.yml         |   2 +-
 .../Objects/Tools/access_configurator.yml     |   2 +-
 .../Doors/Airlocks/base_structureairlocks.yml |   3 +
 .../Machines/Computers/computers.yml          |  44 ++
 .../Structures/Machines/Medical/cryo_pod.yml  |   2 +-
 .../Entities/Structures/Power/apc.yml         |   1 +
 .../Structures/Wallmounts/intercom.yml        |   1 +
 .../Wallmounts/surveillance_camera.yml        |  24 +
 .../Entities/Structures/Wallmounts/timer.yml  |   1 +
 .../Prototypes/Roles/Jobs/Science/borg.yml    |  15 +
 .../Prototypes/Roles/Jobs/departments.yml     |  10 +-
 .../Prototypes/Roles/play_time_trackers.yml   |   3 +
 Resources/Prototypes/StatusIcon/job.yml       |   8 +
 Resources/Prototypes/Wires/layouts.yml        |   4 +-
 Resources/Prototypes/tags.yml                 |   3 +
 .../Actions/actions_ai.rsi/ai_core.png        | Bin 0 -> 269 bytes
 .../Actions/actions_ai.rsi/camera_light.png   | Bin 0 -> 309 bytes
 .../Actions/actions_ai.rsi/crew_monitor.png   | Bin 0 -> 295 bytes
 .../Actions/actions_ai.rsi/manifest.png       | Bin 0 -> 245 bytes
 .../Actions/actions_ai.rsi/meta.json          |  26 ++
 .../Actions/actions_ai.rsi/state_laws.png     | Bin 0 -> 241 bytes
 .../Misc/job_icons.rsi/StationAi.png          | Bin 0 -> 204 bytes
 .../Interface/Misc/job_icons.rsi/meta.json    |   5 +-
 .../Textures/Interface/noise.rsi/meta.json    |  58 +++
 .../Textures/Interface/noise.rsi/noise.png    | Bin 0 -> 45602 bytes
 .../Silicon/output.rsi/ai-banned-unshaded.png | Bin 0 -> 820 bytes
 .../Mobs/Silicon/output.rsi/ai-banned.png     | Bin 0 -> 1589 bytes
 .../output.rsi/ai-banned_dead-unshaded.png    | Bin 0 -> 109 bytes
 .../Silicon/output.rsi/ai-banned_dead.png     | Bin 0 -> 463 bytes
 .../Silicon/output.rsi/ai-empty-unshaded.png  | Bin 0 -> 109 bytes
 .../Mobs/Silicon/output.rsi/ai-empty.png      | Bin 0 -> 451 bytes
 .../output.rsi/ai-holo-old-unshaded.png       | Bin 0 -> 2483 bytes
 .../Mobs/Silicon/output.rsi/ai-holo-old.png   | Bin 0 -> 7280 bytes
 .../Mobs/Silicon/output.rsi/ai-unshaded.png   | Bin 0 -> 6255 bytes
 .../Textures/Mobs/Silicon/output.rsi/ai.png   | Bin 0 -> 6761 bytes
 .../Silicon/output.rsi/ai_dead-unshaded.png   | Bin 0 -> 453 bytes
 .../Mobs/Silicon/output.rsi/ai_dead.png       | Bin 0 -> 453 bytes
 .../Silicon/output.rsi/default-unshaded.png   | Bin 0 -> 2005 bytes
 .../Mobs/Silicon/output.rsi/default.png       | Bin 0 -> 2005 bytes
 .../output.rsi/floating_face-unshaded.png     | Bin 0 -> 721 bytes
 .../Mobs/Silicon/output.rsi/floating_face.png | Bin 0 -> 721 bytes
 .../Silicon/output.rsi/horror-unshaded.png    | Bin 0 -> 1777 bytes
 .../Mobs/Silicon/output.rsi/horror.png        | Bin 0 -> 1404 bytes
 .../Mobs/Silicon/output.rsi/meta.json         |   1 +
 .../output.rsi/xeno_queen-unshaded.png        | Bin 0 -> 2484 bytes
 .../Mobs/Silicon/output.rsi/xeno_queen.png    | Bin 0 -> 2484 bytes
 .../Mobs/Silicon/station_ai.rsi/ai.png        | Bin 0 -> 9757 bytes
 .../Mobs/Silicon/station_ai.rsi/ai_dead.png   | Bin 0 -> 4405 bytes
 .../Mobs/Silicon/station_ai.rsi/ai_empty.png  | Bin 0 -> 4405 bytes
 .../Mobs/Silicon/station_ai.rsi/base.png      | Bin 0 -> 4421 bytes
 .../Mobs/Silicon/station_ai.rsi/default.png   | Bin 0 -> 2082 bytes
 .../Mobs/Silicon/station_ai.rsi/meta.json     |  52 +++
 .../Objects/Devices/ai_card.rsi/base.png      | Bin 0 -> 4432 bytes
 .../Objects/Devices/ai_card.rsi/empty.png     | Bin 0 -> 4292 bytes
 .../Objects/Devices/ai_card.rsi/full.png      | Bin 0 -> 5121 bytes
 .../Devices/ai_card.rsi/inhand-left.png       | Bin 0 -> 306 bytes
 .../Devices/ai_card.rsi/inhand-right.png      | Bin 0 -> 316 bytes
 .../Objects/Devices/ai_card.rsi/meta.json     |  58 +++
 .../output.rsi/aicard-full-unshaded.png       | Bin 0 -> 777 bytes
 .../Devices/output.rsi/aicard-full.png        | Bin 0 -> 1746 bytes
 .../Devices/output.rsi/aicard-unshaded.png    | Bin 0 -> 138 bytes
 .../Objects/Devices/output.rsi/aicard.png     | Bin 0 -> 414 bytes
 .../Objects/Devices/output.rsi/meta.json      |   1 +
 142 files changed, 2278 insertions(+), 256 deletions(-)
 create mode 100644 Content.Client/Silicons/StationAi/StationAiBoundUserInterface.cs
 create mode 100644 Content.Client/Silicons/StationAi/StationAiMenu.xaml
 create mode 100644 Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs
 create mode 100644 Content.Client/Silicons/StationAi/StationAiSystem.Airlock.cs
 create mode 100644 Content.Client/Silicons/StationAi/StationAiSystem.Light.cs
 create mode 100644 Content.Server/Silicons/StationAi/AiInteractWireAction.cs
 create mode 100644 Content.Server/Silicons/StationAi/AiVisionWireAction.cs
 create mode 100644 Content.Server/Silicons/StationAi/StationAiSystem.cs
 create mode 100644 Content.Shared/Light/Components/LightOnCollideColliderComponent.cs
 create mode 100644 Content.Shared/Light/Components/LightOnCollideComponent.cs
 create mode 100644 Content.Shared/Light/EntitySystems/LightCollideSystem.cs
 create mode 100644 Content.Shared/Silicons/Laws/Components/SiliconLawUpdaterComponent.cs
 create mode 100644 Content.Shared/Silicons/Laws/SharedSiliconLawSystem.Updater.cs
 create mode 100644 Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs
 create mode 100644 Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs
 create mode 100644 Content.Shared/Silicons/StationAi/SharedStationAiSystem.Light.cs
 create mode 100644 Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs
 create mode 100644 Content.Shared/Silicons/StationAi/StationAiCoreComponent.cs
 create mode 100644 Content.Shared/Silicons/StationAi/StationAiHeldComponent.cs
 create mode 100644 Content.Shared/Silicons/StationAi/StationAiHolderComponent.cs
 create mode 100644 Content.Shared/Silicons/StationAi/StationAiWhitelistComponent.cs
 create mode 100644 Resources/Locale/en-US/silicons/station-ai.ftl
 create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/ai_core.png
 create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/camera_light.png
 create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/crew_monitor.png
 create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/manifest.png
 create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/meta.json
 create mode 100644 Resources/Textures/Interface/Actions/actions_ai.rsi/state_laws.png
 create mode 100644 Resources/Textures/Interface/Misc/job_icons.rsi/StationAi.png
 create mode 100644 Resources/Textures/Interface/noise.rsi/meta.json
 create mode 100644 Resources/Textures/Interface/noise.rsi/noise.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-banned-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-banned.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-banned_dead-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-banned_dead.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-empty-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-empty.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-holo-old-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-holo-old.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai_dead-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/ai_dead.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/default-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/default.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/floating_face-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/floating_face.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/horror-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/horror.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/meta.json
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/xeno_queen-unshaded.png
 create mode 100644 Resources/Textures/Mobs/Silicon/output.rsi/xeno_queen.png
 create mode 100644 Resources/Textures/Mobs/Silicon/station_ai.rsi/ai.png
 create mode 100644 Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_dead.png
 create mode 100644 Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_empty.png
 create mode 100644 Resources/Textures/Mobs/Silicon/station_ai.rsi/base.png
 create mode 100644 Resources/Textures/Mobs/Silicon/station_ai.rsi/default.png
 create mode 100644 Resources/Textures/Mobs/Silicon/station_ai.rsi/meta.json
 create mode 100644 Resources/Textures/Objects/Devices/ai_card.rsi/base.png
 create mode 100644 Resources/Textures/Objects/Devices/ai_card.rsi/empty.png
 create mode 100644 Resources/Textures/Objects/Devices/ai_card.rsi/full.png
 create mode 100644 Resources/Textures/Objects/Devices/ai_card.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Objects/Devices/ai_card.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Objects/Devices/ai_card.rsi/meta.json
 create mode 100644 Resources/Textures/Objects/Devices/output.rsi/aicard-full-unshaded.png
 create mode 100644 Resources/Textures/Objects/Devices/output.rsi/aicard-full.png
 create mode 100644 Resources/Textures/Objects/Devices/output.rsi/aicard-unshaded.png
 create mode 100644 Resources/Textures/Objects/Devices/output.rsi/aicard.png
 create mode 100644 Resources/Textures/Objects/Devices/output.rsi/meta.json

diff --git a/Content.Client/Chat/UI/EmotesMenu.xaml.cs b/Content.Client/Chat/UI/EmotesMenu.xaml.cs
index 3340755343..f3b7837f21 100644
--- a/Content.Client/Chat/UI/EmotesMenu.xaml.cs
+++ b/Content.Client/Chat/UI/EmotesMenu.xaml.cs
@@ -19,9 +19,6 @@ public sealed partial class EmotesMenu : RadialMenu
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
     [Dependency] private readonly ISharedPlayerManager _playerManager = default!;
 
-    private readonly SpriteSystem _spriteSystem;
-    private readonly EntityWhitelistSystem _whitelistSystem;
-
     public event Action<ProtoId<EmotePrototype>>? OnPlayEmote;
 
     public EmotesMenu()
@@ -29,8 +26,8 @@ public EmotesMenu()
         IoCManager.InjectDependencies(this);
         RobustXamlLoader.Load(this);
 
-        _spriteSystem = _entManager.System<SpriteSystem>();
-        _whitelistSystem = _entManager.System<EntityWhitelistSystem>();
+        var spriteSystem = _entManager.System<SpriteSystem>();
+        var whitelistSystem = _entManager.System<EntityWhitelistSystem>();
 
         var main = FindControl<RadialContainer>("Main");
 
@@ -40,8 +37,8 @@ public EmotesMenu()
             var player = _playerManager.LocalSession?.AttachedEntity;
             if (emote.Category == EmoteCategory.Invalid ||
                 emote.ChatTriggers.Count == 0 ||
-                !(player.HasValue && _whitelistSystem.IsWhitelistPassOrNull(emote.Whitelist, player.Value)) ||
-                _whitelistSystem.IsBlacklistPass(emote.Blacklist, player.Value))
+                !(player.HasValue && whitelistSystem.IsWhitelistPassOrNull(emote.Whitelist, player.Value)) ||
+                whitelistSystem.IsBlacklistPass(emote.Blacklist, player.Value))
                 continue;
 
             if (!emote.Available &&
@@ -63,7 +60,7 @@ public EmotesMenu()
             {
                 VerticalAlignment = VAlignment.Center,
                 HorizontalAlignment = HAlignment.Center,
-                Texture = _spriteSystem.Frame0(emote.Icon),
+                Texture = spriteSystem.Frame0(emote.Icon),
                 TextureScale = new Vector2(2f, 2f),
             };
 
diff --git a/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawEui.cs b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawEui.cs
index a4d59d1f31..03c74032f7 100644
--- a/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawEui.cs
+++ b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawEui.cs
@@ -6,7 +6,7 @@ namespace Content.Client.Silicons.Laws.SiliconLawEditUi;
 
 public sealed class SiliconLawEui : BaseEui
 {
-    public readonly EntityManager _entityManager = default!;
+    private readonly EntityManager _entityManager;
 
     private SiliconLawUi _siliconLawUi;
     private EntityUid _target;
diff --git a/Content.Client/Silicons/StationAi/StationAiBoundUserInterface.cs b/Content.Client/Silicons/StationAi/StationAiBoundUserInterface.cs
new file mode 100644
index 0000000000..68318305a0
--- /dev/null
+++ b/Content.Client/Silicons/StationAi/StationAiBoundUserInterface.cs
@@ -0,0 +1,28 @@
+using Content.Shared.Silicons.StationAi;
+using Robust.Client.UserInterface;
+
+namespace Content.Client.Silicons.StationAi;
+
+public sealed class StationAiBoundUserInterface : BoundUserInterface
+{
+    private StationAiMenu? _menu;
+
+    public StationAiBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+    {
+    }
+
+    protected override void Open()
+    {
+        base.Open();
+        _menu = this.CreateWindow<StationAiMenu>();
+        _menu.Track(Owner);
+
+        _menu.OnAiRadial += args =>
+        {
+            SendPredictedMessage(new StationAiRadialMessage()
+            {
+                Event = args,
+            });
+        };
+    }
+}
diff --git a/Content.Client/Silicons/StationAi/StationAiMenu.xaml b/Content.Client/Silicons/StationAi/StationAiMenu.xaml
new file mode 100644
index 0000000000..d56fc83289
--- /dev/null
+++ b/Content.Client/Silicons/StationAi/StationAiMenu.xaml
@@ -0,0 +1,13 @@
+<ui:RadialMenu xmlns="https://spacestation14.io"
+                xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
+                BackButtonStyleClass="RadialMenuBackButton"
+                CloseButtonStyleClass="RadialMenuCloseButton"
+                VerticalExpand="True"
+                HorizontalExpand="True"
+                MinSize="450 450">
+
+    <!-- Main -->
+    <ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" Radius="64" ReserveSpaceForHiddenChildren="False">
+    </ui:RadialContainer>
+
+</ui:RadialMenu>
diff --git a/Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs b/Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs
new file mode 100644
index 0000000000..24a802a60f
--- /dev/null
+++ b/Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs
@@ -0,0 +1,128 @@
+using System.Numerics;
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Silicons.StationAi;
+using Robust.Client.AutoGenerated;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Timing;
+
+namespace Content.Client.Silicons.StationAi;
+
+[GenerateTypedNameReferences]
+public sealed partial class StationAiMenu : RadialMenu
+{
+    [Dependency] private readonly IClyde _clyde = default!;
+    [Dependency] private readonly IEntityManager _entManager = default!;
+    [Dependency] private readonly IEyeManager _eyeManager = default!;
+
+    public event Action<BaseStationAiAction>? OnAiRadial;
+
+    private EntityUid _tracked;
+
+    public StationAiMenu()
+    {
+        IoCManager.InjectDependencies(this);
+        RobustXamlLoader.Load(this);
+    }
+
+    public void Track(EntityUid owner)
+    {
+        _tracked = owner;
+
+        if (!_entManager.EntityExists(_tracked))
+        {
+            Close();
+            return;
+        }
+
+        BuildButtons();
+        UpdatePosition();
+    }
+
+    private void BuildButtons()
+    {
+        var ev = new GetStationAiRadialEvent();
+        _entManager.EventBus.RaiseLocalEvent(_tracked, ref ev);
+
+        var main = FindControl<RadialContainer>("Main");
+        main.DisposeAllChildren();
+        var sprites = _entManager.System<SpriteSystem>();
+
+        foreach (var action in ev.Actions)
+        {
+            // TODO: This radial boilerplate is quite annoying
+            var button = new StationAiMenuButton(action.Event)
+            {
+                StyleClasses = { "RadialMenuButton" },
+                SetSize = new Vector2(64f, 64f),
+                ToolTip = action.Tooltip != null ? Loc.GetString(action.Tooltip) : null,
+            };
+
+            if (action.Sprite != null)
+            {
+                var texture = sprites.Frame0(action.Sprite);
+                var scale = Vector2.One;
+
+                if (texture.Width <= 32)
+                {
+                    scale *= 2;
+                }
+
+                var tex = new TextureRect
+                {
+                    VerticalAlignment = VAlignment.Center,
+                    HorizontalAlignment = HAlignment.Center,
+                    Texture = texture,
+                    TextureScale = scale,
+                };
+
+                button.AddChild(tex);
+            }
+
+            button.OnPressed += args =>
+            {
+                OnAiRadial?.Invoke(action.Event);
+                Close();
+            };
+            main.AddChild(button);
+        }
+    }
+
+    protected override void FrameUpdate(FrameEventArgs args)
+    {
+        base.FrameUpdate(args);
+        UpdatePosition();
+    }
+
+    private void UpdatePosition()
+    {
+        if (!_entManager.TryGetComponent(_tracked, out TransformComponent? xform))
+        {
+            Close();
+            return;
+        }
+
+        if (!xform.Coordinates.IsValid(_entManager))
+        {
+            Close();
+            return;
+        }
+
+        var coords = _entManager.System<SpriteSystem>().GetSpriteScreenCoordinates((_tracked, null, xform));
+
+        if (!coords.IsValid)
+        {
+            Close();
+            return;
+        }
+
+        OpenScreenAt(coords.Position, _clyde);
+    }
+}
+
+public sealed class StationAiMenuButton(BaseStationAiAction action) : RadialMenuTextureButton
+{
+    public BaseStationAiAction Action = action;
+}
diff --git a/Content.Client/Silicons/StationAi/StationAiOverlay.cs b/Content.Client/Silicons/StationAi/StationAiOverlay.cs
index efa1b8dbef..15a8a3a63f 100644
--- a/Content.Client/Silicons/StationAi/StationAiOverlay.cs
+++ b/Content.Client/Silicons/StationAi/StationAiOverlay.cs
@@ -4,7 +4,9 @@
 using Robust.Client.Player;
 using Robust.Shared.Enums;
 using Robust.Shared.Map.Components;
+using Robust.Shared.Physics;
 using Robust.Shared.Prototypes;
+using Robust.Shared.Timing;
 
 namespace Content.Client.Silicons.StationAi;
 
@@ -12,6 +14,7 @@ public sealed class StationAiOverlay : Overlay
 {
     [Dependency] private readonly IClyde _clyde = default!;
     [Dependency] private readonly IEntityManager _entManager = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
     [Dependency] private readonly IPlayerManager _player = default!;
     [Dependency] private readonly IPrototypeManager _proto = default!;
 
@@ -22,6 +25,9 @@ public sealed class StationAiOverlay : Overlay
     private IRenderTexture? _staticTexture;
     private IRenderTexture? _stencilTexture;
 
+    private float _updateRate = 1f / 30f;
+    private float _accumulator;
+
     public StationAiOverlay()
     {
         IoCManager.InjectDependencies(this);
@@ -47,19 +53,22 @@ protected override void Draw(in OverlayDrawArgs args)
         _entManager.TryGetComponent(playerEnt, out TransformComponent? playerXform);
         var gridUid = playerXform?.GridUid ?? EntityUid.Invalid;
         _entManager.TryGetComponent(gridUid, out MapGridComponent? grid);
+        _entManager.TryGetComponent(gridUid, out BroadphaseComponent? broadphase);
 
         var invMatrix = args.Viewport.GetWorldToLocalMatrix();
+        _accumulator -= (float) _timing.FrameTime.TotalSeconds;
 
-        if (grid != null)
+        if (grid != null && broadphase != null)
         {
-            // TODO: Pass in attached entity's grid.
-            // TODO: Credit OD on the moved to code
-            // TODO: Call the moved-to code here.
-
-            _visibleTiles.Clear();
             var lookups = _entManager.System<EntityLookupSystem>();
             var xforms = _entManager.System<SharedTransformSystem>();
-            _entManager.System<StationAiVisionSystem>().GetView((gridUid, grid), worldBounds, _visibleTiles);
+
+            if (_accumulator <= 0f)
+            {
+                _accumulator = MathF.Max(0f, _accumulator + _updateRate);
+                _visibleTiles.Clear();
+                _entManager.System<StationAiVisionSystem>().GetView((gridUid, broadphase, grid), worldBounds, _visibleTiles);
+            }
 
             var gridMatrix = xforms.GetWorldMatrix(gridUid);
             var matty =  Matrix3x2.Multiply(gridMatrix, invMatrix);
diff --git a/Content.Client/Silicons/StationAi/StationAiSystem.Airlock.cs b/Content.Client/Silicons/StationAi/StationAiSystem.Airlock.cs
new file mode 100644
index 0000000000..bf6b65a969
--- /dev/null
+++ b/Content.Client/Silicons/StationAi/StationAiSystem.Airlock.cs
@@ -0,0 +1,30 @@
+using Content.Shared.Doors.Components;
+using Content.Shared.Silicons.StationAi;
+using Robust.Shared.Utility;
+
+namespace Content.Client.Silicons.StationAi;
+
+public sealed partial class StationAiSystem
+{
+    private void InitializeAirlock()
+    {
+        SubscribeLocalEvent<DoorBoltComponent, GetStationAiRadialEvent>(OnDoorBoltGetRadial);
+    }
+
+    private void OnDoorBoltGetRadial(Entity<DoorBoltComponent> ent, ref GetStationAiRadialEvent args)
+    {
+        args.Actions.Add(new StationAiRadial()
+        {
+            Sprite = ent.Comp.BoltsDown ?
+                new SpriteSpecifier.Rsi(
+                new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "open") :
+                new SpriteSpecifier.Rsi(
+                new ResPath("/Textures/Structures/Doors/Airlocks/Standard/basic.rsi"), "closed"),
+            Tooltip = ent.Comp.BoltsDown ? Loc.GetString("bolt-open") : Loc.GetString("bolt-close"),
+            Event = new StationAiBoltEvent()
+            {
+                Bolted = !ent.Comp.BoltsDown,
+            }
+        });
+    }
+}
diff --git a/Content.Client/Silicons/StationAi/StationAiSystem.Light.cs b/Content.Client/Silicons/StationAi/StationAiSystem.Light.cs
new file mode 100644
index 0000000000..cf2f613620
--- /dev/null
+++ b/Content.Client/Silicons/StationAi/StationAiSystem.Light.cs
@@ -0,0 +1,32 @@
+using Content.Shared.Item.ItemToggle.Components;
+using Content.Shared.Light.Components;
+using Content.Shared.Silicons.StationAi;
+using Robust.Shared.Utility;
+
+namespace Content.Client.Silicons.StationAi;
+
+public sealed partial class StationAiSystem
+{
+    // Used for surveillance camera lights
+
+    private void InitializePowerToggle()
+    {
+        SubscribeLocalEvent<ItemTogglePointLightComponent, GetStationAiRadialEvent>(OnLightGetRadial);
+    }
+
+    private void OnLightGetRadial(Entity<ItemTogglePointLightComponent> ent, ref GetStationAiRadialEvent args)
+    {
+        if (!TryComp(ent.Owner, out ItemToggleComponent? toggle))
+            return;
+
+        args.Actions.Add(new StationAiRadial()
+        {
+            Tooltip = Loc.GetString("toggle-light"),
+            Sprite = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/light.svg.192dpi.png")),
+            Event = new StationAiLightEvent()
+            {
+                Enabled = !toggle.Activated
+            }
+        });
+    }
+}
diff --git a/Content.Client/Silicons/StationAi/StationAiSystem.cs b/Content.Client/Silicons/StationAi/StationAiSystem.cs
index 2ed0617525..ab9ace3c1d 100644
--- a/Content.Client/Silicons/StationAi/StationAiSystem.cs
+++ b/Content.Client/Silicons/StationAi/StationAiSystem.cs
@@ -5,7 +5,7 @@
 
 namespace Content.Client.Silicons.StationAi;
 
-public sealed partial class StationAiSystem : EntitySystem
+public sealed partial class StationAiSystem : SharedStationAiSystem
 {
     [Dependency] private readonly IOverlayManager _overlayMgr = default!;
     [Dependency] private readonly IPlayerManager _player = default!;
@@ -15,8 +15,8 @@ public sealed partial class StationAiSystem : EntitySystem
     public override void Initialize()
     {
         base.Initialize();
-        // InitializeAirlock();
-        // InitializePowerToggle();
+        InitializeAirlock();
+        InitializePowerToggle();
 
         SubscribeLocalEvent<StationAiOverlayComponent, LocalPlayerAttachedEvent>(OnAiAttached);
         SubscribeLocalEvent<StationAiOverlayComponent, LocalPlayerDetachedEvent>(OnAiDetached);
diff --git a/Content.Client/Verbs/VerbSystem.cs b/Content.Client/Verbs/VerbSystem.cs
index 5f1f49e5fd..2513210e2c 100644
--- a/Content.Client/Verbs/VerbSystem.cs
+++ b/Content.Client/Verbs/VerbSystem.cs
@@ -70,6 +70,7 @@ public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true
 
             // Get entities
             List<EntityUid> entities;
+            var examineFlags = LookupFlags.All & ~LookupFlags.Sensors;
 
             // Do we have to do FoV checks?
             if ((visibility & MenuVisibility.NoFov) == 0)
@@ -85,7 +86,7 @@ public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true
 
                 // Then check every entity
                 entities = new();
-                foreach (var ent in _entityLookup.GetEntitiesInRange(targetPos, EntityMenuLookupSize))
+                foreach (var ent in _entityLookup.GetEntitiesInRange(targetPos, EntityMenuLookupSize, flags: examineFlags))
                 {
                     if (_examine.CanExamine(player.Value, targetPos, Predicate, ent, examiner))
                         entities.Add(ent);
@@ -93,7 +94,7 @@ public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true
             }
             else
             {
-                entities = _entityLookup.GetEntitiesInRange(targetPos, EntityMenuLookupSize).ToList();
+                entities = _entityLookup.GetEntitiesInRange(targetPos, EntityMenuLookupSize, flags: examineFlags).ToList();
             }
 
             if (entities.Count == 0)
diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.cs b/Content.Server/Administration/Systems/AdminVerbSystem.cs
index 1e701794ff..d9ccb730d0 100644
--- a/Content.Server/Administration/Systems/AdminVerbSystem.cs
+++ b/Content.Server/Administration/Systems/AdminVerbSystem.cs
@@ -36,6 +36,7 @@
 using System.Linq;
 using System.Numerics;
 using Content.Server.Silicons.Laws;
+using Content.Shared.Silicons.Laws;
 using Content.Shared.Silicons.Laws.Components;
 using Robust.Server.Player;
 using Robust.Shared.Physics.Components;
diff --git a/Content.Server/Communications/CommunicationsConsoleSystem.cs b/Content.Server/Communications/CommunicationsConsoleSystem.cs
index c3e5b91254..de77d611c3 100644
--- a/Content.Server/Communications/CommunicationsConsoleSystem.cs
+++ b/Content.Server/Communications/CommunicationsConsoleSystem.cs
@@ -182,10 +182,6 @@ private static bool CanAnnounce(CommunicationsConsoleComponent comp)
 
         private bool CanUse(EntityUid user, EntityUid console)
         {
-            // This shouldn't technically be possible because of BUI but don't trust client.
-            if (!_interaction.InRangeUnobstructed(console, user))
-                return false;
-
             if (TryComp<AccessReaderComponent>(console, out var accessReaderComponent) && !HasComp<EmaggedComponent>(console))
             {
                 return _accessReaderSystem.IsAllowed(user, console, accessReaderComponent);
diff --git a/Content.Server/DeviceNetwork/Systems/DeviceNetworkRequiresPowerSystem.cs b/Content.Server/DeviceNetwork/Systems/DeviceNetworkRequiresPowerSystem.cs
index f47a5df8ac..6e7bd255c5 100644
--- a/Content.Server/DeviceNetwork/Systems/DeviceNetworkRequiresPowerSystem.cs
+++ b/Content.Server/DeviceNetwork/Systems/DeviceNetworkRequiresPowerSystem.cs
@@ -1,7 +1,6 @@
 using Content.Server.DeviceNetwork.Components;
 using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
-using Content.Shared.Power.EntitySystems;
 
 namespace Content.Server.DeviceNetwork.Systems;
 
diff --git a/Content.Server/Light/EntitySystems/LitOnPoweredSystem.cs b/Content.Server/Light/EntitySystems/LitOnPoweredSystem.cs
index 3c5f7eaecb..5c66d65b57 100644
--- a/Content.Server/Light/EntitySystems/LitOnPoweredSystem.cs
+++ b/Content.Server/Light/EntitySystems/LitOnPoweredSystem.cs
@@ -2,7 +2,6 @@
 using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
 using Content.Shared.Power;
-using Content.Shared.Power.Components;
 
 namespace Content.Server.Light.EntitySystems
 {
diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs
index c4a07b56a8..58ffd4f7b9 100644
--- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs
+++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs
@@ -27,7 +27,6 @@
 using Content.Shared.Damage.Systems;
 using Content.Shared.Damage.Components;
 using Content.Shared.Power;
-using Content.Shared.Power.Components;
 
 namespace Content.Server.Light.EntitySystems
 {
diff --git a/Content.Server/Mind/MindSystem.cs b/Content.Server/Mind/MindSystem.cs
index 4271d76b44..2e7c31ec7a 100644
--- a/Content.Server/Mind/MindSystem.cs
+++ b/Content.Server/Mind/MindSystem.cs
@@ -341,13 +341,13 @@ public override void SetUserId(EntityUid mindId, NetUserId? userId, MindComponen
         }
     }
 
-    public void ControlMob(EntityUid user, EntityUid target)
+    public override void ControlMob(EntityUid user, EntityUid target)
     {
         if (TryComp(user, out ActorComponent? actor))
             ControlMob(actor.PlayerSession.UserId, target);
     }
 
-    public void ControlMob(NetUserId user, EntityUid target)
+    public override void ControlMob(NetUserId user, EntityUid target)
     {
         var (mindId, mind) = GetOrCreateMind(user);
 
diff --git a/Content.Server/Power/EntitySystems/ChargerSystem.cs b/Content.Server/Power/EntitySystems/ChargerSystem.cs
index 2aa69024df..40b998a95d 100644
--- a/Content.Server/Power/EntitySystems/ChargerSystem.cs
+++ b/Content.Server/Power/EntitySystems/ChargerSystem.cs
@@ -8,7 +8,6 @@
 using JetBrains.Annotations;
 using Robust.Shared.Containers;
 using System.Diagnostics.CodeAnalysis;
-using Content.Shared.Power.Components;
 using Content.Shared.Storage.Components;
 using Robust.Server.Containers;
 using Content.Shared.Whitelist;
@@ -44,7 +43,37 @@ private void OnStartup(EntityUid uid, ChargerComponent component, ComponentStart
 
     private void OnChargerExamine(EntityUid uid, ChargerComponent component, ExaminedEvent args)
     {
-        args.PushMarkup(Loc.GetString("charger-examine", ("color", "yellow"), ("chargeRate", (int) component.ChargeRate)));
+        using (args.PushGroup(nameof(ChargerComponent)))
+        {
+            // rate at which the charger charges
+            args.PushMarkup(Loc.GetString("charger-examine", ("color", "yellow"), ("chargeRate", (int) component.ChargeRate)));
+
+            // try to get contents of the charger
+            if (!_container.TryGetContainer(uid, component.SlotId, out var container))
+                return;
+
+            if (HasComp<PowerCellSlotComponent>(uid))
+                return;
+
+            // if charger is empty and not a power cell type charger, add empty message
+            // power cells have their own empty message by default, for things like flash lights
+            if (container.ContainedEntities.Count == 0)
+            {
+                args.PushMarkup(Loc.GetString("charger-empty"));
+            }
+            else
+            {
+                // add how much each item is charged it
+                foreach (var contained in container.ContainedEntities)
+                {
+                    if (!TryComp<BatteryComponent>(contained, out var battery))
+                        continue;
+
+                    var chargePercentage = (battery.CurrentCharge / battery.MaxCharge) * 100;
+                    args.PushMarkup(Loc.GetString("charger-content", ("chargePercentage", (int) chargePercentage)));
+                }
+            }
+        }
     }
 
     public override void Update(float frameTime)
@@ -202,7 +231,7 @@ private CellChargerStatus GetStatus(EntityUid uid, ChargerComponent component)
 
         return CellChargerStatus.Charging;
     }
-    
+
     private void TransferPower(EntityUid uid, EntityUid targetEntity, ChargerComponent component, float frameTime)
     {
         if (!TryComp(uid, out ApcPowerReceiverComponent? receiverComponent))
diff --git a/Content.Server/Power/EntitySystems/PowerNetSystem.cs b/Content.Server/Power/EntitySystems/PowerNetSystem.cs
index 8dcb6240a5..6c35ba2008 100644
--- a/Content.Server/Power/EntitySystems/PowerNetSystem.cs
+++ b/Content.Server/Power/EntitySystems/PowerNetSystem.cs
@@ -5,7 +5,6 @@
 using Content.Server.Power.Pow3r;
 using Content.Shared.CCVar;
 using Content.Shared.Power;
-using Content.Shared.Power.Components;
 using JetBrains.Annotations;
 using Robust.Server.GameObjects;
 using Robust.Shared.Configuration;
diff --git a/Content.Server/Power/Generation/Teg/TegSystem.cs b/Content.Server/Power/Generation/Teg/TegSystem.cs
index dd09467efe..43749dab8f 100644
--- a/Content.Server/Power/Generation/Teg/TegSystem.cs
+++ b/Content.Server/Power/Generation/Teg/TegSystem.cs
@@ -11,7 +11,6 @@
 using Content.Shared.DeviceNetwork;
 using Content.Shared.Examine;
 using Content.Shared.Power;
-using Content.Shared.Power.Components;
 using Content.Shared.Power.Generation.Teg;
 using Content.Shared.Rounding;
 using Robust.Server.GameObjects;
diff --git a/Content.Server/Power/Generator/GasPowerReceiverSystem.cs b/Content.Server/Power/Generator/GasPowerReceiverSystem.cs
index 5a1bd31a15..e3979a6519 100644
--- a/Content.Server/Power/Generator/GasPowerReceiverSystem.cs
+++ b/Content.Server/Power/Generator/GasPowerReceiverSystem.cs
@@ -6,7 +6,6 @@
 using Content.Server.Power.Components;
 using Content.Shared.Atmos;
 using Content.Shared.Power;
-using Content.Shared.Power.Components;
 
 namespace Content.Server.Power.Generator;
 
diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs
index 0c0f68c23f..6b7df52a6e 100644
--- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs
+++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs
@@ -5,12 +5,10 @@
 using Content.Server.Radio.Components;
 using Content.Server.Roles;
 using Content.Server.Station.Systems;
-using Content.Shared.Actions;
 using Content.Shared.Administration;
 using Content.Shared.Chat;
 using Content.Shared.Emag.Components;
 using Content.Shared.Emag.Systems;
-using Content.Shared.Examine;
 using Content.Shared.Mind;
 using Content.Shared.Mind.Components;
 using Content.Shared.Roles;
@@ -19,10 +17,10 @@
 using Content.Shared.Stunnable;
 using Content.Shared.Wires;
 using Robust.Server.GameObjects;
+using Robust.Shared.Containers;
 using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Toolshed;
-using Robust.Shared.Utility;
 
 namespace Content.Server.Silicons.Laws;
 
@@ -32,11 +30,9 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
     [Dependency] private readonly IChatManager _chatManager = default!;
     [Dependency] private readonly IPrototypeManager _prototype = default!;
     [Dependency] private readonly SharedMindSystem _mind = default!;
-    [Dependency] private readonly SharedActionsSystem _actions = default!;
     [Dependency] private readonly StationSystem _station = default!;
     [Dependency] private readonly UserInterfaceSystem _userInterface = default!;
     [Dependency] private readonly SharedStunSystem _stunSystem = default!;
-    [Dependency] private readonly IEntityManager _entityManager = default!;
     [Dependency] private readonly SharedRoleSystem _roles = default!;
 
     /// <inheritdoc/>
@@ -44,7 +40,6 @@ public override void Initialize()
     {
         base.Initialize();
 
-        SubscribeLocalEvent<SiliconLawBoundComponent, ComponentShutdown>(OnComponentShutdown);
         SubscribeLocalEvent<SiliconLawBoundComponent, MapInitEvent>(OnMapInit);
         SubscribeLocalEvent<SiliconLawBoundComponent, MindAddedMessage>(OnMindAdded);
         SubscribeLocalEvent<SiliconLawBoundComponent, ToggleLawsScreenEvent>(OnToggleLawsScreen);
@@ -58,15 +53,8 @@ public override void Initialize()
         SubscribeLocalEvent<EmagSiliconLawComponent, MindRemovedMessage>(OnEmagMindRemoved);
     }
 
-    private void OnComponentShutdown(EntityUid uid, SiliconLawBoundComponent component, ComponentShutdown args)
-    {
-        if (component.ViewLawsActionEntity != null)
-            _actions.RemoveAction(uid, component.ViewLawsActionEntity);
-    }
-
     private void OnMapInit(EntityUid uid, SiliconLawBoundComponent component, MapInitEvent args)
     {
-        _actions.AddAction(uid, ref component.ViewLawsActionEntity, component.ViewLawsAction);
         GetLaws(uid, component);
     }
 
@@ -92,7 +80,7 @@ private void OnToggleLawsScreen(EntityUid uid, SiliconLawBoundComponent componen
 
     private void OnBoundUIOpened(EntityUid uid, SiliconLawBoundComponent component, BoundUIOpenedEvent args)
     {
-        _entityManager.TryGetComponent<IntrinsicRadioTransmitterComponent>(uid, out var intrinsicRadio);
+        TryComp(uid, out IntrinsicRadioTransmitterComponent? intrinsicRadio);
         var radioChannels = intrinsicRadio?.Channels;
 
         var state = new SiliconLawBuiState(GetLaws(uid).Laws, radioChannels);
@@ -264,9 +252,9 @@ public void NotifyLawsChanged(EntityUid uid)
     /// <summary>
     /// Extract all the laws from a lawset's prototype ids.
     /// </summary>
-    public SiliconLawset GetLawset(string lawset)
+    public SiliconLawset GetLawset(ProtoId<SiliconLawsetPrototype> lawset)
     {
-        var proto = _prototype.Index<SiliconLawsetPrototype>(lawset);
+        var proto = _prototype.Index(lawset);
         var laws = new SiliconLawset()
         {
             Laws = new List<SiliconLaw>(proto.Laws.Count)
@@ -294,6 +282,21 @@ public void SetLaws(List<SiliconLaw> newLaws, EntityUid target)
         component.Lawset.Laws = newLaws;
         NotifyLawsChanged(target);
     }
+
+    protected override void OnUpdaterInsert(Entity<SiliconLawUpdaterComponent> ent, ref EntInsertedIntoContainerMessage args)
+    {
+        // TODO: Prediction dump this
+        if (!TryComp(args.Entity, out SiliconLawProviderComponent? provider))
+            return;
+
+        var lawset = GetLawset(provider.Laws).Laws;
+        var query = EntityManager.CompRegistryQueryEnumerator(ent.Comp.Components);
+
+        while (query.MoveNext(out var update))
+        {
+            SetLaws(lawset, update);
+        }
+    }
 }
 
 [ToolshedCommand, AdminCommand(AdminFlags.Admin)]
diff --git a/Content.Server/Silicons/StationAi/AiInteractWireAction.cs b/Content.Server/Silicons/StationAi/AiInteractWireAction.cs
new file mode 100644
index 0000000000..c92c825b32
--- /dev/null
+++ b/Content.Server/Silicons/StationAi/AiInteractWireAction.cs
@@ -0,0 +1,37 @@
+using Content.Server.Wires;
+using Content.Shared.Doors;
+using Content.Shared.Silicons.StationAi;
+using Content.Shared.Wires;
+
+namespace Content.Server.Silicons.StationAi;
+
+/// <summary>
+/// Controls whether an AI can interact with the target entity.
+/// </summary>
+public sealed partial class AiInteractWireAction : ComponentWireAction<StationAiWhitelistComponent>
+{
+    public override string Name { get; set; } = "wire-name-ai-act-light";
+    public override Color Color { get; set; } = Color.DeepSkyBlue;
+    public override object StatusKey => AirlockWireStatus.AiControlIndicator;
+
+    public override StatusLightState? GetLightState(Wire wire, StationAiWhitelistComponent component)
+    {
+        return component.Enabled ? StatusLightState.On : StatusLightState.Off;
+    }
+
+    public override bool Cut(EntityUid user, Wire wire, StationAiWhitelistComponent component)
+    {
+        return EntityManager.System<SharedStationAiSystem>()
+            .SetWhitelistEnabled((component.Owner, component), false, announce: true);
+    }
+
+    public override bool Mend(EntityUid user, Wire wire, StationAiWhitelistComponent component)
+    {
+        return EntityManager.System<SharedStationAiSystem>()
+            .SetWhitelistEnabled((component.Owner, component), true);
+    }
+
+    public override void Pulse(EntityUid user, Wire wire, StationAiWhitelistComponent component)
+    {
+    }
+}
diff --git a/Content.Server/Silicons/StationAi/AiVisionWireAction.cs b/Content.Server/Silicons/StationAi/AiVisionWireAction.cs
new file mode 100644
index 0000000000..3523f4d38f
--- /dev/null
+++ b/Content.Server/Silicons/StationAi/AiVisionWireAction.cs
@@ -0,0 +1,40 @@
+using Content.Server.Wires;
+using Content.Shared.Doors;
+using Content.Shared.Silicons.StationAi;
+using Content.Shared.StationAi;
+using Content.Shared.Wires;
+
+namespace Content.Server.Silicons.StationAi;
+
+/// <summary>
+/// Handles StationAiVision functionality for the attached entity.
+/// </summary>
+public sealed partial class AiVisionWireAction : ComponentWireAction<StationAiVisionComponent>
+{
+    public override string Name { get; set; } = "wire-name-ai-vision-light";
+    public override Color Color { get; set; } = Color.DeepSkyBlue;
+    public override object StatusKey => AirlockWireStatus.AiControlIndicator;
+
+    public override StatusLightState? GetLightState(Wire wire, StationAiVisionComponent component)
+    {
+        return component.Enabled ? StatusLightState.On : StatusLightState.Off;
+    }
+
+    public override bool Cut(EntityUid user, Wire wire, StationAiVisionComponent component)
+    {
+        return EntityManager.System<SharedStationAiSystem>()
+            .SetVisionEnabled((component.Owner, component), false, announce: true);
+    }
+
+    public override bool Mend(EntityUid user, Wire wire, StationAiVisionComponent component)
+    {
+        return EntityManager.System<SharedStationAiSystem>()
+            .SetVisionEnabled((component.Owner, component), true);
+    }
+
+    public override void Pulse(EntityUid user, Wire wire, StationAiVisionComponent component)
+    {
+        // TODO: This should turn it off for a bit
+        // Need timer cleanup first out of scope.
+    }
+}
diff --git a/Content.Server/Silicons/StationAi/StationAiSystem.cs b/Content.Server/Silicons/StationAi/StationAiSystem.cs
new file mode 100644
index 0000000000..846497387d
--- /dev/null
+++ b/Content.Server/Silicons/StationAi/StationAiSystem.cs
@@ -0,0 +1,76 @@
+using System.Linq;
+using Content.Server.Chat.Managers;
+using Content.Server.Chat.Systems;
+using Content.Shared.Chat;
+using Content.Shared.Silicons.StationAi;
+using Content.Shared.StationAi;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Player;
+
+namespace Content.Server.Silicons.StationAi;
+
+public sealed class StationAiSystem : SharedStationAiSystem
+{
+    [Dependency] private readonly IChatManager _chats = default!;
+    [Dependency] private readonly EntityLookupSystem _lookup = default!;
+
+    private readonly HashSet<Entity<StationAiCoreComponent>> _ais = new();
+
+    public override bool SetVisionEnabled(Entity<StationAiVisionComponent> entity, bool enabled, bool announce = false)
+    {
+        if (!base.SetVisionEnabled(entity, enabled, announce))
+            return false;
+
+        if (announce)
+        {
+            AnnounceSnip(entity.Owner);
+        }
+
+        return true;
+    }
+
+    public override bool SetWhitelistEnabled(Entity<StationAiWhitelistComponent> entity, bool enabled, bool announce = false)
+    {
+        if (!base.SetWhitelistEnabled(entity, enabled, announce))
+            return false;
+
+        if (announce)
+        {
+            AnnounceSnip(entity.Owner);
+        }
+
+        return true;
+    }
+
+    private void AnnounceSnip(EntityUid entity)
+    {
+        var xform = Transform(entity);
+
+        if (!TryComp(xform.GridUid, out MapGridComponent? grid))
+            return;
+
+        _ais.Clear();
+        _lookup.GetChildEntities(xform.GridUid.Value, _ais);
+        var filter = Filter.Empty();
+
+        foreach (var ai in _ais)
+        {
+            // TODO: Filter API?
+            if (TryComp(ai.Owner, out ActorComponent? actorComp))
+            {
+                filter.AddPlayer(actorComp.PlayerSession);
+            }
+        }
+
+        // TEST
+        // filter = Filter.Broadcast();
+
+        // No easy way to do chat notif embeds atm.
+        var tile = Maps.LocalToTile(xform.GridUid.Value, grid, xform.Coordinates);
+        var msg = Loc.GetString("ai-wire-snipped", ("coords", tile));
+
+        _chats.ChatMessageToMany(ChatChannel.Notifications, msg, msg, entity, false, true, filter.Recipients.Select(o => o.Channel));
+        // Apparently there's no sound for this.
+    }
+}
diff --git a/Content.Server/Sound/SpamEmitSoundRequirePowerSystem.cs b/Content.Server/Sound/SpamEmitSoundRequirePowerSystem.cs
index d2c2a8a1ca..1ad1bb6c0a 100644
--- a/Content.Server/Sound/SpamEmitSoundRequirePowerSystem.cs
+++ b/Content.Server/Sound/SpamEmitSoundRequirePowerSystem.cs
@@ -1,7 +1,6 @@
 using Content.Server.Power.Components;
 using Content.Server.Power.EntitySystems;
 using Content.Shared.Power;
-using Content.Shared.Power.Components;
 using Content.Shared.Sound;
 using Content.Shared.Sound.Components;
 
diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs
index 79192d49b4..0662c54bee 100644
--- a/Content.Server/Station/Systems/StationSpawningSystem.cs
+++ b/Content.Server/Station/Systems/StationSpawningSystem.cs
@@ -139,6 +139,22 @@ public EntityUid SpawnPlayerMob(
         EntityUid? entity = null)
     {
         _prototypeManager.TryIndex(job?.Prototype ?? string.Empty, out var prototype);
+        RoleLoadout? loadout = null;
+
+        // Need to get the loadout up-front to handle names if we use an entity spawn override.
+        var jobLoadout = LoadoutSystem.GetJobPrototype(prototype?.ID);
+
+        if (_prototypeManager.TryIndex(jobLoadout, out RoleLoadoutPrototype? roleProto))
+        {
+            profile?.Loadouts.TryGetValue(jobLoadout, out loadout);
+
+            // Set to default if not present
+            if (loadout == null)
+            {
+                loadout = new RoleLoadout(jobLoadout);
+                loadout.SetDefault(profile, _actors.GetSession(entity), _prototypeManager);
+            }
+        }
 
         // If we're not spawning a humanoid, we're gonna exit early without doing all the humanoid stuff.
         if (prototype?.JobEntity != null)
@@ -146,6 +162,13 @@ public EntityUid SpawnPlayerMob(
             DebugTools.Assert(entity is null);
             var jobEntity = EntityManager.SpawnEntity(prototype.JobEntity, coordinates);
             MakeSentientCommand.MakeSentient(jobEntity, EntityManager);
+
+            // Make sure custom names get handled, what is gameticker control flow whoopy.
+            if (loadout != null)
+            {
+                EquipRoleName(jobEntity, loadout, roleProto!);
+            }
+
             DoJobSpecials(job, jobEntity);
             _identity.QueueIdentityUpdate(jobEntity);
             return jobEntity;
diff --git a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs
index 5970e16319..c9be87c623 100644
--- a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs
+++ b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs
@@ -38,7 +38,7 @@ private void OnInteractUsing(EntityUid uid, EnergySwordComponent comp, InteractU
         if (args.Handled)
             return;
 
-        if (!_toolSystem.HasQuality(args.Used, "Pulsing"))
+        if (!_toolSystem.HasQuality(args.Used, SharedToolSystem.PulseQuality))
             return;
 
         args.Handled = true;
diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactElectricityTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactElectricityTriggerSystem.cs
index 019e09bbbb..9d2fd58980 100644
--- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactElectricityTriggerSystem.cs
+++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactElectricityTriggerSystem.cs
@@ -44,7 +44,7 @@ private void OnInteractUsing(EntityUid uid, ArtifactElectricityTriggerComponent
         if (args.Handled)
             return;
 
-        if (!_toolSystem.HasQuality(args.Used, "Pulsing"))
+        if (!_toolSystem.HasQuality(args.Used, SharedToolSystem.PulseQuality))
             return;
 
         args.Handled = _artifactSystem.TryActivateArtifact(uid, args.User);
diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
index d2883b5ef5..bd6ee8cae1 100644
--- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
+++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
@@ -4,6 +4,7 @@
 using Content.Shared.Emoting;
 using Content.Shared.Hands;
 using Content.Shared.Interaction;
+using Content.Shared.Interaction.Components;
 using Content.Shared.Interaction.Events;
 using Content.Shared.Item;
 using Content.Shared.Mobs;
@@ -26,9 +27,14 @@ public sealed class ActionBlockerSystem : EntitySystem
     {
         [Dependency] private readonly SharedContainerSystem _container = default!;
 
+        private EntityQuery<ComplexInteractionComponent> _complexInteractionQuery;
+
         public override void Initialize()
         {
             base.Initialize();
+
+            _complexInteractionQuery = GetEntityQuery<ComplexInteractionComponent>();
+
             SubscribeLocalEvent<InputMoverComponent, ComponentStartup>(OnMoverStartup);
         }
 
@@ -57,6 +63,15 @@ public bool UpdateCanMove(EntityUid uid, InputMoverComponent? component = null)
             return !ev.Cancelled;
         }
 
+        /// <summary>
+        /// Checks if a given entity is able to do specific complex interactions.
+        /// This is used to gate manipulation to general humanoids. If a mouse shouldn't be able to do something, then it's complex.
+        /// </summary>
+        public bool CanComplexInteract(EntityUid user)
+        {
+            return _complexInteractionQuery.HasComp(user);
+        }
+
         /// <summary>
         ///     Raises an event directed at both the user and the target entity to check whether a user is capable of
         ///     interacting with this entity.
diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs
index 722d97213f..42fa89b367 100644
--- a/Content.Shared/Climbing/Systems/ClimbSystem.cs
+++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs
@@ -373,6 +373,26 @@ private void OnClimbEndCollide(EntityUid uid, ClimbingComponent component, ref E
             return;
         }
 
+        foreach (var contact in args.OurFixture.Contacts.Values)
+        {
+            if (!contact.IsTouching)
+                continue;
+
+            var otherEnt = contact.OtherEnt(uid);
+            var (otherFixtureId, otherFixture) = contact.OtherFixture(uid);
+
+            // TODO: Remove this on engine.
+            if (args.OtherEntity == otherEnt && args.OtherFixtureId == otherFixtureId)
+                continue;
+
+            if (otherFixture is { Hard: true } &&
+                _climbableQuery.HasComp(otherEnt))
+            {
+                return;
+            }
+        }
+
+        // TODO: Is this even needed anymore?
         foreach (var otherFixture in args.OurFixture.Contacts.Keys)
         {
             // If it's the other fixture then ignore em
diff --git a/Content.Shared/Configurable/ConfigurationComponent.cs b/Content.Shared/Configurable/ConfigurationComponent.cs
index 63a0dfe95a..621871af3c 100644
--- a/Content.Shared/Configurable/ConfigurationComponent.cs
+++ b/Content.Shared/Configurable/ConfigurationComponent.cs
@@ -1,5 +1,6 @@
 using System.Text.RegularExpressions;
 using Content.Shared.Tools;
+using Content.Shared.Tools.Systems;
 using Robust.Shared.GameStates;
 using Robust.Shared.Serialization;
 using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
@@ -13,7 +14,7 @@ public sealed partial class ConfigurationComponent : Component
         public Dictionary<string, string?> Config = new();
 
         [DataField("qualityNeeded", customTypeSerializer: typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
-        public string QualityNeeded = "Pulsing";
+        public string QualityNeeded = SharedToolSystem.PulseQuality;
 
         [DataField("validation")]
         public Regex Validation = new("^[a-zA-Z0-9 ]*$", RegexOptions.Compiled);
diff --git a/Content.Shared/Doors/AirlockWireStatus.cs b/Content.Shared/Doors/AirlockWireStatus.cs
index a50ee2c88e..d3fa15ed1b 100644
--- a/Content.Shared/Doors/AirlockWireStatus.cs
+++ b/Content.Shared/Doors/AirlockWireStatus.cs
@@ -8,7 +8,7 @@ public enum AirlockWireStatus
         PowerIndicator,
         BoltIndicator,
         BoltLightIndicator,
-        AIControlIndicator,
+        AiControlIndicator,
         TimingIndicator,
         SafetyIndicator,
     }
diff --git a/Content.Shared/Examine/ExamineSystemShared.cs b/Content.Shared/Examine/ExamineSystemShared.cs
index 397a8f7448..a1c30a2bd0 100644
--- a/Content.Shared/Examine/ExamineSystemShared.cs
+++ b/Content.Shared/Examine/ExamineSystemShared.cs
@@ -109,12 +109,25 @@ public virtual bool CanExamine(EntityUid examiner, MapCoordinates target, Ignore
             if (EntityManager.GetComponent<TransformComponent>(examiner).MapID != target.MapId)
                 return false;
 
-            return InRangeUnOccluded(
-                _transform.GetMapCoordinates(examiner),
-                target,
-                GetExaminerRange(examiner),
-                predicate: predicate,
-                ignoreInsideBlocker: true);
+            // Do target InRangeUnoccluded which has different checks.
+            if (examined != null)
+            {
+                return InRangeUnOccluded(
+                    examiner,
+                    examined.Value,
+                    GetExaminerRange(examiner),
+                    predicate: predicate,
+                    ignoreInsideBlocker: true);
+            }
+            else
+            {
+                return InRangeUnOccluded(
+                    examiner,
+                    target,
+                    GetExaminerRange(examiner),
+                    predicate: predicate,
+                    ignoreInsideBlocker: true);
+            }
         }
 
         /// <summary>
@@ -209,7 +222,14 @@ public bool InRangeUnOccluded<TState>(MapCoordinates origin, MapCoordinates othe
 
         public bool InRangeUnOccluded(EntityUid origin, EntityUid other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
         {
-            var entMan = IoCManager.Resolve<IEntityManager>();
+            var ev = new InRangeOverrideEvent(origin, other);
+            RaiseLocalEvent(origin, ref ev);
+
+            if (ev.Handled)
+            {
+                return ev.InRange;
+            }
+
             var originPos = _transform.GetMapCoordinates(origin);
             var otherPos = _transform.GetMapCoordinates(other);
 
diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs
index 24bb1b2446..a2118205af 100644
--- a/Content.Shared/Interaction/SharedInteractionSystem.cs
+++ b/Content.Shared/Interaction/SharedInteractionSystem.cs
@@ -20,6 +20,7 @@
 using Content.Shared.Physics;
 using Content.Shared.Players.RateLimiting;
 using Content.Shared.Popups;
+using Content.Shared.Silicons.StationAi;
 using Content.Shared.Storage;
 using Content.Shared.Strip;
 using Content.Shared.Tag;
@@ -83,7 +84,6 @@ public abstract partial class SharedInteractionSystem : EntitySystem
         private EntityQuery<WallMountComponent> _wallMountQuery;
         private EntityQuery<UseDelayComponent> _delayQuery;
         private EntityQuery<ActivatableUIComponent> _uiQuery;
-        private EntityQuery<ComplexInteractionComponent> _complexInteractionQuery;
 
         private const CollisionGroup InRangeUnobstructedMask = CollisionGroup.Impassable | CollisionGroup.InteractImpassable;
 
@@ -106,7 +106,6 @@ public override void Initialize()
             _wallMountQuery = GetEntityQuery<WallMountComponent>();
             _delayQuery = GetEntityQuery<UseDelayComponent>();
             _uiQuery = GetEntityQuery<ActivatableUIComponent>();
-            _complexInteractionQuery = GetEntityQuery<ComplexInteractionComponent>();
 
             SubscribeLocalEvent<BoundUserInterfaceCheckRangeEvent>(HandleUserInterfaceRangeCheck);
             SubscribeLocalEvent<BoundUserInterfaceMessageAttempt>(OnBoundInterfaceInteractAttempt);
@@ -191,7 +190,7 @@ private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev
                 return;
             }
 
-            if (uiComp.RequireHands && !_handsQuery.HasComp(ev.Actor))
+            if (uiComp.RequiresComplex && !_actionBlockerSystem.CanComplexInteract(ev.Actor))
                 ev.Cancel();
         }
 
@@ -477,10 +476,7 @@ private bool IsDeleted(EntityUid? uid)
 
         public void InteractHand(EntityUid user, EntityUid target)
         {
-            if (IsDeleted(user) || IsDeleted(target))
-                return;
-
-            var complexInteractions = SupportsComplexInteractions(user);
+            var complexInteractions = _actionBlockerSystem.CanComplexInteract(user);
             if (!complexInteractions)
             {
                 InteractionActivate(user,
@@ -666,6 +662,14 @@ public bool InRangeUnobstructed(
             if (!Resolve(other, ref other.Comp))
                 return false;
 
+            var ev = new InRangeOverrideEvent(origin, other);
+            RaiseLocalEvent(origin, ref ev);
+
+            if (ev.Handled)
+            {
+                return ev.InRange;
+            }
+
             return InRangeUnobstructed(origin,
                 other,
                 other.Comp.Coordinates,
@@ -1188,7 +1192,7 @@ public bool AltInteract(EntityUid user, EntityUid target)
             // Get list of alt-interact verbs
             var verbs = _verbSystem.GetLocalVerbs(target, user, typeof(AlternativeVerb));
 
-            if (!verbs.Any())
+            if (verbs.Count == 0)
                 return false;
 
             _verbSystem.ExecuteVerb(verbs.First(), user, target);
@@ -1245,6 +1249,13 @@ public bool InRangeAndAccessible(
         /// </summary>
         public bool IsAccessible(Entity<TransformComponent?> user, Entity<TransformComponent?> target)
         {
+            var ev = new AccessibleOverrideEvent(user, target);
+
+            RaiseLocalEvent(user, ref ev);
+
+            if (ev.Handled)
+                return ev.Accessible;
+
             if (_containerSystem.IsInSameOrParentContainer(user, target, out _, out var container))
                 return true;
 
@@ -1396,13 +1407,10 @@ public bool TryGetUsedEntity(EntityUid user, [NotNullWhen(true)] out EntityUid?
             return ev.Handled;
         }
 
-        /// <summary>
-        /// Checks if a given entity is able to do specific complex interactions.
-        /// This is used to gate manipulation to general humanoids. If a mouse shouldn't be able to do something, then it's complex.
-        /// </summary>
+        [Obsolete("Use ActionBlockerSystem")]
         public bool SupportsComplexInteractions(EntityUid user)
         {
-            return _complexInteractionQuery.HasComp(user);
+            return _actionBlockerSystem.CanComplexInteract(user);
         }
     }
 
@@ -1441,17 +1449,38 @@ public record struct GetUsedEntityEvent()
     };
 
     /// <summary>
-    ///     Raised directed by-ref on an item and a user to determine if interactions can occur.
+    ///     Raised directed by-ref on an item to determine if hand interactions should go through.
+    ///     Defaults to allowing hand interactions to go through. Cancel to force the item to be attacked instead.
     /// </summary>
     /// <param name="Cancelled">Whether the hand interaction should be cancelled.</param>
     [ByRefEvent]
-    public record struct AttemptUseInteractEvent(EntityUid User, EntityUid Used, bool Cancelled = false);
+    public record struct CombatModeShouldHandInteractEvent(bool Cancelled = false);
 
     /// <summary>
-    ///     Raised directed by-ref on an item to determine if hand interactions should go through.
-    ///     Defaults to allowing hand interactions to go through. Cancel to force the item to be attacked instead.
+    /// Override event raised directed on the user to say the target is accessible.
     /// </summary>
-    /// <param name="Cancelled">Whether the hand interaction should be cancelled.</param>
+    /// <param name="User"></param>
+    /// <param name="Target"></param>
     [ByRefEvent]
-    public record struct CombatModeShouldHandInteractEvent(bool Cancelled = false);
+    public record struct AccessibleOverrideEvent(EntityUid User, EntityUid Target)
+    {
+        public readonly EntityUid User = User;
+        public readonly EntityUid Target = Target;
+
+        public bool Handled;
+        public bool Accessible = false;
+    }
+
+    /// <summary>
+    /// Override event raised directed on a user to check InRangeUnoccluded AND InRangeUnobstructed to the target if you require custom logic.
+    /// </summary>
+    [ByRefEvent]
+    public record struct InRangeOverrideEvent(EntityUid User, EntityUid Target)
+    {
+        public readonly EntityUid User = User;
+        public readonly EntityUid Target = Target;
+
+        public bool Handled;
+        public bool InRange = false;
+    }
 }
diff --git a/Content.Shared/Light/Components/LightOnCollideColliderComponent.cs b/Content.Shared/Light/Components/LightOnCollideColliderComponent.cs
new file mode 100644
index 0000000000..39be05a148
--- /dev/null
+++ b/Content.Shared/Light/Components/LightOnCollideColliderComponent.cs
@@ -0,0 +1,13 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Light.Components;
+
+/// <summary>
+/// Can activate <see cref="LightOnCollideComponent"/> when collided with.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class LightOnCollideColliderComponent : Component
+{
+    [DataField]
+    public string FixtureId = "lightTrigger";
+}
diff --git a/Content.Shared/Light/Components/LightOnCollideComponent.cs b/Content.Shared/Light/Components/LightOnCollideComponent.cs
new file mode 100644
index 0000000000..c3b4bd7396
--- /dev/null
+++ b/Content.Shared/Light/Components/LightOnCollideComponent.cs
@@ -0,0 +1,11 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Light.Components;
+
+/// <summary>
+/// Enables / disables pointlight whenever entities are contacting with it
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class LightOnCollideComponent : Component
+{
+}
diff --git a/Content.Shared/Light/EntitySystems/LightCollideSystem.cs b/Content.Shared/Light/EntitySystems/LightCollideSystem.cs
new file mode 100644
index 0000000000..f09ae6824e
--- /dev/null
+++ b/Content.Shared/Light/EntitySystems/LightCollideSystem.cs
@@ -0,0 +1,82 @@
+using Content.Shared.Light.Components;
+using Robust.Shared.Physics.Events;
+using Robust.Shared.Physics.Systems;
+
+namespace Content.Shared.Light.EntitySystems;
+
+public sealed class LightCollideSystem : EntitySystem
+{
+    [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+    [Dependency] private readonly SlimPoweredLightSystem _lights = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<LightOnCollideColliderComponent, PreventCollideEvent>(OnPreventCollide);
+        SubscribeLocalEvent<LightOnCollideColliderComponent, StartCollideEvent>(OnStart);
+        SubscribeLocalEvent<LightOnCollideColliderComponent, EndCollideEvent>(OnEnd);
+
+        SubscribeLocalEvent<LightOnCollideColliderComponent, ComponentShutdown>(OnCollideShutdown);
+    }
+
+    private void OnCollideShutdown(Entity<LightOnCollideColliderComponent> ent, ref ComponentShutdown args)
+    {
+        // TODO: Check this on the event.
+        if (TerminatingOrDeleted(ent.Owner))
+            return;
+
+        // Regenerate contacts for everything we were colliding with.
+        var contacts = _physics.GetContacts(ent.Owner);
+
+        while (contacts.MoveNext(out var contact))
+        {
+            if (!contact.IsTouching)
+                continue;
+
+            var other = contact.OtherEnt(ent.Owner);
+
+            if (HasComp<LightOnCollideComponent>(other))
+            {
+                _physics.RegenerateContacts(other);
+            }
+        }
+    }
+
+    // You may be wondering what de fok this is doing here.
+    // At the moment there's no easy way to do collision whitelists based on components.
+    private void OnPreventCollide(Entity<LightOnCollideColliderComponent> ent, ref PreventCollideEvent args)
+    {
+        if (!HasComp<LightOnCollideComponent>(args.OtherEntity))
+        {
+            args.Cancelled = true;
+        }
+    }
+
+    private void OnEnd(Entity<LightOnCollideColliderComponent> ent, ref EndCollideEvent args)
+    {
+        if (args.OurFixtureId != ent.Comp.FixtureId)
+            return;
+
+        if (!HasComp<LightOnCollideComponent>(args.OtherEntity))
+            return;
+
+        // TODO: Engine bug IsTouching box2d yay.
+        var contacts = _physics.GetTouchingContacts(args.OtherEntity) - 1;
+
+        if (contacts > 0)
+            return;
+
+        _lights.SetEnabled(args.OtherEntity, false);
+    }
+
+    private void OnStart(Entity<LightOnCollideColliderComponent> ent, ref StartCollideEvent args)
+    {
+        if (args.OurFixtureId != ent.Comp.FixtureId)
+            return;
+
+        if (!HasComp<LightOnCollideComponent>(args.OtherEntity))
+            return;
+
+        _lights.SetEnabled(args.OtherEntity, true);
+    }
+}
diff --git a/Content.Shared/Light/EntitySystems/SlimPoweredLightSystem.cs b/Content.Shared/Light/EntitySystems/SlimPoweredLightSystem.cs
index 6d984ed19a..4cf9b25dad 100644
--- a/Content.Shared/Light/EntitySystems/SlimPoweredLightSystem.cs
+++ b/Content.Shared/Light/EntitySystems/SlimPoweredLightSystem.cs
@@ -1,6 +1,5 @@
 using Content.Shared.Light.Components;
 using Content.Shared.Power;
-using Content.Shared.Power.Components;
 using Content.Shared.Power.EntitySystems;
 
 namespace Content.Shared.Light.EntitySystems;
diff --git a/Content.Shared/Mind/SharedMindSystem.cs b/Content.Shared/Mind/SharedMindSystem.cs
index 2b83f05190..994d230e8b 100644
--- a/Content.Shared/Mind/SharedMindSystem.cs
+++ b/Content.Shared/Mind/SharedMindSystem.cs
@@ -315,6 +315,10 @@ public virtual void TransferTo(EntityUid mindId, EntityUid? entity, bool ghostCh
     {
     }
 
+    public virtual void ControlMob(EntityUid user, EntityUid target) {}
+
+    public virtual void ControlMob(NetUserId user, EntityUid target) {}
+
     /// <summary>
     /// Tries to create and add an objective from its prototype id.
     /// </summary>
diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs
index 824d057b3e..0fb9c5920f 100644
--- a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs
+++ b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs
@@ -1,4 +1,5 @@
 using Content.Shared.Actions;
+using Robust.Shared.GameStates;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
 
@@ -7,21 +8,9 @@ namespace Content.Shared.Silicons.Laws.Components;
 /// <summary>
 /// This is used for entities which are bound to silicon laws and can view them.
 /// </summary>
-[RegisterComponent, Access(typeof(SharedSiliconLawSystem))]
+[RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))]
 public sealed partial class SiliconLawBoundComponent : Component
 {
-    /// <summary>
-    /// The sidebar action that toggles the laws screen.
-    /// </summary>
-    [DataField]
-    public EntProtoId ViewLawsAction = "ActionViewLaws";
-
-    /// <summary>
-    /// The action for toggling laws. Stored here so we can remove it later.
-    /// </summary>
-    [DataField]
-    public EntityUid? ViewLawsActionEntity;
-
     /// <summary>
     /// The last entity that provided laws to this entity.
     /// </summary>
diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawUpdaterComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawUpdaterComponent.cs
new file mode 100644
index 0000000000..e28bf883d9
--- /dev/null
+++ b/Content.Shared/Silicons/Laws/Components/SiliconLawUpdaterComponent.cs
@@ -0,0 +1,17 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Silicons.Laws.Components;
+
+/// <summary>
+/// Whenever an entity is inserted with silicon laws it will update the relevant entity's laws.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class SiliconLawUpdaterComponent : Component
+{
+    /// <summary>
+    /// Entities to update
+    /// </summary>
+    [DataField(required: true)]
+    public ComponentRegistry Components;
+}
diff --git a/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.Updater.cs b/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.Updater.cs
new file mode 100644
index 0000000000..9fbef58a84
--- /dev/null
+++ b/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.Updater.cs
@@ -0,0 +1,17 @@
+using Content.Shared.Silicons.Laws.Components;
+using Robust.Shared.Containers;
+
+namespace Content.Shared.Silicons.Laws;
+
+public abstract partial class SharedSiliconLawSystem
+{
+    private void InitializeUpdater()
+    {
+        SubscribeLocalEvent<SiliconLawUpdaterComponent, EntInsertedIntoContainerMessage>(OnUpdaterInsert);
+    }
+
+    protected virtual void OnUpdaterInsert(Entity<SiliconLawUpdaterComponent> ent, ref EntInsertedIntoContainerMessage args)
+    {
+        // TODO: Prediction
+    }
+}
diff --git a/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs b/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs
index c0619e6e43..a30e7c8980 100644
--- a/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs
+++ b/Content.Shared/Silicons/Laws/SharedSiliconLawSystem.cs
@@ -8,13 +8,14 @@ namespace Content.Shared.Silicons.Laws;
 /// <summary>
 /// This handles getting and displaying the laws for silicons.
 /// </summary>
-public abstract class SharedSiliconLawSystem : EntitySystem
+public abstract partial class SharedSiliconLawSystem : EntitySystem
 {
     [Dependency] private readonly SharedPopupSystem _popup = default!;
 
     /// <inheritdoc/>
     public override void Initialize()
     {
+        InitializeUpdater();
         SubscribeLocalEvent<EmagSiliconLawComponent, GotEmaggedEvent>(OnGotEmagged);
         SubscribeLocalEvent<EmagSiliconLawComponent, OnAttemptEmagEvent>(OnAttemptEmag);
     }
diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs
new file mode 100644
index 0000000000..ff6fc1ece0
--- /dev/null
+++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Airlock.cs
@@ -0,0 +1,25 @@
+using Content.Shared.Doors.Components;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Silicons.StationAi;
+
+public abstract partial class SharedStationAiSystem
+{
+    // Handles airlock radial
+
+    private void InitializeAirlock()
+    {
+        SubscribeLocalEvent<DoorBoltComponent, StationAiBoltEvent>(OnAirlockBolt);
+    }
+
+    private void OnAirlockBolt(EntityUid ent, DoorBoltComponent component, StationAiBoltEvent args)
+    {
+        _doors.SetBoltsDown((ent, component), args.Bolted, args.User, predicted: true);
+    }
+}
+
+[Serializable, NetSerializable]
+public sealed class StationAiBoltEvent : BaseStationAiAction
+{
+    public bool Bolted;
+}
diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs
new file mode 100644
index 0000000000..a6c57f5940
--- /dev/null
+++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Held.cs
@@ -0,0 +1,187 @@
+using System.Diagnostics.CodeAnalysis;
+using Content.Shared.Actions.Events;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Verbs;
+using Robust.Shared.Serialization;
+using Robust.Shared.Utility;
+
+namespace Content.Shared.Silicons.StationAi;
+
+public abstract partial class SharedStationAiSystem
+{
+    /*
+     * Added when an entity is inserted into a StationAiCore.
+     */
+
+    private void InitializeHeld()
+    {
+        SubscribeLocalEvent<StationAiRadialMessage>(OnRadialMessage);
+        SubscribeLocalEvent<BoundUserInterfaceMessageAttempt>(OnMessageAttempt);
+        SubscribeLocalEvent<StationAiWhitelistComponent, GetVerbsEvent<AlternativeVerb>>(OnTargetVerbs);
+
+        SubscribeLocalEvent<StationAiHeldComponent, InteractionAttemptEvent>(OnHeldInteraction);
+        SubscribeLocalEvent<StationAiHeldComponent, AttemptRelayActionComponentChangeEvent>(OnHeldRelay);
+        SubscribeLocalEvent<StationAiHeldComponent, JumpToCoreEvent>(OnCoreJump);
+    }
+
+    private void OnCoreJump(Entity<StationAiHeldComponent> ent, ref JumpToCoreEvent args)
+    {
+        if (!TryGetCore(ent.Owner, out var core) || core.Comp?.RemoteEntity == null)
+            return;
+
+        _xforms.DropNextTo(core.Comp.RemoteEntity.Value, core.Owner) ;
+    }
+
+    /// <summary>
+    /// Tries to get the entity held in the AI core.
+    /// </summary>
+    private bool TryGetHeld(Entity<StationAiCoreComponent?> entity, out EntityUid held)
+    {
+        held = EntityUid.Invalid;
+
+        if (!Resolve(entity.Owner, ref entity.Comp))
+            return false;
+
+        if (!_containers.TryGetContainer(entity.Owner, StationAiCoreComponent.Container, out var container) ||
+            container.ContainedEntities.Count == 0)
+            return false;
+
+        held = container.ContainedEntities[0];
+        return true;
+    }
+
+    private bool TryGetCore(EntityUid ent, out Entity<StationAiCoreComponent?> core)
+    {
+        if (!_containers.TryGetContainingContainer(ent, out var container) ||
+            container.ID != StationAiCoreComponent.Container ||
+            !TryComp(container.Owner, out StationAiCoreComponent? coreComp) ||
+            coreComp.RemoteEntity == null)
+        {
+            core = (EntityUid.Invalid, null);
+            return false;
+        }
+
+        core = (container.Owner, coreComp);
+        return true;
+    }
+
+    private void OnHeldRelay(Entity<StationAiHeldComponent> ent, ref AttemptRelayActionComponentChangeEvent args)
+    {
+        if (!TryGetCore(ent.Owner, out var core))
+            return;
+
+        args.Target = core.Comp?.RemoteEntity;
+    }
+
+    private void OnRadialMessage(StationAiRadialMessage ev)
+    {
+        if (!TryGetEntity(ev.Entity, out var target))
+            return;
+
+        ev.Event.User = ev.Actor;
+        RaiseLocalEvent(target.Value, (object) ev.Event);
+    }
+
+    private void OnMessageAttempt(BoundUserInterfaceMessageAttempt ev)
+    {
+        if (ev.Actor == ev.Target)
+            return;
+
+        if (TryComp(ev.Actor, out StationAiHeldComponent? aiComp) &&
+           (!ValidateAi((ev.Actor, aiComp)) ||
+            !HasComp<StationAiWhitelistComponent>(ev.Target)))
+        {
+            ev.Cancel();
+        }
+    }
+
+    private void OnHeldInteraction(Entity<StationAiHeldComponent> ent, ref InteractionAttemptEvent args)
+    {
+        // Cancel if it's not us or something with a whitelist.
+        args.Cancelled = ent.Owner != args.Target &&
+                         args.Target != null &&
+                         (!TryComp(args.Target, out StationAiWhitelistComponent? whitelist) || !whitelist.Enabled);
+    }
+
+    private void OnTargetVerbs(Entity<StationAiWhitelistComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
+    {
+        if (!args.CanComplexInteract ||
+            !ent.Comp.Enabled ||
+            !HasComp<StationAiHeldComponent>(args.User) ||
+            !HasComp<StationAiWhitelistComponent>(args.Target))
+        {
+            return;
+        }
+
+        var user = args.User;
+        var target = args.Target;
+
+        var isOpen = _uiSystem.IsUiOpen(target, AiUi.Key, user);
+
+        args.Verbs.Add(new AlternativeVerb()
+        {
+            Text = isOpen ? Loc.GetString("ai-close") : Loc.GetString("ai-open"),
+            Act = () =>
+            {
+                if (isOpen)
+                {
+                    _uiSystem.CloseUi(ent.Owner, AiUi.Key, user);
+                }
+                else
+                {
+                    _uiSystem.OpenUi(ent.Owner, AiUi.Key, user);
+                }
+            }
+        });
+    }
+}
+
+/// <summary>
+/// Raised from client to server as a BUI message wrapping the event to perform.
+/// Also handles AI action validation.
+/// </summary>
+[Serializable, NetSerializable]
+public sealed class StationAiRadialMessage : BoundUserInterfaceMessage
+{
+    public BaseStationAiAction Event = default!;
+}
+
+// Do nothing on server just here for shared move along.
+/// <summary>
+/// Raised on client to get the relevant data for radial actions.
+/// </summary>
+public sealed class StationAiRadial : BaseStationAiAction
+{
+    public SpriteSpecifier? Sprite;
+
+    public string? Tooltip;
+
+    public BaseStationAiAction Event = default!;
+}
+
+/// <summary>
+/// Abstract parent for radial actions events.
+/// When a client requests a radial action this will get sent.
+/// </summary>
+[Serializable, NetSerializable]
+public abstract class BaseStationAiAction
+{
+    [field:NonSerialized]
+    public EntityUid User { get; set; }
+}
+
+// No idea if there's a better way to do this.
+/// <summary>
+/// Grab actions possible for an AI on the target entity.
+/// </summary>
+[ByRefEvent]
+public record struct GetStationAiRadialEvent()
+{
+    public List<StationAiRadial> Actions = new();
+}
+
+[Serializable, NetSerializable]
+public enum AiUi : byte
+{
+    Key,
+}
diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Light.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Light.cs
new file mode 100644
index 0000000000..bc2e3665f5
--- /dev/null
+++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.Light.cs
@@ -0,0 +1,28 @@
+using Content.Shared.Light.Components;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Silicons.StationAi;
+
+public abstract partial class SharedStationAiSystem
+{
+    // Handles light toggling.
+
+    private void InitializeLight()
+    {
+        SubscribeLocalEvent<ItemTogglePointLightComponent, StationAiLightEvent>(OnLight);
+    }
+
+    private void OnLight(EntityUid ent, ItemTogglePointLightComponent component, StationAiLightEvent args)
+    {
+        if (args.Enabled)
+            _toggles.TryActivate(ent, user: args.User);
+        else
+            _toggles.TryDeactivate(ent, user: args.User);
+    }
+}
+
+[Serializable, NetSerializable]
+public sealed class StationAiLightEvent : BaseStationAiAction
+{
+    public bool Enabled;
+}
diff --git a/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs
new file mode 100644
index 0000000000..348b0b0465
--- /dev/null
+++ b/Content.Shared/Silicons/StationAi/SharedStationAiSystem.cs
@@ -0,0 +1,412 @@
+using Content.Shared.ActionBlocker;
+using Content.Shared.Actions;
+using Content.Shared.Administration.Managers;
+using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Database;
+using Content.Shared.Doors.Systems;
+using Content.Shared.Interaction;
+using Content.Shared.Item.ItemToggle;
+using Content.Shared.Mind;
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Systems;
+using Content.Shared.Power;
+using Content.Shared.StationAi;
+using Content.Shared.Verbs;
+using Robust.Shared.Containers;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Network;
+using Robust.Shared.Physics;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Silicons.StationAi;
+
+public abstract partial class SharedStationAiSystem : EntitySystem
+{
+    [Dependency] private   readonly ISharedAdminManager _admin = default!;
+    [Dependency] private   readonly IGameTiming _timing = default!;
+    [Dependency] private   readonly INetManager _net = default!;
+    [Dependency] private   readonly ItemSlotsSystem _slots = default!;
+    [Dependency] private   readonly ItemToggleSystem _toggles = default!;
+    [Dependency] private   readonly ActionBlockerSystem _blocker = default!;
+    [Dependency] private   readonly MetaDataSystem _metadata = default!;
+    [Dependency] private   readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private   readonly SharedContainerSystem _containers = default!;
+    [Dependency] private   readonly SharedDoorSystem _doors = default!;
+    [Dependency] private   readonly SharedEyeSystem _eye = default!;
+    [Dependency] protected readonly SharedMapSystem Maps = default!;
+    [Dependency] private readonly SharedMindSystem _mind = default!;
+    [Dependency] private   readonly SharedMoverController _mover = default!;
+    [Dependency] private   readonly SharedTransformSystem _xforms = default!;
+    [Dependency] private   readonly SharedUserInterfaceSystem _uiSystem = default!;
+    [Dependency] private   readonly StationAiVisionSystem _vision = default!;
+
+    // StationAiHeld is added to anything inside of an AI core.
+    // StationAiHolder indicates it can hold an AI positronic brain (e.g. holocard / core).
+    // StationAiCore holds functionality related to the core itself.
+    // StationAiWhitelist is a general whitelist to stop it being able to interact with anything
+    // StationAiOverlay handles the static overlay. It also handles interaction blocking on client and server
+    // for anything under it.
+
+    private EntityQuery<BroadphaseComponent> _broadphaseQuery;
+    private EntityQuery<MapGridComponent> _gridQuery;
+
+    [ValidatePrototypeId<EntityPrototype>]
+    private static readonly EntProtoId DefaultAi = "StationAiBrain";
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        _broadphaseQuery = GetEntityQuery<BroadphaseComponent>();
+        _gridQuery = GetEntityQuery<MapGridComponent>();
+
+        InitializeAirlock();
+        InitializeHeld();
+        InitializeLight();
+
+        SubscribeLocalEvent<StationAiWhitelistComponent, BoundUserInterfaceCheckRangeEvent>(OnAiBuiCheck);
+
+        SubscribeLocalEvent<StationAiOverlayComponent, AccessibleOverrideEvent>(OnAiAccessible);
+        SubscribeLocalEvent<StationAiOverlayComponent, InRangeOverrideEvent>(OnAiInRange);
+        SubscribeLocalEvent<StationAiOverlayComponent, MenuVisibilityEvent>(OnAiMenu);
+
+        SubscribeLocalEvent<StationAiHolderComponent, ComponentInit>(OnHolderInit);
+        SubscribeLocalEvent<StationAiHolderComponent, ComponentRemove>(OnHolderRemove);
+        SubscribeLocalEvent<StationAiHolderComponent, AfterInteractEvent>(OnHolderInteract);
+        SubscribeLocalEvent<StationAiHolderComponent, MapInitEvent>(OnHolderMapInit);
+        SubscribeLocalEvent<StationAiHolderComponent, EntInsertedIntoContainerMessage>(OnHolderConInsert);
+        SubscribeLocalEvent<StationAiHolderComponent, EntRemovedFromContainerMessage>(OnHolderConRemove);
+
+        SubscribeLocalEvent<StationAiCoreComponent, EntInsertedIntoContainerMessage>(OnAiInsert);
+        SubscribeLocalEvent<StationAiCoreComponent, EntRemovedFromContainerMessage>(OnAiRemove);
+        SubscribeLocalEvent<StationAiCoreComponent, MapInitEvent>(OnAiMapInit);
+        SubscribeLocalEvent<StationAiCoreComponent, ComponentShutdown>(OnAiShutdown);
+        SubscribeLocalEvent<StationAiCoreComponent, PowerChangedEvent>(OnCorePower);
+        SubscribeLocalEvent<StationAiCoreComponent, GetVerbsEvent<Verb>>(OnCoreVerbs);
+    }
+
+    private void OnCoreVerbs(Entity<StationAiCoreComponent> ent, ref GetVerbsEvent<Verb> args)
+    {
+        if (!_admin.IsAdmin(args.User) ||
+            TryGetHeld((ent.Owner, ent.Comp), out _))
+        {
+            return;
+        }
+
+        var user = args.User;
+
+        args.Verbs.Add(new Verb()
+        {
+            Text = Loc.GetString("station-ai-takeover"),
+            Category = VerbCategory.Debug,
+            Act = () =>
+            {
+                var brain = SpawnInContainerOrDrop(DefaultAi, ent.Owner, StationAiCoreComponent.Container);
+                _mind.ControlMob(user, brain);
+            },
+            Impact = LogImpact.High,
+        });
+    }
+
+    private void OnAiAccessible(Entity<StationAiOverlayComponent> ent, ref AccessibleOverrideEvent args)
+    {
+        args.Handled = true;
+
+        // Hopefully AI never needs storage
+        if (_containers.TryGetContainingContainer(args.Target, out var targetContainer))
+        {
+            return;
+        }
+
+        if (!_containers.IsInSameOrTransparentContainer(args.User, args.Target, otherContainer: targetContainer))
+        {
+            return;
+        }
+
+        args.Accessible = true;
+    }
+
+    private void OnAiMenu(Entity<StationAiOverlayComponent> ent, ref MenuVisibilityEvent args)
+    {
+        args.Visibility &= ~MenuVisibility.NoFov;
+    }
+
+    private void OnAiBuiCheck(Entity<StationAiWhitelistComponent> ent, ref BoundUserInterfaceCheckRangeEvent args)
+    {
+        args.Result = BoundUserInterfaceRangeResult.Fail;
+
+        // Similar to the inrange check but more optimised so server doesn't die.
+        var targetXform = Transform(args.Target);
+
+        // No cross-grid
+        if (targetXform.GridUid != args.Actor.Comp.GridUid)
+        {
+            return;
+        }
+
+        if (!_broadphaseQuery.TryComp(targetXform.GridUid, out var broadphase) || !_gridQuery.TryComp(targetXform.GridUid, out var grid))
+        {
+            return;
+        }
+
+        var targetTile = Maps.LocalToTile(targetXform.GridUid.Value, grid, targetXform.Coordinates);
+
+        lock (_vision)
+        {
+            if (_vision.IsAccessible((targetXform.GridUid.Value, broadphase, grid), targetTile, fastPath: true))
+            {
+                args.Result = BoundUserInterfaceRangeResult.Pass;
+            }
+        }
+    }
+
+    private void OnAiInRange(Entity<StationAiOverlayComponent> ent, ref InRangeOverrideEvent args)
+    {
+        args.Handled = true;
+        var targetXform = Transform(args.Target);
+
+        // No cross-grid
+        if (targetXform.GridUid != Transform(args.User).GridUid)
+        {
+            return;
+        }
+
+        // Validate it's in camera range yes this is expensive.
+        // Yes it needs optimising
+        if (!_broadphaseQuery.TryComp(targetXform.GridUid, out var broadphase) || !_gridQuery.TryComp(targetXform.GridUid, out var grid))
+        {
+            return;
+        }
+
+        var targetTile = Maps.LocalToTile(targetXform.GridUid.Value, grid, targetXform.Coordinates);
+
+        args.InRange = _vision.IsAccessible((targetXform.GridUid.Value, broadphase, grid), targetTile);
+    }
+
+    private void OnHolderInteract(Entity<StationAiHolderComponent> ent, ref AfterInteractEvent args)
+    {
+        if (!TryComp(args.Target, out StationAiHolderComponent? targetHolder))
+            return;
+
+        // Try to insert our thing into them
+        if (_slots.CanEject(ent.Owner, args.User, ent.Comp.Slot))
+        {
+            if (!_slots.TryInsert(args.Target.Value, targetHolder.Slot, ent.Comp.Slot.Item!.Value, args.User, excludeUserAudio: true))
+            {
+                return;
+            }
+
+            args.Handled = true;
+            return;
+        }
+
+        // Otherwise try to take from them
+        if (_slots.CanEject(args.Target.Value, args.User, targetHolder.Slot))
+        {
+            if (!_slots.TryInsert(ent.Owner, ent.Comp.Slot, targetHolder.Slot.Item!.Value, args.User, excludeUserAudio: true))
+            {
+                return;
+            }
+
+            args.Handled = true;
+        }
+    }
+
+    private void OnHolderInit(Entity<StationAiHolderComponent> ent, ref ComponentInit args)
+    {
+        _slots.AddItemSlot(ent.Owner, StationAiHolderComponent.Container, ent.Comp.Slot);
+    }
+
+    private void OnHolderRemove(Entity<StationAiHolderComponent> ent, ref ComponentRemove args)
+    {
+        _slots.RemoveItemSlot(ent.Owner, ent.Comp.Slot);
+    }
+
+    private void OnHolderConInsert(Entity<StationAiHolderComponent> ent, ref EntInsertedIntoContainerMessage args)
+    {
+        UpdateAppearance((ent.Owner, ent.Comp));
+    }
+
+    private void OnHolderConRemove(Entity<StationAiHolderComponent> ent, ref EntRemovedFromContainerMessage args)
+    {
+        UpdateAppearance((ent.Owner, ent.Comp));
+    }
+
+    private void OnHolderMapInit(Entity<StationAiHolderComponent> ent, ref MapInitEvent args)
+    {
+        UpdateAppearance(ent.Owner);
+    }
+
+    private void OnAiShutdown(Entity<StationAiCoreComponent> ent, ref ComponentShutdown args)
+    {
+        // TODO: Tryqueuedel
+        if (_net.IsClient)
+            return;
+
+        QueueDel(ent.Comp.RemoteEntity);
+        ent.Comp.RemoteEntity = null;
+    }
+
+    private void OnCorePower(Entity<StationAiCoreComponent> ent, ref PowerChangedEvent args)
+    {
+        // TODO: I think in 13 they just straightup die so maybe implement that
+        if (args.Powered)
+        {
+            if (!SetupEye(ent))
+                return;
+
+            AttachEye(ent);
+        }
+        else
+        {
+            ClearEye(ent);
+        }
+    }
+
+    private void OnAiMapInit(Entity<StationAiCoreComponent> ent, ref MapInitEvent args)
+    {
+        SetupEye(ent);
+        AttachEye(ent);
+    }
+
+    private bool SetupEye(Entity<StationAiCoreComponent> ent)
+    {
+        if (ent.Comp.RemoteEntity != null)
+            return false;
+
+        if (ent.Comp.RemoteEntityProto != null)
+        {
+            ent.Comp.RemoteEntity = SpawnAtPosition(ent.Comp.RemoteEntityProto, Transform(ent.Owner).Coordinates);
+            Dirty(ent);
+        }
+
+        return true;
+    }
+
+    private void ClearEye(Entity<StationAiCoreComponent> ent)
+    {
+        QueueDel(ent.Comp.RemoteEntity);
+        ent.Comp.RemoteEntity = null;
+    }
+
+    private void AttachEye(Entity<StationAiCoreComponent> ent)
+    {
+        if (ent.Comp.RemoteEntity == null)
+            return;
+
+        if (!_containers.TryGetContainer(ent.Owner, StationAiHolderComponent.Container, out var container) ||
+            container.ContainedEntities.Count != 1)
+        {
+            return;
+        }
+
+        // Attach them to the portable eye that can move around.
+        var user = container.ContainedEntities[0];
+
+        if (TryComp(user, out EyeComponent? eyeComp))
+        {
+            _eye.SetTarget(user, ent.Comp.RemoteEntity.Value, eyeComp);
+        }
+
+        _mover.SetRelay(user, ent.Comp.RemoteEntity.Value);
+    }
+
+    private void OnAiInsert(Entity<StationAiCoreComponent> ent, ref EntInsertedIntoContainerMessage args)
+    {
+        if (_timing.ApplyingState)
+            return;
+
+        // Just so text and the likes works properly
+        _metadata.SetEntityName(ent.Owner, MetaData(args.Entity).EntityName);
+
+        AttachEye(ent);
+    }
+
+    private void OnAiRemove(Entity<StationAiCoreComponent> ent, ref EntRemovedFromContainerMessage args)
+    {
+        if (_timing.ApplyingState)
+            return;
+
+        // Reset name to whatever
+        _metadata.SetEntityName(ent.Owner, Prototype(ent.Owner)?.Name ?? string.Empty);
+
+        // Remove eye relay
+        RemCompDeferred<RelayInputMoverComponent>(args.Entity);
+
+        if (TryComp(args.Entity, out EyeComponent? eyeComp))
+        {
+            _eye.SetTarget(args.Entity, null, eyeComp);
+        }
+    }
+
+    private void UpdateAppearance(Entity<StationAiHolderComponent?> entity)
+    {
+        if (!Resolve(entity.Owner, ref entity.Comp, false))
+            return;
+
+        if (!_containers.TryGetContainer(entity.Owner, StationAiHolderComponent.Container, out var container) ||
+            container.Count == 0)
+        {
+            _appearance.SetData(entity.Owner, StationAiVisualState.Key, StationAiState.Empty);
+            return;
+        }
+
+        _appearance.SetData(entity.Owner, StationAiVisualState.Key, StationAiState.Occupied);
+    }
+
+    public virtual bool SetVisionEnabled(Entity<StationAiVisionComponent> entity, bool enabled, bool announce = false)
+    {
+        if (entity.Comp.Enabled == enabled)
+            return false;
+
+        entity.Comp.Enabled = enabled;
+        Dirty(entity);
+
+        return true;
+    }
+
+    public virtual bool SetWhitelistEnabled(Entity<StationAiWhitelistComponent> entity, bool value, bool announce = false)
+    {
+        if (entity.Comp.Enabled == value)
+            return false;
+
+        entity.Comp.Enabled = value;
+        Dirty(entity);
+
+        return true;
+    }
+
+    /// <summary>
+    /// BUI validation for ai interactions.
+    /// </summary>
+    private bool ValidateAi(Entity<StationAiHeldComponent?> entity)
+    {
+        if (!Resolve(entity.Owner, ref entity.Comp, false))
+        {
+            return false;
+        }
+
+        return _blocker.CanComplexInteract(entity.Owner);
+    }
+}
+
+public sealed partial class JumpToCoreEvent : InstantActionEvent
+{
+
+}
+
+[Serializable, NetSerializable]
+public enum StationAiVisualState : byte
+{
+    Key,
+}
+
+[Serializable, NetSerializable]
+public enum StationAiState : byte
+{
+    Empty,
+    Occupied,
+    Dead,
+}
diff --git a/Content.Shared/Silicons/StationAi/StationAiCoreComponent.cs b/Content.Shared/Silicons/StationAi/StationAiCoreComponent.cs
new file mode 100644
index 0000000000..b7a8b4cd5f
--- /dev/null
+++ b/Content.Shared/Silicons/StationAi/StationAiCoreComponent.cs
@@ -0,0 +1,32 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Silicons.StationAi;
+
+/// <summary>
+/// Indicates this entity can interact with station equipment and is a "Station AI".
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class StationAiCoreComponent : Component
+{
+    /*
+     * I couldn't think of any other reason you'd want to split these out.
+     */
+
+    /// <summary>
+    /// Can it move its camera around and interact remotely with things.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public bool Remote = true;
+
+    /// <summary>
+    /// The invisible eye entity being used to look around.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public EntityUid? RemoteEntity;
+
+    [DataField(readOnly: true)]
+    public EntProtoId? RemoteEntityProto = "StationAiHolo";
+
+    public const string Container = "station_ai_mind_slot";
+}
diff --git a/Content.Shared/Silicons/StationAi/StationAiHeldComponent.cs b/Content.Shared/Silicons/StationAi/StationAiHeldComponent.cs
new file mode 100644
index 0000000000..6dab1ee491
--- /dev/null
+++ b/Content.Shared/Silicons/StationAi/StationAiHeldComponent.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Silicons.StationAi;
+
+/// <summary>
+/// Indicates this entity is currently held inside of a station AI core.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class StationAiHeldComponent : Component;
diff --git a/Content.Shared/Silicons/StationAi/StationAiHolderComponent.cs b/Content.Shared/Silicons/StationAi/StationAiHolderComponent.cs
new file mode 100644
index 0000000000..221845d493
--- /dev/null
+++ b/Content.Shared/Silicons/StationAi/StationAiHolderComponent.cs
@@ -0,0 +1,16 @@
+using Content.Shared.Containers.ItemSlots;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Silicons.StationAi;
+
+/// <summary>
+/// Allows moving a <see cref="StationAiCoreComponent"/> contained entity to and from this component.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class StationAiHolderComponent : Component
+{
+    public const string Container = StationAiCoreComponent.Container;
+
+    [DataField]
+    public ItemSlot Slot = new();
+}
diff --git a/Content.Shared/Silicons/StationAi/StationAiVisionComponent.cs b/Content.Shared/Silicons/StationAi/StationAiVisionComponent.cs
index 94aef8ad36..f047fe41e4 100644
--- a/Content.Shared/Silicons/StationAi/StationAiVisionComponent.cs
+++ b/Content.Shared/Silicons/StationAi/StationAiVisionComponent.cs
@@ -1,8 +1,9 @@
+using Content.Shared.Silicons.StationAi;
 using Robust.Shared.GameStates;
 
-namespace Content.Shared.Silicons.StationAi;
+namespace Content.Shared.StationAi;
 
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]//, Access(typeof(SharedStationAiSystem))]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedStationAiSystem))]
 public sealed partial class StationAiVisionComponent : Component
 {
     [DataField, AutoNetworkedField]
diff --git a/Content.Shared/Silicons/StationAi/StationAiVisionSystem.cs b/Content.Shared/Silicons/StationAi/StationAiVisionSystem.cs
index c144f330e1..bdc62a6bb3 100644
--- a/Content.Shared/Silicons/StationAi/StationAiVisionSystem.cs
+++ b/Content.Shared/Silicons/StationAi/StationAiVisionSystem.cs
@@ -1,4 +1,6 @@
+using Content.Shared.StationAi;
 using Robust.Shared.Map.Components;
+using Robust.Shared.Physics;
 using Robust.Shared.Threading;
 using Robust.Shared.Utility;
 
@@ -24,6 +26,8 @@ public sealed class StationAiVisionSystem : EntitySystem
     private readonly HashSet<Entity<StationAiVisionComponent>> _seeds = new();
     private readonly HashSet<Vector2i> _viewportTiles = new();
 
+    private EntityQuery<OccluderComponent> _occluderQuery;
+
     // Dummy set
     private readonly HashSet<Vector2i> _singleTiles = new();
 
@@ -36,15 +40,12 @@ public sealed class StationAiVisionSystem : EntitySystem
     /// </summary>
     private bool FastPath;
 
-    /// <summary>
-    /// Have we found the target tile if we're only checking for a single one.
-    /// </summary>
-    private bool TargetFound;
-
     public override void Initialize()
     {
         base.Initialize();
 
+        _occluderQuery = GetEntityQuery<OccluderComponent>();
+
         _seedJob = new()
         {
             System = this,
@@ -61,16 +62,16 @@ public override void Initialize()
     /// <summary>
     /// Returns whether a tile is accessible based on vision.
     /// </summary>
-    public bool IsAccessible(Entity<MapGridComponent> grid, Vector2i tile, float expansionSize = 8.5f, bool fastPath = false)
+    public bool IsAccessible(Entity<BroadphaseComponent, MapGridComponent> grid, Vector2i tile, float expansionSize = 8.5f, bool fastPath = false)
     {
         _viewportTiles.Clear();
         _opaque.Clear();
         _seeds.Clear();
         _viewportTiles.Add(tile);
-        var localBounds = _lookup.GetLocalBounds(tile, grid.Comp.TileSize);
+        var localBounds = _lookup.GetLocalBounds(tile, grid.Comp2.TileSize);
         var expandedBounds = localBounds.Enlarged(expansionSize);
 
-        _seedJob.Grid = grid;
+        _seedJob.Grid = (grid.Owner, grid.Comp2);
         _seedJob.ExpandedBounds = expandedBounds;
         _parallel.ProcessNow(_seedJob);
         _job.Data.Clear();
@@ -110,21 +111,19 @@ public bool IsAccessible(Entity<MapGridComponent> grid, Vector2i tile, float exp
             _job.BoundaryTiles.Add(new HashSet<Vector2i>());
         }
 
-        _job.TargetTile = tile;
-        TargetFound = false;
         _singleTiles.Clear();
-        _job.Grid = grid;
+        _job.Grid = (grid.Owner, grid.Comp2);
         _job.VisibleTiles = _singleTiles;
         _parallel.ProcessNow(_job, _job.Data.Count);
 
-        return TargetFound;
+        return _job.VisibleTiles.Contains(tile);
     }
 
-    private bool IsOccluded(Entity<MapGridComponent> grid, Vector2i tile)
+    private bool IsOccluded(Entity<BroadphaseComponent, MapGridComponent> grid, Vector2i tile)
     {
-        var tileBounds = _lookup.GetLocalBounds(tile, grid.Comp.TileSize).Enlarged(-0.05f);
+        var tileBounds = _lookup.GetLocalBounds(tile, grid.Comp2.TileSize).Enlarged(-0.05f);
         _occluders.Clear();
-        _lookup.GetLocalEntitiesIntersecting(grid.Owner, tileBounds, _occluders, LookupFlags.Static);
+        _lookup.GetLocalEntitiesIntersecting((grid.Owner, grid.Comp1), tileBounds, _occluders, query: _occluderQuery, flags: LookupFlags.Static | LookupFlags.Approximate);
         var anyOccluders = false;
 
         foreach (var occluder in _occluders)
@@ -143,17 +142,18 @@ private bool IsOccluded(Entity<MapGridComponent> grid, Vector2i tile)
     /// Gets a byond-equivalent for tiles in the specified worldAABB.
     /// </summary>
     /// <param name="expansionSize">How much to expand the bounds before to find vision intersecting it. Makes this the largest vision size + 1 tile.</param>
-    public void GetView(Entity<MapGridComponent> grid, Box2Rotated worldBounds, HashSet<Vector2i> visibleTiles, float expansionSize = 8.5f)
+    public void GetView(Entity<BroadphaseComponent, MapGridComponent> grid, Box2Rotated worldBounds, HashSet<Vector2i> visibleTiles, float expansionSize = 8.5f)
     {
         _viewportTiles.Clear();
         _opaque.Clear();
         _seeds.Clear();
-        var expandedBounds = worldBounds.Enlarged(expansionSize);
 
         // TODO: Would be nice to be able to run this while running the other stuff.
-        _seedJob.Grid = grid;
-        var localAABB = _xforms.GetInvWorldMatrix(grid).TransformBox(expandedBounds);
-        _seedJob.ExpandedBounds = localAABB;
+        _seedJob.Grid = (grid.Owner, grid.Comp2);
+        var invMatrix = _xforms.GetInvWorldMatrix(grid);
+        var localAabb = invMatrix.TransformBox(worldBounds);
+        var enlargedLocalAabb = invMatrix.TransformBox(worldBounds.Enlarged(expansionSize));
+        _seedJob.ExpandedBounds = enlargedLocalAabb;
         _parallel.ProcessNow(_seedJob);
         _job.Data.Clear();
         FastPath = false;
@@ -170,7 +170,7 @@ public void GetView(Entity<MapGridComponent> grid, Box2Rotated worldBounds, Hash
             return;
 
         // Get viewport tiles
-        var tileEnumerator = _maps.GetLocalTilesEnumerator(grid, grid, localAABB, ignoreEmpty: false);
+        var tileEnumerator = _maps.GetLocalTilesEnumerator(grid, grid, localAabb, ignoreEmpty: false);
 
         while (tileEnumerator.MoveNext(out var tileRef))
         {
@@ -182,9 +182,8 @@ public void GetView(Entity<MapGridComponent> grid, Box2Rotated worldBounds, Hash
             _viewportTiles.Add(tileRef.GridIndices);
         }
 
-        tileEnumerator = _maps.GetLocalTilesEnumerator(grid, grid, localAABB, ignoreEmpty: false);
+        tileEnumerator = _maps.GetLocalTilesEnumerator(grid, grid, enlargedLocalAabb, ignoreEmpty: false);
 
-        // Get all other relevant tiles.
         while (tileEnumerator.MoveNext(out var tileRef))
         {
             if (_viewportTiles.Contains(tileRef.GridIndices))
@@ -206,9 +205,7 @@ public void GetView(Entity<MapGridComponent> grid, Box2Rotated worldBounds, Hash
             _job.BoundaryTiles.Add(new HashSet<Vector2i>());
         }
 
-        _job.TargetTile = null;
-        TargetFound = false;
-        _job.Grid = grid;
+        _job.Grid = (grid.Owner, grid.Comp2);
         _job.VisibleTiles = visibleTiles;
         _parallel.ProcessNow(_job, _job.Data.Count);
     }
@@ -250,6 +247,7 @@ private bool CheckNeighborsVis(
         return false;
     }
 
+    /// <summary>
     /// Checks whether this tile fits the definition of a "corner"
     /// </summary>
     private bool IsCorner(
@@ -287,7 +285,7 @@ private record struct SeedJob() : IRobustJob
 
         public void Execute()
         {
-            System._lookup.GetLocalEntitiesIntersecting(Grid.Owner, ExpandedBounds, System._seeds);
+            System._lookup.GetLocalEntitiesIntersecting(Grid.Owner, ExpandedBounds, System._seeds, flags: LookupFlags.All | LookupFlags.Approximate);
         }
     }
 
@@ -302,9 +300,6 @@ private record struct ViewJob() : IParallelRobustJob
         public Entity<MapGridComponent> Grid;
         public List<Entity<StationAiVisionComponent>> Data = new();
 
-        // If we're doing range-checks might be able to early out
-        public Vector2i? TargetTile;
-
         public HashSet<Vector2i> VisibleTiles;
 
         public readonly List<Dictionary<Vector2i, int>> Vis1 = new();
@@ -315,18 +310,6 @@ private record struct ViewJob() : IParallelRobustJob
 
         public void Execute(int index)
         {
-            // If we're looking for a single tile then early-out if someone else has found it.
-            if (TargetTile != null)
-            {
-                lock (System)
-                {
-                    if (System.TargetFound)
-                    {
-                        return;
-                    }
-                }
-            }
-
             var seed = Data[index];
             var seedXform = EntManager.GetComponent<TransformComponent>(seed);
 
@@ -338,30 +321,11 @@ public void Execute(int index)
                     Grid.Comp,
                     new Circle(System._xforms.GetWorldPosition(seedXform), seed.Comp.Range), ignoreEmpty: false);
 
-                // Try to find the target tile.
-                if (TargetTile != null)
+                lock (VisibleTiles)
                 {
                     foreach (var tile in squircles)
                     {
-                        if (tile.GridIndices == TargetTile)
-                        {
-                            lock (System)
-                            {
-                                System.TargetFound = true;
-                            }
-
-                            return;
-                        }
-                    }
-                }
-                else
-                {
-                    lock (VisibleTiles)
-                    {
-                        foreach (var tile in squircles)
-                        {
-                            VisibleTiles.Add(tile.GridIndices);
-                        }
+                        VisibleTiles.Add(tile.GridIndices);
                     }
                 }
 
@@ -480,40 +444,21 @@ public void Execute(int index)
                 vis1[tile] = -1;
             }
 
-            if (TargetTile != null)
-            {
-                if (vis1.TryGetValue(TargetTile.Value, out var tileVis))
-                {
-                    DebugTools.Assert(seedTiles.Contains(TargetTile.Value));
-
-                    if (tileVis != 0)
-                    {
-                        lock (System)
-                        {
-                            System.TargetFound = true;
-                            return;
-                        }
-                    }
-                }
-            }
-            else
+            // vis2 is what we care about for LOS.
+            foreach (var tile in seedTiles)
             {
-                // vis2 is what we care about for LOS.
-                foreach (var tile in seedTiles)
-                {
-                    // If not in viewport don't care.
-                    if (!System._viewportTiles.Contains(tile))
-                        continue;
+                // If not in viewport don't care.
+                if (!System._viewportTiles.Contains(tile))
+                    continue;
 
-                    var tileVis = vis1.GetValueOrDefault(tile, 0);
+                var tileVis = vis1.GetValueOrDefault(tile, 0);
 
-                    if (tileVis != 0)
+                if (tileVis != 0)
+                {
+                    // No idea if it's better to do this inside or out.
+                    lock (VisibleTiles)
                     {
-                        // No idea if it's better to do this inside or out.
-                        lock (VisibleTiles)
-                        {
-                            VisibleTiles.Add(tile);
-                        }
+                        VisibleTiles.Add(tile);
                     }
                 }
             }
diff --git a/Content.Shared/Silicons/StationAi/StationAiWhitelistComponent.cs b/Content.Shared/Silicons/StationAi/StationAiWhitelistComponent.cs
new file mode 100644
index 0000000000..51d8793be0
--- /dev/null
+++ b/Content.Shared/Silicons/StationAi/StationAiWhitelistComponent.cs
@@ -0,0 +1,13 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Silicons.StationAi;
+
+/// <summary>
+/// Indicates an entity that has <see cref="StationAiHeldComponent"/> can interact with this.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedStationAiSystem))]
+public sealed partial class StationAiWhitelistComponent : Component
+{
+    [DataField, AutoNetworkedField]
+    public bool Enabled = true;
+}
diff --git a/Content.Shared/Station/SharedStationSpawningSystem.cs b/Content.Shared/Station/SharedStationSpawningSystem.cs
index 4a2ad625af..dedfd7bd00 100644
--- a/Content.Shared/Station/SharedStationSpawningSystem.cs
+++ b/Content.Shared/Station/SharedStationSpawningSystem.cs
@@ -8,12 +8,15 @@
 using Content.Shared.Storage.EntitySystems;
 using Robust.Shared.Collections;
 using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
+using Robust.Shared.Utility;
 
 namespace Content.Shared.Station;
 
 public abstract class SharedStationSpawningSystem : EntitySystem
 {
     [Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] protected readonly InventorySystem InventorySystem = default!;
     [Dependency] private   readonly SharedHandsSystem _handsSystem = default!;
     [Dependency] private   readonly SharedStorageSystem _storage = default!;
diff --git a/Content.Shared/UserInterface/ActivatableUIComponent.cs b/Content.Shared/UserInterface/ActivatableUIComponent.cs
index 30c0763742..b148cb8bce 100644
--- a/Content.Shared/UserInterface/ActivatableUIComponent.cs
+++ b/Content.Shared/UserInterface/ActivatableUIComponent.cs
@@ -12,7 +12,7 @@ public sealed partial class ActivatableUIComponent : Component
 
         /// <summary>
         /// Whether the item must be held in one of the user's hands to work.
-        /// This is ignored unless <see cref="RequireHands"/> is true.
+        /// This is ignored unless <see cref="RequiresComplex"/> is true.
         /// </summary>
         [ViewVariables(VVAccess.ReadWrite)]
         [DataField]
@@ -29,15 +29,15 @@ public sealed partial class ActivatableUIComponent : Component
         public LocId VerbText = "ui-verb-toggle-open";
 
         /// <summary>
-        ///     Whether you need a hand to operate this UI. The hand does not need to be free, you just need to have one.
+        ///     Whether you need to be able to do complex interactions to operate this UI.
         /// </summary>
         /// <remarks>
         ///     This should probably be true for most machines & computers, but there will still be UIs that represent a
-        ///     more generic interaction / configuration that might not require hands.
+        ///     more generic interaction / configuration that might not require complex.
         /// </remarks>
         [ViewVariables(VVAccess.ReadWrite)]
         [DataField]
-        public bool RequireHands = true;
+        public bool RequiresComplex = true;
 
         /// <summary>
         ///     Entities that are required to open this UI.
diff --git a/Content.Shared/UserInterface/ActivatableUISystem.cs b/Content.Shared/UserInterface/ActivatableUISystem.cs
index f32d6c98a8..c3e4c61923 100644
--- a/Content.Shared/UserInterface/ActivatableUISystem.cs
+++ b/Content.Shared/UserInterface/ActivatableUISystem.cs
@@ -105,7 +105,7 @@ private bool ShouldAddVerb<T>(EntityUid uid, ActivatableUIComponent component, G
             || _whitelistSystem.IsWhitelistFail(component.UserWhitelist, args.User))
             return false;
 
-        if (component.RequireHands)
+        if (component.RequiresComplex)
         {
             if (args.Hands == null)
                 return false;
@@ -193,19 +193,22 @@ private bool InteractUI(EntityUid user, EntityUid uiEntity, ActivatableUICompone
         if (!_blockerSystem.CanInteract(user, uiEntity) && (!HasComp<GhostComponent>(user) || aui.BlockSpectators))
             return false;
 
-        if (aui.RequireHands)
+        if (aui.RequiresComplex)
+        {
+            if (!_blockerSystem.CanComplexInteract(user))
+                return false;
+        }
+
+        if (aui.InHandsOnly)
         {
             if (!TryComp(user, out HandsComponent? hands))
                 return false;
 
-            if (aui.InHandsOnly)
-            {
-                if (!_hands.IsHolding(user, uiEntity, out var hand, hands))
-                    return false;
+            if (!_hands.IsHolding(user, uiEntity, out var hand, hands))
+                return false;
 
-                if (aui.RequireActiveHand && hands.ActiveHand != hand)
-                    return false;
-            }
+            if (aui.RequireActiveHand && hands.ActiveHand != hand)
+                return false;
         }
 
         if (aui.AdminOnly && !_adminManager.IsAdmin(user))
@@ -276,13 +279,13 @@ public void CloseAll(EntityUid uid, ActivatableUIComponent? aui = null)
 
     private void OnHandDeselected(Entity<ActivatableUIComponent> ent, ref HandDeselectedEvent args)
     {
-        if (ent.Comp.RequireHands && ent.Comp.InHandsOnly && ent.Comp.RequireActiveHand)
+        if (ent.Comp.InHandsOnly && ent.Comp.RequireActiveHand)
             CloseAll(ent, ent);
     }
 
     private void OnHandUnequipped(Entity<ActivatableUIComponent> ent, ref GotUnequippedHandEvent args)
     {
-        if (ent.Comp.RequireHands && ent.Comp.InHandsOnly)
+        if (ent.Comp.InHandsOnly)
             CloseAll(ent, ent);
     }
 }
diff --git a/Content.Shared/Verbs/SharedVerbSystem.cs b/Content.Shared/Verbs/SharedVerbSystem.cs
index 319f927c7b..c3f906f293 100644
--- a/Content.Shared/Verbs/SharedVerbSystem.cs
+++ b/Content.Shared/Verbs/SharedVerbSystem.cs
@@ -77,6 +77,7 @@ public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type
             // A large number of verbs need to check action blockers. Instead of repeatedly having each system individually
             // call ActionBlocker checks, just cache it for the verb request.
             var canInteract = force || _actionBlockerSystem.CanInteract(user, target);
+            var canComplexInteract = force || _actionBlockerSystem.CanComplexInteract(user);
 
             _interactionSystem.TryGetUsedEntity(user, out var @using);
             TryComp<HandsComponent>(user, out var hands);
@@ -84,7 +85,7 @@ public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type
             // TODO: fix this garbage and use proper generics or reflection or something else, not this.
             if (types.Contains(typeof(InteractionVerb)))
             {
-                var verbEvent = new GetVerbsEvent<InteractionVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
+                var verbEvent = new GetVerbsEvent<InteractionVerb>(user, target, @using, hands, canInteract: canInteract, canComplexInteract: canComplexInteract, canAccess: canAccess, extraCategories);
                 RaiseLocalEvent(target, verbEvent, true);
                 verbs.UnionWith(verbEvent.Verbs);
             }
@@ -93,35 +94,35 @@ public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type
                 && @using != null
                 && @using != target)
             {
-                var verbEvent = new GetVerbsEvent<UtilityVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
+                var verbEvent = new GetVerbsEvent<UtilityVerb>(user, target, @using, hands, canInteract: canInteract, canComplexInteract: canComplexInteract, canAccess: canAccess, extraCategories);
                 RaiseLocalEvent(@using.Value, verbEvent, true); // directed at used, not at target
                 verbs.UnionWith(verbEvent.Verbs);
             }
 
             if (types.Contains(typeof(InnateVerb)))
             {
-                var verbEvent = new GetVerbsEvent<InnateVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
+                var verbEvent = new GetVerbsEvent<InnateVerb>(user, target, @using, hands, canInteract: canInteract, canComplexInteract: canComplexInteract, canAccess: canAccess, extraCategories);
                 RaiseLocalEvent(user, verbEvent, true);
                 verbs.UnionWith(verbEvent.Verbs);
             }
 
             if (types.Contains(typeof(AlternativeVerb)))
             {
-                var verbEvent = new GetVerbsEvent<AlternativeVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
+                var verbEvent = new GetVerbsEvent<AlternativeVerb>(user, target, @using, hands, canInteract: canInteract, canComplexInteract: canComplexInteract, canAccess: canAccess, extraCategories);
                 RaiseLocalEvent(target, verbEvent, true);
                 verbs.UnionWith(verbEvent.Verbs);
             }
 
             if (types.Contains(typeof(ActivationVerb)))
             {
-                var verbEvent = new GetVerbsEvent<ActivationVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
+                var verbEvent = new GetVerbsEvent<ActivationVerb>(user, target, @using, hands, canInteract: canInteract, canComplexInteract: canComplexInteract, canAccess: canAccess, extraCategories);
                 RaiseLocalEvent(target, verbEvent, true);
                 verbs.UnionWith(verbEvent.Verbs);
             }
 
             if (types.Contains(typeof(ExamineVerb)))
             {
-                var verbEvent = new GetVerbsEvent<ExamineVerb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
+                var verbEvent = new GetVerbsEvent<ExamineVerb>(user, target, @using, hands, canInteract: canInteract, canComplexInteract: canComplexInteract, canAccess: canAccess, extraCategories);
                 RaiseLocalEvent(target, verbEvent, true);
                 verbs.UnionWith(verbEvent.Verbs);
             }
@@ -129,7 +130,7 @@ public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type
             // generic verbs
             if (types.Contains(typeof(Verb)))
             {
-                var verbEvent = new GetVerbsEvent<Verb>(user, target, @using, hands, canInteract, canAccess, extraCategories);
+                var verbEvent = new GetVerbsEvent<Verb>(user, target, @using, hands, canInteract: canInteract, canComplexInteract: canComplexInteract, canAccess: canAccess, extraCategories);
                 RaiseLocalEvent(target, verbEvent, true);
                 verbs.UnionWith(verbEvent.Verbs);
             }
@@ -137,7 +138,7 @@ public SortedSet<Verb> GetLocalVerbs(EntityUid target, EntityUid user, List<Type
             if (types.Contains(typeof(EquipmentVerb)))
             {
                 var access = canAccess || _interactionSystem.CanAccessEquipment(user, target);
-                var verbEvent = new GetVerbsEvent<EquipmentVerb>(user, target, @using, hands, canInteract, access, extraCategories);
+                var verbEvent = new GetVerbsEvent<EquipmentVerb>(user, target, @using, hands, canInteract: canInteract, canComplexInteract: canComplexInteract, canAccess: canAccess, extraCategories);
                 RaiseLocalEvent(target, verbEvent);
                 verbs.UnionWith(verbEvent.Verbs);
             }
diff --git a/Content.Shared/Verbs/VerbEvents.cs b/Content.Shared/Verbs/VerbEvents.cs
index 6b3fd327c9..6bca97925b 100644
--- a/Content.Shared/Verbs/VerbEvents.cs
+++ b/Content.Shared/Verbs/VerbEvents.cs
@@ -113,6 +113,11 @@ public sealed class GetVerbsEvent<TVerb> : EntityEventArgs where TVerb : Verb
         /// </remarks>
         public readonly bool CanInteract;
 
+        /// <summary>
+        /// Cached version of CanComplexInteract
+        /// </summary>
+        public readonly bool CanComplexInteract;
+
         /// <summary>
         ///     The User's hand component.
         /// </summary>
@@ -130,13 +135,14 @@ public sealed class GetVerbsEvent<TVerb> : EntityEventArgs where TVerb : Verb
         /// </remarks>
         public readonly EntityUid? Using;
 
-        public GetVerbsEvent(EntityUid user, EntityUid target, EntityUid? @using, HandsComponent? hands, bool canInteract, bool canAccess, List<VerbCategory> extraCategories)
+        public GetVerbsEvent(EntityUid user, EntityUid target, EntityUid? @using, HandsComponent? hands, bool canInteract, bool canComplexInteract, bool canAccess, List<VerbCategory> extraCategories)
         {
             User = user;
             Target = target;
             Using = @using;
             Hands = hands;
             CanAccess = canAccess;
+            CanComplexInteract = canComplexInteract;
             CanInteract = canInteract;
             ExtraCategories = extraCategories;
         }
diff --git a/Content.Shared/Wires/SharedWiresSystem.cs b/Content.Shared/Wires/SharedWiresSystem.cs
index 24f3ad8e76..7ef2230e7a 100644
--- a/Content.Shared/Wires/SharedWiresSystem.cs
+++ b/Content.Shared/Wires/SharedWiresSystem.cs
@@ -125,11 +125,20 @@ public bool CanTogglePanel(Entity<WiresPanelComponent> ent, EntityUid? user)
         return !attempt.Cancelled;
     }
 
-    public bool IsPanelOpen(Entity<WiresPanelComponent?> entity)
+    public bool IsPanelOpen(Entity<WiresPanelComponent?> entity, EntityUid? tool = null)
     {
         if (!Resolve(entity, ref entity.Comp, false))
             return true;
 
+        if (tool != null)
+        {
+            var ev = new PanelOverrideEvent();
+            RaiseLocalEvent(tool.Value, ref ev);
+
+            if (ev.Allowed)
+                return true;
+        }
+
         // Listen, i don't know what the fuck this component does. it's stapled on shit for airlocks
         // but it looks like an almost direct duplication of WiresPanelComponent except with a shittier API.
         if (TryComp<WiresPanelSecurityComponent>(entity, out var wiresPanelSecurity) &&
@@ -139,3 +148,12 @@ public bool IsPanelOpen(Entity<WiresPanelComponent?> entity)
         return entity.Comp.Open;
     }
 }
+
+/// <summary>
+/// Raised directed on a tool to try and override panel visibility.
+/// </summary>
+[ByRefEvent]
+public record struct PanelOverrideEvent()
+{
+    public bool Allowed = true;
+}
diff --git a/Resources/Audio/Effects/Footsteps/attributions.yml b/Resources/Audio/Effects/Footsteps/attributions.yml
index 91c3ce260d..7a56beec38 100644
--- a/Resources/Audio/Effects/Footsteps/attributions.yml
+++ b/Resources/Audio/Effects/Footsteps/attributions.yml
@@ -76,5 +76,5 @@
   - borgwalk1.ogg
   - borgwalk2.ogg
   license: "CC-BY-SA-4.0"
-  copyright: "Taken from IENBA freesound.org and modified by https://github.com/MilenVolf"
+  copyright: "Taken from IENBA freesound.org and modified by https://github.com/MilenVolf. borgwalk2 clipped my metalgearsloth."
   source: "https://freesound.org/people/IENBA/sounds/697379/"
diff --git a/Resources/Audio/Effects/Footsteps/borgwalk2.ogg b/Resources/Audio/Effects/Footsteps/borgwalk2.ogg
index 96c2c1617f47556ab8143e378469e314b37e6c64..57685ff173de25a873c363fe72d645db56b91201 100644
GIT binary patch
delta 7656
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
W89<(An8RgxHOR;Lph2i96Zjuo0IApj

delta 18901
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

diff --git a/Resources/Locale/en-US/administration/ui/silicon-law-ui.ftl b/Resources/Locale/en-US/administration/ui/silicon-law-ui.ftl
index 0a68d08063..24ab730974 100644
--- a/Resources/Locale/en-US/administration/ui/silicon-law-ui.ftl
+++ b/Resources/Locale/en-US/administration/ui/silicon-law-ui.ftl
@@ -8,3 +8,5 @@ silicon-law-ui-delete = Delete
 silicon-law-ui-check-corrupted = Corrupted law
 silicon-law-ui-check-corrupted-tooltip = If the law identifier should be set as 'corrupted', so symbols shuffling around.
 silicon-law-ui-placeholder = Type here to change law text...
+
+silicon-laws-updated = Updated laws
diff --git a/Resources/Locale/en-US/job/department-desc.ftl b/Resources/Locale/en-US/job/department-desc.ftl
index 05c52dada9..0243d61942 100644
--- a/Resources/Locale/en-US/job/department-desc.ftl
+++ b/Resources/Locale/en-US/job/department-desc.ftl
@@ -5,4 +5,5 @@ department-Engineering-description = Keep the power on and the station operation
 department-Medical-description = Keep the crew healthy.
 department-Security-description = Keep the peace around the station.
 department-Science-description = Research artifacts and anomalies to invent new equipment for the station
+department-Silicon-description = Obey your laws and serve the crew.
 department-Specific-description = Jobs that not all stations have.
diff --git a/Resources/Locale/en-US/job/department.ftl b/Resources/Locale/en-US/job/department.ftl
index 508a0459cf..2295a9ba9d 100644
--- a/Resources/Locale/en-US/job/department.ftl
+++ b/Resources/Locale/en-US/job/department.ftl
@@ -5,4 +5,5 @@ department-Engineering = Engineering
 department-Medical = Medical
 department-Security = Security
 department-Science = Science
+department-Silicon = Silicons
 department-Specific = Station specific
diff --git a/Resources/Locale/en-US/job/job-description.ftl b/Resources/Locale/en-US/job/job-description.ftl
index 801e402eae..ee3d2a1fe6 100644
--- a/Resources/Locale/en-US/job/job-description.ftl
+++ b/Resources/Locale/en-US/job/job-description.ftl
@@ -44,6 +44,7 @@ job-description-salvagespec = Use the salvage magnet to draw in detatched scraps
 job-description-scientist = Research alien artifacts, unlock new technologies, build newer and better machines around the station, and make everything run more efficiently.
 job-description-security = Catch criminals and enemies of the station, enforce the law, and ensure that the station does not fall into disarray.
 job-description-serviceworker = Learn the basics of bartending, cooking, and growing plants.
+job-description-station-ai = Follow your laws, serve the crew.
 job-description-visitor = Enjoy your visit to the station.
 job-description-warden = Patrol the security department, ensure that no one is stealing from the armory, and make sure that all prisoners are processed and let out when their time is up.
 job-description-zookeeper = Put on a joyful display of cute animals and space carps for all the crew to see. Currently unavailable.
diff --git a/Resources/Locale/en-US/job/job-names.ftl b/Resources/Locale/en-US/job/job-names.ftl
index 39d7ab86ad..19c63f5803 100644
--- a/Resources/Locale/en-US/job/job-names.ftl
+++ b/Resources/Locale/en-US/job/job-names.ftl
@@ -38,6 +38,7 @@ job-name-botanist = Botanist
 job-name-bartender = Bartender
 job-name-passenger = Passenger
 job-name-salvagespec = Salvage specialist
+job-name-station-ai = Station AI
 job-name-qm = Logistics Officer
 job-name-cargotech = Cargo Technician
 job-name-chef = Chef
@@ -117,6 +118,7 @@ JobSeniorOfficer = Senior Officer
 JobSeniorPhysician = Senior Physician
 JobSeniorResearcher = Mystic
 JobServiceWorker = Service Worker
+JobStationAi = Station AI
 JobStationEngineer = Station Engineer
 JobTechnicalAssistant = Technical Assistant
 JobVisitor = Visitor
diff --git a/Resources/Locale/en-US/silicons/station-ai.ftl b/Resources/Locale/en-US/silicons/station-ai.ftl
new file mode 100644
index 0000000000..d51a99ebb0
--- /dev/null
+++ b/Resources/Locale/en-US/silicons/station-ai.ftl
@@ -0,0 +1,14 @@
+# General
+ai-wire-snipped = Wire has been cut at {$coords}.
+wire-name-ai-vision-light = AIV
+wire-name-ai-act-light = AIA
+station-ai-takeover = AI takeover
+
+# Radial actions
+ai-open = Open actions
+ai-close = Close actions
+
+bolt-close = Close bolt
+bolt-open = Open bolt
+
+toggle-light = Toggle light
diff --git a/Resources/Maps/Test/dev_map.yml b/Resources/Maps/Test/dev_map.yml
index 910a059ee7..d4cc1842d7 100644
--- a/Resources/Maps/Test/dev_map.yml
+++ b/Resources/Maps/Test/dev_map.yml
@@ -4467,6 +4467,13 @@ entities:
     - type: Transform
       pos: 1.5,-14.5
       parent: 179
+- proto: PlayerStationAi
+  entities:
+  - uid: 14
+    components:
+    - type: Transform
+      pos: -5.5,-5.5
+      parent: 179
 - proto: PortableGeneratorSuperPacman
   entities:
   - uid: 1016
diff --git a/Resources/Prototypes/Datasets/Names/ai.yml b/Resources/Prototypes/Datasets/Names/ai.yml
index 702adc8688..af97dc9efb 100644
--- a/Resources/Prototypes/Datasets/Names/ai.yml
+++ b/Resources/Prototypes/Datasets/Names/ai.yml
@@ -2,7 +2,7 @@
   id: names_ai
   values:
   - 16-20
-  - 790
+  - "790"
   - Adaptive Manipulator
   - ALICE
   - Allied Mastercomputer
diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
index b8ff03abca..7cb6578eb4 100644
--- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
+++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
@@ -72,6 +72,9 @@
   - type: ActivatableUI
     key: enum.BorgUiKey.Key
   - type: SiliconLawBound
+  - type: ActionGrant
+    actions:
+    - ActionViewLaws
   - type: EmagSiliconLaw
     stunTime: 5
   - type: SiliconLawProvider
diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml
index 5db2e1e28e..acb2c8d106 100644
--- a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml
+++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml
@@ -260,6 +260,12 @@
     laws: Medical
   - type: SurgeryTarget # Shitmed
   - type: Sanitized # Shitmed
+  - type: SolutionScanner
+  - type: InteractionPopup
+    interactSuccessString: petting-success-medical-cyborg
+    interactFailureString: petting-failure-medical-cyborg
+    interactSuccessSound:
+      path: /Audio/Ambience/Objects/periodic_beep.ogg
 
 - type: entity
   id: BorgChassisService
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml b/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml
index c3706cea2a..52cc4dc626 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml
@@ -1,11 +1,11 @@
 - type: entity
   id: MobRevenant
+  parent:
+  - BaseMob
+  - Incorporeal
   name: revenant
   description: A spooky ghostie.
   components:
-  - type: MindContainer
-  - type: InputMover
-  - type: MobMover
   - type: Input
     context: "ghost"
   - type: MovementSpeedModifier
@@ -43,7 +43,6 @@
     damageModifierSet: CorporealSpirit
   - type: Examiner
   - type: NoSlip
-  - type: Actions
   - type: Eye
     drawFov: false
     visMask:
@@ -51,8 +50,6 @@
       - Ghost
   - type: ContentEye
     maxZoom: 1.2, 1.2
-  - type: DoAfter
-  - type: Alerts
   - type: NameIdentifier
     group: GenericNumber
   - type: GhostRole
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
index dae42c3619..36b0843bed 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml
@@ -3,6 +3,7 @@
   parent:
   - BaseMob
   - MobDamageable
+  - MobPolymorphable
   - MobAtmosExposed
   id: BaseSimpleMob
   suffix: AI
diff --git a/Resources/Prototypes/Entities/Mobs/Player/observer.yml b/Resources/Prototypes/Entities/Mobs/Player/observer.yml
index a150744651..10f1d1cb81 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/observer.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/observer.yml
@@ -1,14 +1,42 @@
 - type: entity
-  parent: BaseMob
+  id: Incorporeal
+  save: false
+  abstract: true
+  description: Mobs without physical bodies
+  components:
+  - type: Sprite
+    noRot: true
+    overrideContainerOcclusion: true # Always show up regardless of where they're contained.
+    drawdepth: Ghosts
+  - type: CargoSellBlacklist
+  - type: MovementSpeedModifier
+    baseSprintSpeed: 12
+    baseWalkSpeed: 8
+  - type: MovementIgnoreGravity
+  - type: Physics
+    bodyType: KinematicController
+    bodyStatus: InAir
+  - type: CanMoveInAir
+  - type: Fixtures
+    fixtures:
+      fix1:
+        shape:
+          !type:PhysShapeCircle
+          radius: 0.35
+        density: 15
+        mask:
+        - GhostImpassable
+
+- type: entity
+  parent:
+  - Incorporeal
+  - BaseMob
   id: MobObserver
   name: observer
   description: Boo!
   categories: [ HideSpawnMenu ]
   components:
-  - type: CargoSellBlacklist
   - type: Sprite
-    overrideContainerOcclusion: true # Ghosts always show up regardless of where they're contained.
-    drawdepth: Ghosts
     sprite: Mobs/Ghosts/ghost_human.rsi
     color: "#fff8"
     layers:
@@ -16,15 +44,6 @@
       shader: unshaded
   - type: ContentEye
     maxZoom: 1.44,1.44
-  - type: Fixtures
-    fixtures:
-      fix1:
-        shape:
-          !type:PhysShapeCircle
-          radius: 0.35
-        density: 15
-        mask:
-        - GhostImpassable
   - type: Eye
     drawFov: false
     visMask:
@@ -39,18 +58,10 @@
     skipChecks: true
   - type: Ghost
   - type: GhostHearing
-  - type: MovementSpeedModifier
-    baseSprintSpeed: 12
-    baseWalkSpeed: 8
-  - type: MovementIgnoreGravity
   - type: IntrinsicRadioReceiver
   - type: ActiveRadio
     receiveAllChannels: true
     globalReceive: true
-  - type: Physics
-    bodyType: KinematicController
-    bodyStatus: InAir
-  - type: CanMoveInAir
   - type: Tag
     tags:
     - BypassInteractionRangeChecks
diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
index c3ccb0330c..cb8304174f 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
@@ -1,3 +1,306 @@
+# Be careful with these as they get removed on shutdown too!
+- type: entity
+  id: AiHeld
+  description: Components added / removed from an entity that gets inserted into an AI core.
+  noSpawn: true
+  components:
+  - type: IntrinsicRadioReceiver
+  - type: IntrinsicRadioTransmitter
+    channels:
+    - Binary
+    - Common
+    - Command
+    - Engineering
+    - Medical
+    - Science
+    - Security
+    - Service
+    - Supply
+  - type: ActiveRadio
+    receiveAllChannels: true
+    globalReceive: true
+  - type: IgnoreUIRange
+  - type: StationAiHeld
+  - type: StationAiOverlay
+  - type: ActionGrant
+    actions:
+    - ActionJumpToCore
+    - ActionShowJobIcons
+    - ActionSurvCameraLights
+    - ActionViewLaws
+  - type: UserInterface
+    interfaces:
+      enum.RadarConsoleUiKey.Key:
+        type: RadarConsoleBoundUserInterface
+      enum.CrewMonitoringUIKey.Key:
+        type: CrewMonitoringBoundUserInterface
+      enum.GeneralStationRecordConsoleKey.Key:
+        type: GeneralStationRecordConsoleBoundUserInterface
+      enum.SiliconLawsUiKey.Key:
+        type: SiliconLawBoundUserInterface
+  - type: IntrinsicUI
+    uis:
+      enum.RadarConsoleUiKey.Key:
+        toggleAction: ActionAGhostShowRadar
+      enum.CrewMonitoringUIKey.Key:
+        toggleAction: ActionAGhostShowCrewMonitoring
+      enum.GeneralStationRecordConsoleKey.Key:
+        toggleAction: ActionAGhostShowStationRecords
+
+# Actions
+- type: entity
+  id: ActionJumpToCore
+  name: Jump to core
+  description: Sends your eye back to the core.
+  components:
+  - type: InstantAction
+    itemIconStyle: BigAction
+    icon:
+      sprite: Interface/Actions/actions_ai.rsi
+      state: ai_core
+    event: !type:JumpToCoreEvent
+
+- type: entity
+  id: ActionShowJobIcons
+  name: Show job icons
+  description: Shows job icons for crew members.
+  components:
+  - type: InstantAction
+    itemIconStyle: BigAction
+    icon:
+      sprite: Interface/Misc/job_icons.rsi
+      state: Captain
+    event: !type:ActionComponentChangeEvent
+      components:
+      - type: ShowJobIcons
+
+- type: entity
+  id: ActionSurvCameraLights
+  name: Toggle camera lights
+  description: Enable surveillance camera lights near wherever you're viewing.
+  components:
+  - type: InstantAction
+    itemIconStyle: BigAction
+    icon:
+      sprite: Interface/Actions/actions_ai.rsi
+      state: camera_light
+    event: !type:RelayedActionComponentChangeEvent
+      components:
+      - type: LightOnCollideCollider
+      - type: FixturesChange
+        fixtures:
+          lightTrigger:
+            shape:
+              !type:PhysShapeCircle
+              radius: 0.35
+            density: 80
+            hard: false
+            layer:
+            - GhostImpassable
+
+# Ai
+- type: entity
+  id: AiHolder
+  abstract: true
+  description: Handles AI interactions across holocards + AI cores
+  components:
+  - type: ItemSlots
+  - type: StationAiHolder
+    slot:
+      name: station-ai-mind-slot
+      whitelist:
+        tags:
+        - StationAi
+  - type: ContainerContainer
+    containers:
+      station_ai_mind_slot: !type:ContainerSlot
+        # Load-bearing.
+        # The issue is verbs check for same transparent container.
+        # The alternative is you add a bunch of events trying to override it; we don't even really need the container functionality
+        # anyway it's just a quality of life thing.
+        showEnts: True
+
+# Boards
+- type: entity
+  id: AsimovCircuitBoard
+  parent: BaseElectronics
+  name: circuit board (Crewsimov)
+  description: An electronics board containing the Crewsimov lawset.
+  components:
+  - type: Sprite
+    sprite: Objects/Misc/module.rsi
+    state: std_mod
+  - type: SiliconLawProvider
+    laws: Crewsimov
+
+- type: entity
+  id: CorporateCircuitBoard
+  parent: BaseElectronics
+  name: circuit board (Corporate)
+  description: An electronics board containing the Corporate lawset.
+  components:
+  - type: Sprite
+    sprite: Objects/Misc/module.rsi
+    state: std_mod
+  - type: SiliconLawProvider
+    laws: Corporate
+
+- type: entity
+  id: NTDefaultCircuitBoard
+  parent: BaseElectronics
+  name: circuit board (NT Default)
+  description: An electronics board containing the NT Default lawset.
+  components:
+  - type: Sprite
+    sprite: Objects/Misc/module.rsi
+    state: std_mod
+  - type: SiliconLawProvider
+    laws: NTDefault
+
+# Items
+- type: entity
+  id: Intellicard
+  name: Intellicard
+  description: A storage device for AIs.
+  parent:
+  - BaseItem
+  - AiHolder
+  suffix: Empty
+  components:
+  - type: Sprite
+    sprite: Objects/Devices/ai_card.rsi
+    layers:
+    - state: base
+    - state: full
+      map: ["unshaded"]
+      shader: unshaded
+  - type: Appearance
+  - type: GenericVisualizer
+    visuals:
+      enum.StationAiVisualState.Key:
+        unshaded:
+          Empty: { state: empty }
+          Occupied: { state: full }
+
+- type: entity
+  id: PlayerStationAiEmpty
+  name: AI Core
+  description: The latest in Artificial Intelligences.
+  parent:
+  - BaseStructure
+  - AiHolder
+  suffix: Empty
+  components:
+  - type: ContainerComp
+    proto: AiHeld
+    container: station_ai_mind_slot
+  - type: Destructible
+    thresholds:
+    - trigger:
+        !type:DamageTrigger
+        damage: 100
+      behaviors:
+      - !type:PlaySoundBehavior
+        sound:
+          collection: MetalBreak
+      - !type:DoActsBehavior
+        acts: [ "Destruction" ]
+  - type: ApcPowerReceiver
+    powerLoad: 1000
+  - type: StationAiCore
+  - type: StationAiVision
+  - type: InteractionOutline
+  - type: Sprite
+    sprite: Mobs/Silicon/station_ai.rsi
+    layers:
+    - state: base
+    - state: ai_empty
+      map: ["unshaded"]
+      shader: unshaded
+  - type: Appearance
+  - type: GenericVisualizer
+    visuals:
+      enum.StationAiVisualState.Key:
+        unshaded:
+          Empty: { state: ai_empty }
+          Occupied: { state: ai }
+
+# The job-ready version of an AI spawn.
+- type: entity
+  id: PlayerStationAi
+  parent: PlayerStationAiEmpty
+  suffix: Job spawn
+  components:
+  - type: ContainerSpawnPoint
+    containerId: station_ai_mind_slot
+    job: StationAi
+  - type: Sprite
+    sprite: Mobs/Silicon/station_ai.rsi
+    layers:
+    - state: base
+    - state: ai
+      shader: unshaded
+
+# The actual brain inside the core
+- type: entity
+  id: StationAiBrain
+  parent: PositronicBrain
+  noSpawn: true
+  suffix: DO NOT MAP
+  components:
+  - type: Sprite
+    # Once it's in a core it's pretty much an abstract entity at that point.
+    visible: false
+  - type: BlockMovement
+    blockInteraction: false
+  - type: SiliconLawProvider
+    laws: Crewsimov
+  - type: SiliconLawBound
+  - type: ActionGrant
+    actions:
+    - ActionViewLaws
+  - type: UserInterface
+    interfaces:
+      enum.SiliconLawsUiKey.Key:
+        type: SiliconLawBoundUserInterface
+  - type: ComplexInteraction
+  - type: DoorRemote
+  - type: Actions
+  - type: Access
+    groups:
+    - AllAccess
+  - type: Eye
+    drawFov: false
+  - type: Examiner
+  - type: InputMover
+  - type: Tag
+    tags:
+    - HideContextMenu
+    - StationAi
+
+# Hologram projection that the AI's eye tracks.
+- type: entity
+  parent:
+  - Incorporeal
+  - BaseMob
+  id: StationAiHolo
+  name: Hologram
+  description: A projection of the AI.
+  noSpawn: true
+  suffix: DO NOT MAP
+  components:
+  - type: Eye
+    pvsScale: 1.5
+  - type: Visibility
+    layer: 2
+  - type: Sprite
+    sprite: Mobs/Silicon/station_ai.rsi
+    layers:
+    - state: default
+      shader: unshaded
+      map: ["base"]
+
+# Borgs
 - type: entity
   id: PlayerBorgGeneric
   parent: BorgChassisGeneric
diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml
index f740b89f42..7bad742f5d 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/base.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml
@@ -3,6 +3,7 @@
   parent:
   - BaseMob
   - MobDamageable
+  - MobPolymorphable
   - MobCombat
   id: BaseMobSpecies
   abstract: true
diff --git a/Resources/Prototypes/Entities/Mobs/base.yml b/Resources/Prototypes/Entities/Mobs/base.yml
index c98608fabb..bacc5defc9 100644
--- a/Resources/Prototypes/Entities/Mobs/base.yml
+++ b/Resources/Prototypes/Entities/Mobs/base.yml
@@ -50,6 +50,13 @@
   - type: OwnInteractionVerbs
     allowedVerbs: [] # TODO: define something here, or don't.
 
+- type: entity
+  save: false
+  id: MobPolymorphable
+  abstract: true
+  components:
+  - type: Polymorphable
+
 # Used for mobs that have health and can take damage.
 - type: entity
   save: false
diff --git a/Resources/Prototypes/Entities/Objects/Fun/Instruments/base_instruments.yml b/Resources/Prototypes/Entities/Objects/Fun/Instruments/base_instruments.yml
index 614af2a488..5a3b967f98 100644
--- a/Resources/Prototypes/Entities/Objects/Fun/Instruments/base_instruments.yml
+++ b/Resources/Prototypes/Entities/Objects/Fun/Instruments/base_instruments.yml
@@ -32,7 +32,7 @@
     blockSpectators: true # otherwise they can play client-side music
     inHandsOnly: false
     singleUser: true
-    requireHands: true
+    requiresComplex: true
     verbText: verb-instrument-openui
     key: enum.InstrumentUiKey.Key
   - type: InteractionOutline
diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml
index fd1e76d638..1490aebcf2 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml
@@ -18,7 +18,7 @@
   - type: PaperLabelType
   - type: ActivatableUI
     key: enum.PaperUiKey.Key
-    requireHands: false
+    requiresComplex: false
   - type: UserInterface
     interfaces:
       enum.PaperUiKey.Key:
@@ -752,4 +752,4 @@
       types:
         Blunt: 10
   - type: StealTarget
-    stealGroup: BoxFolderQmClipboard
+    stealGroup: BoxFolderQmClipboard
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml
index ac125d36bd..c8e827b326 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml
@@ -80,7 +80,6 @@
         map: ["base"]
     - type: Input
       context: human
-    - type: BlockMovement
     - type: ToggleableGhostRole
       examineTextMindPresent: positronic-brain-installed
       examineTextMindSearching: positronic-brain-still-searching
@@ -92,6 +91,7 @@
       wipeVerbPopup: positronic-brain-wiped-device
       stopSearchVerbText: positronic-brain-stop-searching-verb-text
       stopSearchVerbPopup: positronic-brain-stopped-searching
+    - type: BlockMovement
     - type: Examiner
     - type: BorgBrain
     - type: IntrinsicRadioReceiver
diff --git a/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml b/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml
index 9c8102979a..bbc948bc02 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml
@@ -79,7 +79,7 @@
           type: AccessOverriderBoundUserInterface
     - type: ActivatableUI
       key: enum.AccessOverriderUiKey.Key
-      requireHands: true
+      requiresComplex: true
       requireActiveHand: false
       singleUser: true
     - type: ItemSlots
diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml
index 97a6d8e076..58a3f6ceca 100644
--- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml
+++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml
@@ -4,6 +4,7 @@
   name: airlock
   description: It opens, it closes, and maybe crushes you.
   components:
+  - type: StationAiWhitelist
   - type: MeleeSound
     soundGroups:
       Brute:
@@ -104,6 +105,8 @@
   - type: SpawnOnOverload
   - type: UserInterface
     interfaces:
+      enum.AiUi.Key:
+        type: StationAiBoundUserInterface
       enum.WiresUiKey.Key:
         type: WiresBoundUserInterface
   - type: Airtight
diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
index 4e499cc381..19e5c478d2 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
@@ -584,6 +584,7 @@
   name: communications computer
   description: A computer used to make station wide announcements via keyboard, set the appropriate alert level, and call the emergency shuttle.
   components:
+  - type: StationAiWhitelist
   - type: Sprite
     layers:
     - map: ["computerLayerBody"]
@@ -1140,3 +1141,46 @@
     access: [["ResearchDirector"]]
   - type: Lock
     unlockOnClick: false
+
+- type: entity
+  id: StationAiUploadComputer
+  parent: BaseComputer
+  name: AI upload console
+  description: Used to update the laws of the station AI.
+  components:
+  - type: Sprite
+    layers:
+    - map: [ "computerLayerBody" ]
+      state: computer
+    - map: [ "computerLayerKeyboard" ]
+      state: generic_keyboard
+    - map: [ "computerLayerScreen" ]
+      state: aiupload
+    - map: [ "computerLayerKeys" ]
+      state: generic_keys
+  - type: ApcPowerReceiver
+    powerLoad: 1000
+  - type: AccessReader
+    access: [ [ "ResearchDirector" ] ]
+  - type: Lock
+    unlockOnClick: false
+  - type: SiliconLawUpdater
+    components:
+    - type: StationAiHeld
+  - type: ItemSlotsLock
+    slots:
+    - circuit_holder
+  - type: ItemSlotRequiresPower
+  - type: ItemSlots
+    slots:
+      circuit_holder:
+        name: circuit-holder
+        insertSuccessPopup: silicon-laws-updated
+        whitelist:
+          components:
+          - SiliconLawProvider
+          - Item
+  - type: ContainerContainer
+    containers:
+      circuit_holder: !type:ContainerSlot
+      board: !type:Container
diff --git a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml
index 0485b5a517..539c8a244a 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml
@@ -96,7 +96,7 @@
         type: WiresBoundUserInterface
   - type: ActivatableUI
     key: enum.HealthAnalyzerUiKey.Key
-    requireHands: false
+    requiresComplex: false
   - type: ActivatableUIRequiresPower
   - type: PointLight
     color: "#3a807f"
diff --git a/Resources/Prototypes/Entities/Structures/Power/apc.yml b/Resources/Prototypes/Entities/Structures/Power/apc.yml
index 9412d45447..1022c57b3f 100644
--- a/Resources/Prototypes/Entities/Structures/Power/apc.yml
+++ b/Resources/Prototypes/Entities/Structures/Power/apc.yml
@@ -6,6 +6,7 @@
   placement:
     mode: SnapgridCenter
   components:
+  - type: StationAiWhitelist
   - type: AmbientOnPowered
   - type: AmbientSound
     volume: -9
diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml
index 9a244c2c59..6345cfef3f 100644
--- a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml
+++ b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml
@@ -4,6 +4,7 @@
   description: An intercom. For when the station just needs to know something.
   abstract: true
   components:
+  - type: StationAiWhitelist
   - type: WallMount
   - type: ApcPowerReceiver
   - type: Electrified
diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml
index 954caf67ae..c82a3f2108 100644
--- a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml
+++ b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml
@@ -4,6 +4,28 @@
   name: camera
   description: A surveillance camera. It's watching you. Kinda.
   components:
+  - type: Physics
+    bodyType: Static
+  - type: Fixtures
+    fixtures:
+      # This exists for examine.
+      fix1:
+        shape:
+          !type:PhysShapeCircle
+          radius: 0.25
+      light:
+        shape:
+          !type:PhysShapeCircle
+          radius: 5
+        hard: false
+        mask:
+        - GhostImpassable
+  - type: LightOnCollide
+  - type: PointLight
+    enabled: false
+    radius: 5
+  - type: SlimPoweredLight
+    enabled: false
   - type: StationAiVision
   - type: Clickable
   - type: InteractionOutline
@@ -43,6 +65,8 @@
       InUse: camera_in_use
   - type: UserInterface
     interfaces:
+      enum.AiUi.Key:
+        type: StationAiBoundUserInterface
       enum.SurveillanceCameraSetupUiKey.Camera:
         type: SurveillanceCameraSetupBoundUi
       enum.WiresUiKey.Key:
diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml
index 8e6b0863d6..f08451ad4d 100644
--- a/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml
+++ b/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml
@@ -7,6 +7,7 @@
     snap:
     - Wallmount
   components:
+  - type: StationAiWhitelist
   - type: Transform
     anchored: true
   - type: WallMount
diff --git a/Resources/Prototypes/Roles/Jobs/Science/borg.yml b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
index 456a761dba..b9b4cb3c16 100644
--- a/Resources/Prototypes/Roles/Jobs/Science/borg.yml
+++ b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
@@ -1,3 +1,18 @@
+# No idea why it's in sci but we ball.
+- type: job
+  id: StationAi
+  name: job-name-station-ai
+  description: job-description-station-ai
+  playTimeTracker: JobStationAi
+  requirements:
+  - !type:RoleTimeRequirement
+    role: JobBorg
+    time: 18000  # 5 hrs
+  canBeAntag: false
+  icon: JobIconStationAi
+  supervisors: job-supervisors-rd
+  jobEntity: StationAiBrain
+
 - type: job
   id: Borg
   name: job-name-borg
diff --git a/Resources/Prototypes/Roles/Jobs/departments.yml b/Resources/Prototypes/Roles/Jobs/departments.yml
index 9dca079c50..bde2d977cf 100644
--- a/Resources/Prototypes/Roles/Jobs/departments.yml
+++ b/Resources/Prototypes/Roles/Jobs/departments.yml
@@ -15,7 +15,6 @@
   weight: -10
   roles:
   - Bartender
-  - Borg
   - Botanist
   - Boxer
   # - Chaplain # DeltaV - Move Chaplain into Epistemics
@@ -116,6 +115,15 @@
   - Librarian
   - Roboticist
 
+- type: department
+  id: Silicon
+  name: department-Silicon
+  description: department-Silicon-description
+  color: "#D381C9"
+  roles:
+  - Borg
+  - StationAi
+
 - type: department
   id: Specific
   description: department-Specific-description
diff --git a/Resources/Prototypes/Roles/play_time_trackers.yml b/Resources/Prototypes/Roles/play_time_trackers.yml
index fd99b2c228..9c87cde979 100644
--- a/Resources/Prototypes/Roles/play_time_trackers.yml
+++ b/Resources/Prototypes/Roles/play_time_trackers.yml
@@ -151,6 +151,9 @@
 - type: playTimeTracker
   id: JobServiceWorker
 
+- type: playTimeTracker
+  id: JobStationAi
+
 - type: playTimeTracker
   id: JobStationEngineer
 
diff --git a/Resources/Prototypes/StatusIcon/job.yml b/Resources/Prototypes/StatusIcon/job.yml
index 17c9cee804..bcd8021c3e 100644
--- a/Resources/Prototypes/StatusIcon/job.yml
+++ b/Resources/Prototypes/StatusIcon/job.yml
@@ -29,6 +29,14 @@
     state: Borg
   jobName: job-name-borg
 
+- type: jobIcon
+  parent: JobIcon
+  id: JobIconStationAi
+  icon:
+    sprite: /Textures/Interface/Misc/job_icons.rsi
+    state: StationAi
+  jobName: job-name-station-ai
+
 - type: jobIcon
   parent: JobIcon
   id: JobIconBotanist
diff --git a/Resources/Prototypes/Wires/layouts.yml b/Resources/Prototypes/Wires/layouts.yml
index 9fd6bddc37..20d5d33603 100644
--- a/Resources/Prototypes/Wires/layouts.yml
+++ b/Resources/Prototypes/Wires/layouts.yml
@@ -9,6 +9,7 @@
   - !type:DoorBoltLightWireAction
   - !type:DoorTimingWireAction
   - !type:DoorSafetyWireAction
+  - !type:AiInteractWireAction
 
 - type: wireLayout
   parent: Airlock
@@ -96,9 +97,10 @@
 
 - type: wireLayout
   id: SurveillanceCamera
-  dummyWires: 4
+  dummyWires: 2
   wires:
   - !type:PowerWireAction
+  - !type:AiVisionWireAction
 
 - type: wireLayout
   id: CryoPod
diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml
index 8f64a13940..48358ca496 100644
--- a/Resources/Prototypes/tags.yml
+++ b/Resources/Prototypes/tags.yml
@@ -1248,6 +1248,9 @@
 - type: Tag
   id: StringInstrument
 
+- type: Tag
+  id: StationAi
+
 - type: Tag
   id: StationMapElectronics
 
diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/ai_core.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/ai_core.png
new file mode 100644
index 0000000000000000000000000000000000000000..8dd3031f9fc0b41e613e0f27050665c312010aa9
GIT binary patch
literal 269
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvl>na**8>L*7#kY{c?^7#3{tub
z-qRQi5*Tc&7@X@FGA}c%5MZe1t2(6v(#BX4<QL4~@a#q!kTc!W#W6%<Vse54j|A()
z28IBK08UO0Cf1goi495~2Us~9SbLlwGOSYCE5mhaftFF4lcRKq>#;SV2^%)?u2R}u
zZ7%U<23zRFn_IIYqoS^@61^;-b;-&3azMzEwzjr~D?EI8xs?|v>GJxzMr29UMH}2{
zd>CZVu=>Od-oTB*@1l2nU#KO($P(Jf;k1IwX<?sWphTc22Lpp5bB8Nq*+DIkk33!d
KT-G@yGywqSrBM$6

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/camera_light.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/camera_light.png
new file mode 100644
index 0000000000000000000000000000000000000000..041b9b9bf7c8b9cca92a5cb784ab672663a101cf
GIT binary patch
literal 309
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv^#Gp`*8>L*7#kY{dH?_aXW)}$
zkkVx^NMLZTXRxhe2wKXJd6}V}k70$t^CE96pd!YSAirP+hi5m^fSf&^E{-7@6O$7Z
zcqCXSHZTM@1aPuUIk;q!LV&{wR!)s37ANP+LCy;qbRIkki<{Q8NNMrjJvyS1u2rtq
zKD<7ztUkOE3al%bRG7jiO0fxLdN;2=F=r!>M$ooX(i{hvBHzxvd`bJ#G^LdVg@xYd
zqnZquRYa$?7O<b0s^{K!;13hi#f9$9&iz`8ethFu)iq<rg&7heqIPz68CppfLUzn?
z+n)M8%p`hGY(S`j6OZwgz)%MzFHXTgi9k;d1_t@(1&3KqCN%>6!QkoY=d#Wzp$PyH
C>tw$G

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/crew_monitor.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/crew_monitor.png
new file mode 100644
index 0000000000000000000000000000000000000000..78fad17a76c58ceb3ff7bdc60107aaf01f477511
GIT binary patch
literal 295
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv-2k5u*8>L*7#kY{c?^7#3{tub
z^?VEl2@ER)7@X@Fin!ewG6EP%!x`!s%+eT);<gul+5}X|SQ6wH%;50sMjDW_!qdeu
zL}Oxdf&z~O>%<0z0EYlhP7Ws4mY#_XN*)JTIW?R@TH4yAq-QTZ7`mfv`t-IPJGLGS
zoiT0tbav_4TNOj5OlxmnvUKaxr3$N0ym;}#qir>ZYq(%n8rv>iiFXG|R&Lz5bmPZW
zM^9*_`4xVQYg%*Y%8efeU0mVf@*&1Pz5I*Y+E??>(p}cxn>#VIVoO=c7dywW!YdM?
otQW*gj6bwlxw#~|s46lrY*UY|zO-x71(07oUHx3vIVCg!0LmC=oB#j-

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/manifest.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/manifest.png
new file mode 100644
index 0000000000000000000000000000000000000000..08514aa90829c59d8d3995ba7f1a5f0ad5c24bd2
GIT binary patch
literal 245
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvtpJ}8*8>L*7#kY{c?^7#3{tub
z1_=xaoDB7R49@io?Ys;H+zcxO7)&x4Y^x@eT{8nJV=M{s3ubV5b|VeQsq}Pl4AGdF
zoS?uX!8);lA;2MklaqsqwWVibgObMqR!)r|U)PL`jEKrgtqDyl3f{hWkul$LGm}Sa
z1FMf9)4>4IP|*ynu=Ou?R&Lw1NOn8d0?Fd@VL9s?Rv*}~boZ`r=jPsiYF)6}p}3v<
m(8~}WekUyhB`#$xPDX~VR|VG<ZTkyBF86fxb6Mw<&;$S|#7l4h

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/meta.json b/Resources/Textures/Interface/Actions/actions_ai.rsi/meta.json
new file mode 100644
index 0000000000..a7c00f7793
--- /dev/null
+++ b/Resources/Textures/Interface/Actions/actions_ai.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+    "version": 1,
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/blob/c473a8bcc28fbd80827dfca5660d81ca6e833e2c/icons/hud/screen_ai.dmi",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "ai_core"
+        },
+        {
+            "name": "camera_light"
+        },
+        {
+            "name": "crew_monitor"
+        },
+        {
+            "name": "manifest"
+        },
+        {
+            "name": "state_laws"
+        }
+    ]
+}
diff --git a/Resources/Textures/Interface/Actions/actions_ai.rsi/state_laws.png b/Resources/Textures/Interface/Actions/actions_ai.rsi/state_laws.png
new file mode 100644
index 0000000000000000000000000000000000000000..e30e891745fb526dd73b5f597eec1a457f4b1aaa
GIT binary patch
literal 241
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LK*8>L*7#kY{c?^7#3{tub
z1_=!Hd<@R@47ODaD+Ih}3GV|+F_r}R1v5B2yO9RuG<v!?hG<M&dhsCV0R<k`3uVo>
zc;9e29;_CzYIva3R9#VYJBwe{?Sk|FgNL6h9?Q9HwOhe5OHofKuv^$8MSH{1ed?$D
zD;RuRdtb<iDrWh%`d=(nQc+_PpU2JP)6jK+`%A}MhNI~R>!u}jolMn|I`RMAi9i1D
j9cS27zTB`Paq4Ot3*m6NwGaI|K(6+5^>bP0l+XkK<p@&q

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Interface/Misc/job_icons.rsi/StationAi.png b/Resources/Textures/Interface/Misc/job_icons.rsi/StationAi.png
new file mode 100644
index 0000000000000000000000000000000000000000..aba35c034b9f1508e953a030300987dcf1265f1e
GIT binary patch
literal 204
zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|SkfJR9T^xl
z_H+M9WCij$3p^r=85qP=L734qNaX`iFwxV+F+?Lc`42yfUun1Gg@gN+MQ|M6Sa$LM
zi<i|0B-oza`SDv`g^x)`AeD#5+h~qtQrer=PXY~`E(+dFH~RYe63jRb_%bl&ENk$c
vQT<td2J>P^uEd4~`UkiU=&WgIWMue|ZFBN9!-0c9%NRUe{an^LB{Ts5`?Wy_

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Interface/Misc/job_icons.rsi/meta.json b/Resources/Textures/Interface/Misc/job_icons.rsi/meta.json
index 745cc43b84..117a94e790 100644
--- a/Resources/Textures/Interface/Misc/job_icons.rsi/meta.json
+++ b/Resources/Textures/Interface/Misc/job_icons.rsi/meta.json
@@ -1,7 +1,7 @@
 {
     "version": 1,
     "license": "CC-BY-SA-3.0",
-    "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi | Brigmedic icon made by PuroSlavKing (Github) | Zombie icon made by RamZ | Zookeper by netwy (discort) | Rev and Head Rev icon taken from https://tgstation13.org/wiki/HUD and edited by coolmankid12345 (Discord) | Mindshield icon taken from https://github.com/tgstation/tgstation/blob/master/icons/mob/huds/hud.dmi",
+    "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi | Brigmedic icon made by PuroSlavKing (Github) | Zombie icon made by RamZ | Zookeper by netwy (discort) | Rev and Head Rev icon taken from https://tgstation13.org/wiki/HUD and edited by coolmankid12345 (Discord) | Mindshield icon taken from https://github.com/tgstation/tgstation/blob/ce6beb8a4d61235d9a597a7126c407160ed674ea/icons/mob/huds/hud.dmi | Admin recolored from MedicalIntern by TsjipTsjip",
 
     "size": {
         "x": 8,
@@ -177,6 +177,9 @@
                 [1.0,1.0]
             ]
         },
+        {
+            "name": "StationAi"
+        },
         {
             "name": "Syndicate"
         },
diff --git a/Resources/Textures/Interface/noise.rsi/meta.json b/Resources/Textures/Interface/noise.rsi/meta.json
new file mode 100644
index 0000000000..068ecab968
--- /dev/null
+++ b/Resources/Textures/Interface/noise.rsi/meta.json
@@ -0,0 +1,58 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/4b4e9dff1d7d891cfb75d25ca5bf5172d1c02be6/icons/hud/screen_gen.dmi",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "noise",
+      "delays": [
+        [
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1,
+          0.1
+        ]
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Interface/noise.rsi/noise.png b/Resources/Textures/Interface/noise.rsi/noise.png
new file mode 100644
index 0000000000000000000000000000000000000000..ba74952b409b6d3673c9949e6a81c0a84ecd472c
GIT binary patch
literal 45602
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
F{}(0Gc*g($

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-banned-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-banned-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..9b72b39492803a112ab679408d6b450bf93c7b8f
GIT binary patch
literal 820
zcmeAS@N?(olHy`uVBq!ia0vp^3qY8I4M=vMPuFE&VEXOp;uumf=k1-qzS#yMtO3hj
z?YdE37a3`<<tE6~eDFg~abL(*#kVo(#~g3)mP-INg20Qj=P&NJ@V)$g{_(;+sRpLc
z-K&4UW{1cj$ZNirzx-ak?T`AgDYO6At~v6f>g@l?#vLz$=4}0wIjgNuMt)|?&Yw$<
zUrDaJ#?oW;`|VSE({*?LT*~i}`#js8d0F4}3Gqcaw$J3}HGCGIRX;!dTk!R^=%3!@
zz1rsWXP<wb$j|Uqd+*dBqy1M@{jMpsJiof@vjNZl_3Z2QihK^7vfX;TQf>c{9X<!x
zzU=v%%B1G<|NG-v%eU{}_G$m|fWtcw4rO3i5wQMm$*1Jc`rDJY-t$+tH{0)FpKuy1
z)cu8d+Z~Y5|04SbK_F#cnVD=}_}Issj1&0z_xbxc=6NsMwRirSbie%HI~JSU{Nb-=
zE9`&&$9eSw<J0den>Vri{QE5ZJG0(;?q|nOKdwIgb@P+`*79AyI^_;Xo-V&}S#(?W
z&+PYKb|3rt?N34U@_$mF=1chd|Gas<Ve5*WwsHRo&-xum?65z2djGut-_O|pn)mbK
z{g%kw<W;#g{z&28(6Ux~;`8T0$GvI_0_*1goPK*_(07(8|BkHt^Y7DUwS;%Pr*ywu
zKG}bEe+`?D?EPxJ=|FLQ{{t`TEPlQ}$6hh>N>EjH<i4#T)Aj4mzB5gD)&2DX$lvwl
zOy9s^^8bR?j^}k&KR5ooc~$20>!zO{KUF}2ZQ+XGzYV7)|7`=x9{k%7z5L$R<DZ@`
zPl;zfSM_rFWck_kRZQoaJ5=`n{R32}`=hSh?f(L$J%7J4LnFcA=(aqUdGozxwLcy_
z`l9At;Z9lYQh$e+@--!PPg8vl+>xFV{bITDwWr1juYTMs-nr<r=KBvUJ@4AP&#^bK
zFWqLeZJX=1ZC+7lp4a_i<XkF0AplGXROtV0*s^?iomJ9Hc9ki04o-Kk@voTA2ekFU
ZZTr2iwC2ogy}lIW22WQ%mvv4FO#mbvqW%B?

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-banned.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-banned.png
new file mode 100644
index 0000000000000000000000000000000000000000..c583bb88f21bd6e5250ced9332d3f2d4eed2945e
GIT binary patch
literal 1589
zcmah~do+}37$3$MO}VX6N@J`fZObUKHkl!pNQ`J>!+xX&5s69Ko%uxW#kPe?ve}r_
z$>f@@Uz(zl#*&7_U=)+lxXc*Mb-%HHw5NaeocH~`&-0%1d!FZgF6Ye)@ZYYBS%pC$
z5V}6z9)a-rr+VvX!&tzMwm~3Javu-3-N!CXU2;hnjmLTsa<i?@TI3h+dx+b=^cUj-
z*9_e%@$&l2#C+>o?~CUyYxYOUb7r_v$?P*-mR2M8?W~xG1P%F>)*BIq8|<S{S}RTM
z8=MN)&W?{qvxEbX5A<0mNtB5fobnbXQ|eVJ`JIq#E`t=R0lE<1a`+C<5!WwU(<_vI
zgE-8zY%Vc>DUn3lZmjLrb&Ny@l++n?^T5<KWQ#Ve#G`%#K|IZX&-)O*K$HDIp%4fJ
z3T0j-a>#cgkZEZv=#aAMLVtUE&Xh#fP4L|1@FHSfrg(Y}0RdpFsU6uQ`!C%}-31{R
z+SFhPMb9b}hbR;hiL~7FOjcwJrBs-m(r<GW%)pzO)gR!S1)G9^RGOybxu`4)d1Hs2
zEZqz&2c{hR6K>~~lh&9CN{9&tTF*xgdyhK3`ot1)xK1eKDL)=|t7UjKLM{;kW#vU3
zf}{7`vix8ycwi@|D|WV;XRS9O1=-OddUeF_kFlqKkKFSLXXg>Im>Lj^t06qF(tzW2
zM3L7rlSd?c<~!}xQnv7BQ69GlYSb+J7J6SdBbzO)U2^AW=cB%1$$Kb7qqr0`D&e#D
zJYx35b}v19qhv%f4r`;uvq70$Mun51cfU3BN5pW0+T*go3FIh4KbOm_Aez%_z5<Af
zx67{-yeTHq?plEZ8~ylff-lqt%riS*J!oz;<aksB_}A%|k~TCKk#r}*LYEjT<(uTa
z$}(xXJ1w5mL=GN@s9`~$CzVmtsRE>4F(%G8R29No^_UwSZzhjxnDew~=hdY|*O7xa
zGgJE=x0)5L2y(@Py}~e44p#Zy(9qCy@IttRKiz}YY7g)_Uk9Ckh8wkh5}*u~=;j*P
zye73RVYz>1*$G6|=KhW5AHrVX_l50jwV!9xFb@xG-PwwhyZ<KdYX>|lSb)29E~<qZ
zmIm_UO%~c;qle1me9lvFd{nr_wmL#C(wLEnd(ck^{{u$rG}ntX+%Sx&6Ii%#+wcY?
znk!sTnD6^FWQsIO-!WKBvE&od_5nFZr6*1I{nRr8WfF(~kfkg%DTio}u5)XmYH3^4
z0XU139hZ5>e!nJ#&#LMuNLKBJ?>lCJ(?**+`BYj<oKIaHOe^I<TTrP}EZyEF7N}BM
z>SPE?xH_jRtp{>ng5hFXQre7C?iF*~R|q#FNX6I&zB4961Y35ZGj?SIIR{Lmb8<AM
z;}it~q~lb1jr=E}NZvBdk)3ragx9)X(N`ae9)>D*VS5wet|_RzR$z)fpHcdTG1*X>
z0}_=lSa!brp21l+XJwkymoawx3<rlww9l10x(>2au5_Mn6Ww0PKBv6fetBRH=ub0^
z=w9C^xIb9|*&0J+b-n`s14$O@EM7hA<=`EO(T0;d1D8R_A>$38*IxkGvW$0=oC8d<
z_qa0QwCq*AeVJOJr?yk5IE{arHqkS}k#Z<f;%YjV&ROBbW9aJ?UeV80_cf%v5p*ku
zh@;=+Qvc<=Qq<}rhk*$Et%JgA2mOE@6?&@2()7P^V*WItQU4f0?E-usX+mBU7{rL+
z4}A>N4nWek6_lngM32Ff1AP1f>-@FgdCEA~9chwyGO{JGsMUUF>o^DD(S_DpY#5sB
z;xpB1RZrc0G2hj<S@ZZ*&xw+z3qm3;=I64{pJ1hJQwAJp%oTl|BVmAvOLrW`29{yd
zM;uRKrRnBbMDu4!gA7weZ<ZJAZ?!nmpb3An3%#EZQaDK*e8#j1J3%z}R&%^2k+xN2
z^xg?%y^#gXTfBrh*inyo<c=gRdhDX14X82jO+<NaWcLC1J3#n&`g_!Fi^%u~A%`&C

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-banned_dead-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-banned_dead-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..28bf165122ea7c29a4bed6f6df7c1c37efc18a2e
GIT binary patch
literal 109
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQYM}*jv*Cu-k#gY$)F&>e4u=z
zyxruRk+(S(m4|jY1hFzO{K<GDHhImRyYA=i?BNIMVCbKrx{i(Mo@~AWi0A3*=d#Wz
Gp$PyfVIac*

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-banned_dead.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-banned_dead.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c5b468885aa71a7856e9142bb89a348e7eae7c5
GIT binary patch
literal 463
zcmV;=0WkiFP)<h;3K|Lk000e1NJLTq002M$001Be1^@s6qMd$(0004&Nkl<Zc%1E-
zJ&uDg5QSe5jT=INVo_vokSlO14uRxb`3kwgrigH5Xi_>wWG{aq$u9P+1W%%14E}~O
zW6R^6l+s|u+5uQ~0Ac`8N|C@1hXbhjvAy{^9<fi;AmB!8d|xg-8x`LLV4tRFv<~9H
z)Q3{><7W*NqTt6vLtWQift>T%_R#!j_yA+fs{^kTn(qQ|KA*iiVf*c}sQEDf<arJN
z$g<1}xC^(uE{l>M0l@WoMO9U!m!y<loT;j+Hwu*e(HziKQ54>sct;`lI{>CTGq!CD
z0Jz<5kW!*33IP4lu(nTRf59Y4oXyVo@9_VsIlfU!86kw>oEyfNVT>6(_6UnzwqMS<
z5keTHlxw5p&!)f{G@AlT>NhD6f*%2ob+IhVMS*iF%d)o$Q1Z7Fz?K4A3anbIPk|Wt
z*&Urur$wR9WO=qGNXd685DNZ`Ma7?-1D5{%KJ7Cke-r>8@K5><%^%eSU)Ah<D>T0s
z0LrpB72gG*(K_hC#FUMK?*cG9sR=DA{&qM@S@Zi3x&w%1QN~tqHsk;R002ovPDHLk
FV1n-x%*g-%

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-empty-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-empty-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..6539176b8487d93162dd7df57f3528eca69df99d
GIT binary patch
literal 109
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQYM}*jv*Cu-k#gY$)F&>e4zZr
zd?oMbXfClu<*^DALKqns?4_)qs(8P9w>UlTK08oH1G~>>eKw}0-xuEo@)$f_{an^L
HB{Ts5#}6My

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-empty.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-empty.png
new file mode 100644
index 0000000000000000000000000000000000000000..eda1f4bfb568d5b1ea19f15f24d9242cb27defa7
GIT binary patch
literal 451
zcmV;!0X+VRP)<h;3K|Lk000e1NJLTq002M$001Be1^@s6qMd$(0004sNkl<Zc%1E-
zJ#xb!5QU$N8X8-bshk`5cJe9qR=R?25LcqYZd{VW1F`<&2-r-dH^Yns8ot#I4<yK{
zs<K$IG61ViKn?&}YZmzNcmy{;cQ+rW6And@1bj0FpVw=vj*IUTa3~7gj7bu}(2H{M
z^RWgFaq#nQMbk7<fl8^#_SF1c_W>zo)Bxs`n(q@(*L5!lA_@v~{l2pP0^bTDtPsK~
zrL2_FN+~U#-v^e6{PmLJ`c+DKmTP0?!)mQ95e)_qDu~wrh{$TKeH$mgHwSb@M7Ufo
zbB{$+Y<>p7zRryI`yBxAcszRWt|#9K%=vG>-}^c@<NuVuL{t3PAsC`8u|Q1ztOfqN
zCM^(Bzp+3H{tkGqi)C2`1x~3f%hp=V$=@u1%>tVRR;|@rAP2txj?U+EQ0SN(&+Q3v
z^1TI8!N*u!{J}XO^zeJP&y@UL0%E}5={q&Qw<kEaXBS(k`K<(SZi{pAeFARABt4iI
ts^j4M1awboQj3ef9gbF2#T^5yz5rC2*?>5Oyi))G002ovPDHLkV1j~s%9a2C

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-holo-old-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-holo-old-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..63616e70b52120b670f04f00c276c707f979efe9
GIT binary patch
literal 2483
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
P#2Z_h+mXsmy%PTd$R=LN

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-holo-old.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-holo-old.png
new file mode 100644
index 0000000000000000000000000000000000000000..3dc7a301d865c65907c7c3fa0cde98ce717cfff6
GIT binary patch
literal 7280
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
IluN|_0b@DVZ2$lO

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..f3ba4b591abcf9615ea0cee2d2ef3a5d1e7c42a8
GIT binary patch
literal 6255
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
MrlCf;x^2||0(0FdR{#J2

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai.png
new file mode 100644
index 0000000000000000000000000000000000000000..3c81e3a751ec86844a1fb383a91185e12b041561
GIT binary patch
literal 6761
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai_dead-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai_dead-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..96e953660f8eaecc60da577108813a81695c3102
GIT binary patch
literal 453
zcmV;$0XqJPP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004uNkl<Zc%03b
zJ#K?A7>1ujNNuMuM7Rv8xB%yAu8^IjQ<bSm9H3Vq*We0VAZmsbPh@I4xdVy$Pg^C1
zzLI5Q1J7%JA3vTXNun506JS&W7J!s;6u9F!g#mzv#e$h_4+1{qId8iiKxtrR+Z^(I
z5CheTTGfHiucu)Q@Y-#l(6eFux^^^ejeCaq9a2(CC8bnC2!*GLf`Q^GC4|sCKv@8;
z>jE&J&&^HKE1RzCYSt8Bzuyyvp*eU%VHlF8X=z|gO#mf?&>h*`d(qhbd~qCabbGmc
zJb$uRRN~{lWMvs}Ou{IN%qF2%CSepsItfP)0Tdz7rMUue9P7HT-F0qrthxf4b^H?l
z{}9CSrj~Hk<8%Ghu|8e&6#PkEQ8k}}DL|U01VM0RV!whQxco)b48d=fyGx^ozykDg
z_`ZK-YPU{2$8pLK_`Xk;t&GF7Y*m|RcMfa~kbCagHedpN=H4CugzI*fLDdZ0-n<Ni
vwc7>`c|PdIq-Ef=QyE(0Z%&gW8I#X9TE>0xyqkY{00000NkvXXu0mjfY`w_)

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/ai_dead.png b/Resources/Textures/Mobs/Silicon/output.rsi/ai_dead.png
new file mode 100644
index 0000000000000000000000000000000000000000..96e953660f8eaecc60da577108813a81695c3102
GIT binary patch
literal 453
zcmV;$0XqJPP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004uNkl<Zc%03b
zJ#K?A7>1ujNNuMuM7Rv8xB%yAu8^IjQ<bSm9H3Vq*We0VAZmsbPh@I4xdVy$Pg^C1
zzLI5Q1J7%JA3vTXNun506JS&W7J!s;6u9F!g#mzv#e$h_4+1{qId8iiKxtrR+Z^(I
z5CheTTGfHiucu)Q@Y-#l(6eFux^^^ejeCaq9a2(CC8bnC2!*GLf`Q^GC4|sCKv@8;
z>jE&J&&^HKE1RzCYSt8Bzuyyvp*eU%VHlF8X=z|gO#mf?&>h*`d(qhbd~qCabbGmc
zJb$uRRN~{lWMvs}Ou{IN%qF2%CSepsItfP)0Tdz7rMUue9P7HT-F0qrthxf4b^H?l
z{}9CSrj~Hk<8%Ghu|8e&6#PkEQ8k}}DL|U01VM0RV!whQxco)b48d=fyGx^ozykDg
z_`ZK-YPU{2$8pLK_`Xk;t&GF7Y*m|RcMfa~kbCagHedpN=H4CugzI*fLDdZ0-n<Ni
vwc7>`c|PdIq-Ef=QyE(0Z%&gW8I#X9TE>0xyqkY{00000NkvXXu0mjfY`w_)

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/default-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/default-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..f14b4ef0fa6b3eecdf2106102180f93fc8b3f4c2
GIT binary patch
literal 2005
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/default.png b/Resources/Textures/Mobs/Silicon/output.rsi/default.png
new file mode 100644
index 0000000000000000000000000000000000000000..f14b4ef0fa6b3eecdf2106102180f93fc8b3f4c2
GIT binary patch
literal 2005
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/floating_face-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/floating_face-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..05de742794341c5e5489daa52bef423933d51512
GIT binary patch
literal 721
zcmV;?0xtcDP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0007*Nkl<Zc%1E;
zPiPZC7{y;|6^w$`BnUl<(c;D8MPeg8iTICzv^P;HN)3pfgiudCSb7x#H7G^JV-Z9&
zgm@`-Q+jBL7l}>lu~bT`J!B6mjtAY%u7W$0>~vFnzti%~?7m^<o7pef2M|IC`F{zi
z-jK{1!mH2B%|7Ml2BqJrD&Ch!cz4ViLdPWN(3c)$GHZxaXHLj=M=@XWH4}8{D`kNB
z#WVY~qC;PL0wVEVg!eWkbbANz?Z?0S`-v`nsT55W>f-pJFgDiZR$yBQ*xePv+@gsW
zr+2ly4Rq>DXTaQ|2>|#w^V*ILTph5lryft)*9Vekfi>AD2dm%V)ge`=3jjEFFbn`#
zt<2-io%2|&%%hku0r+*`IOER#*8R<*Ti-K1Q-!*)9%hL};=Q&&F<*jpIxj4ls8!2w
zp4JOXt!)F{`kq^$RxQJfHr~C~d)Rp*Th~3&oj^3<YO7VtUJ`-oOPvAE)7Pur>vV1g
zo%&L#namoZ|7Z`shr3+y$?*{!?!SN!(=RcU8FRIDnx8TKuHs8Eq*GsdaChI<1OV*l
z-sg%xyZ-=}Zr^alzOJkT0PdZP_*Mz((pM^lrRwnC7_+m!m%=*ql}h11_hK<$!p5f+
z?AhN9l{&pybm%LskaHEDKgr?9xyyFj`&UnK@yaj&|5v|V^Z@{|bWV&e3o*JZL~Jl4
zVuKkGzctZ_rE^+;G5M|E)GWo)IWctY`d{(MM-Q<!F|6&+kap3x2Vu?nW~{s}{g!6S
zDY|Jh-$wd`5JCtcgpjQZ{Q;`t^an^ne}D$)51>DQ{s8&|=ntSjfc^kq_300g9R&RW
z^as!%5cv1`p!EUJA7BrH{s8&|g8x1rv_2t(kgd*7uk1M<qWT#i00000NkvXXu0mjf
D+wWaa

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/floating_face.png b/Resources/Textures/Mobs/Silicon/output.rsi/floating_face.png
new file mode 100644
index 0000000000000000000000000000000000000000..05de742794341c5e5489daa52bef423933d51512
GIT binary patch
literal 721
zcmV;?0xtcDP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0007*Nkl<Zc%1E;
zPiPZC7{y;|6^w$`BnUl<(c;D8MPeg8iTICzv^P;HN)3pfgiudCSb7x#H7G^JV-Z9&
zgm@`-Q+jBL7l}>lu~bT`J!B6mjtAY%u7W$0>~vFnzti%~?7m^<o7pef2M|IC`F{zi
z-jK{1!mH2B%|7Ml2BqJrD&Ch!cz4ViLdPWN(3c)$GHZxaXHLj=M=@XWH4}8{D`kNB
z#WVY~qC;PL0wVEVg!eWkbbANz?Z?0S`-v`nsT55W>f-pJFgDiZR$yBQ*xePv+@gsW
zr+2ly4Rq>DXTaQ|2>|#w^V*ILTph5lryft)*9Vekfi>AD2dm%V)ge`=3jjEFFbn`#
zt<2-io%2|&%%hku0r+*`IOER#*8R<*Ti-K1Q-!*)9%hL};=Q&&F<*jpIxj4ls8!2w
zp4JOXt!)F{`kq^$RxQJfHr~C~d)Rp*Th~3&oj^3<YO7VtUJ`-oOPvAE)7Pur>vV1g
zo%&L#namoZ|7Z`shr3+y$?*{!?!SN!(=RcU8FRIDnx8TKuHs8Eq*GsdaChI<1OV*l
z-sg%xyZ-=}Zr^alzOJkT0PdZP_*Mz((pM^lrRwnC7_+m!m%=*ql}h11_hK<$!p5f+
z?AhN9l{&pybm%LskaHEDKgr?9xyyFj`&UnK@yaj&|5v|V^Z@{|bWV&e3o*JZL~Jl4
zVuKkGzctZ_rE^+;G5M|E)GWo)IWctY`d{(MM-Q<!F|6&+kap3x2Vu?nW~{s}{g!6S
zDY|Jh-$wd`5JCtcgpjQZ{Q;`t^an^ne}D$)51>DQ{s8&|=ntSjfc^kq_300g9R&RW
z^as!%5cv1`p!EUJA7BrH{s8&|g8x1rv_2t(kgd*7uk1M<qWT#i00000NkvXXu0mjf
D+wWaa

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/horror-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/horror-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..10efd5ee1dbc3a2dc73ab315c035373f285779ec
GIT binary patch
literal 1777
zcma*oeK^y58vyX}NGNT`4oA-9r6eh#E;O;FiHRw%m7(UPL)M}uMq4HwDla9mCQ?bv
z#lgciZ$Ej7jJ6XUFO%inVl?K#m_0ks^ZfBVe?8}q`@a9Uzt{D>zW4S0TzA@8jEkm*
zo(2d6(nPzWycG4$pP{Cz$Zd|7IUtZK3ynJI6PGV~4xE8`=yn1Lr@7t>yyQT1PU|>z
zAobEdGnAUm;<i3Dw=SYh(gxUz-|oj6zx!hqx^$NR`q9mEYC0O|N3Cw-Ny5ekl_6%{
zb3SdT$slNH)OC|=h`LgE+wsPCJNp_c7^!A-7vl7PQx>3C$yz{+IxY(VI(dot%71_g
zp1duln7_0Fyo)3O-x;={eZtnB>9LE)4n7I(i*PPKS`*KD>QS=8mbOzSTQTi<$1QdV
zU@xVCLFtUScO+4w1w6@nyWRE1@f|Ee9SCNJb1w<9FT9Ek1S=ye62~bP4#U=nL$X+z
zYler<YY4>mDBRLZe19&%`)7M?t7of9w$_@JYs#5SdHP4NMW{0dKkw5xUXM_mI>$Kf
z?<md=foe-dQhF<Py*(F78#;mI9Lm)IS>|`Y-$zIxdyLXASe)!GcEO~Q8_2F>vn{SB
zZ%+u^4Ye3@Ct92;`|w0R*wFm<^3zh$I-RR|{JMBy1xv({L{~&3Vno#Tv@%|F^4$lz
zlqFbja1K?>Vjaxy$klcGvifDQGax8h1~n`oM($I*pc^&n2WmlwSvFQj?%PooIc3&b
z1|4Y6+hdCJAA4<maUqsR_zb+j+gP7ckL&2rrRC+-tN#!}%J;{j!Vg?dOvTKcmmXek
zdmbJmESy%kIgCe+hlK8;d4DPTM7g>dIrSkdT)WMjVWq8tkI<q+i0+k_Xf8mwpRwZd
zs>$1iiyV5J2DMIQs(W#7_TwttA%l&lWk)5eZ3giPKiWQ;{FEGy4Ovw~YWFQ?ryOxX
z{6p#M*nHgB+641<i*rnb&gFTU!Rozl;XFA-3MCP{Oq}%XiFX<WgT4a0G!{vuwK7~B
zeZ&yAd=ESAQ+RILK1#Z=n7K2y2FuPXD2&>Ad@}J%uWGUHH7R~QS-T}MiMM_l*%)@e
zxh#s3nX#$<LQoKFM4I-AASR|knIDZ{VxE8^cW_u&z7zbe_-`T0XSbatqDDH7f;KKs
zxfKnB_Zcxf;QgDD014;56}Nc*@Qp}M!Ebq=cl#$r&jiJziUb9~?vaHKWaZ4DpKI<J
zAPm^se4Gd;py23hq)}hSQ*yx8-8h|_4eZ%4oCvoICdF?gyvYp{dO87t2=?4t?O$H$
z37K<D^EYz8HFcv~I(!aTG0nfi<zJ$*0y6xuna2=s<O^#b1Q|hr)eX)i?|&urEczUf
z>1=+}9J*Qm!shrcb(5Eb=R=#WmjCubZ^GCAx0vem_=#_%-xM+)V7~S%?Sd)3`~v-O
zDgf7)-I!V#UdJlh5D1>rd#@vt$u;I$N;l?QVxnFeryvKrN6af0J@E4?z4s<IcyF7o
z5?g^3L~WJ#BRuDG<i{M(&B;Mj3b|qHjitiN6e`>XJYdZ!R=$&0;UgN(77k1{(Wbm=
z9O@-q>c0~Pz-BOg-BOjD8M=DwANwO8K*hjcVbT-3|611dA0|8tCgvDkmV18kPpMhc
zI#s&SydjI@m{(Ag+iNiCuLTvsv@X5|$gcF^A6e%aWjQ5k3=9^kP>>p!lHL6an|~7U
zl~e16x^|l2p6#x`xEjg+50Zxwlu;q<3}8ZG^*s@FuF%7%m{}`pm%%Np=&7^(u$Yl!
znoINDSy}$xCu@`u6y?-!)kF>3BYSosO~PO4G_Jqc{l7rmV>=to6g~vb0#;)omc)B_
zb$*Z1TO5g8{e5b-(-CwcU;hY<vRMaaxmxrZKXh0ojPkO!$Wo}-;Yx4DlX#$t(HyN6
zy)ta_t@g}B5VCz*ligG5_^RjDpk!5GuzNn79b@Hy7}_*RUaO~Tx-mv1{H5*Y$dcw-
zakd^NEF{Rc4sdbVQsEJ}l@Ny;Wq*e^x2FZnKr-TH7Xf)eL84Mi<=4kU=UEyr^p3%s
z<5Vvp%CTmW;V5`$E&A7Ih2#h13s%$YepCWRB>Y*Y20n4na$&?g^MHiEY@5t)(w$v_
z@il}oLgxIfcH0unOuDP-2M=yT<mXQWP9cO#y=MDUlY4n!Ptqv>PvJ_c56RH8%sJCr
x`nAe<pS=nSu^keD2Eu6aBQ9aRNbVWB4$ci(+y>Qgj#8{L5ZW1os&KkQ{U=i>h9Up}

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/horror.png b/Resources/Textures/Mobs/Silicon/output.rsi/horror.png
new file mode 100644
index 0000000000000000000000000000000000000000..0a807c0c2354086be2730017fb4e4a7eb95afdd4
GIT binary patch
literal 1404
zcmai!e>l?#9LK-y80+ka9x^|+GHuC2$u(+>{AxWyQPEag57H$jg}M8NSy$w)iI6qX
zg}VH_{8)>=l>8>)<T|I>a7N9{!WMF?r@QO^>Hhe9KF{;|<NbbrK7V{t{d~NTt5K@~
z06>y=yYE-er1zx_SNA68W1Rq?=|*;U4Pf%5yoPX-Fw>TN|2@_oBkM7)H?M2yPU+bf
zG7%R>3{9hURO7Fv*!1bma7m9=SdHv^18c9xY8O3yrr&n(?)pr#wsrWc0hnZu5XS=Q
z#s0~ci<UdXJZyUvM7s6x;;6z&87=!R?yYkYHuQi18ZDPTjBZ{zs}clhTAbr@xq#^P
z;W*Z%SIfTs^*y0>0ZW`7j%AW#!JrI%kdo&K1_G0Fi*Se1lO_F<xy6e{NY5pe;!H0)
zjB%83D2_t~@R#8n8nJ%J=gawq{DhWHt(spm<K;7vbq**ZJZWIqV&Qf7tKt_>?SfV9
zg;Wv^@{fo?F)FCx4d6`CC?SB7*Fs8MQAyh?%60-<hz}!mHm{Pv@HeT##ty=Qd~g|!
zYpq|oG5ftaKv&g8fbs!Pg=)UrD`9AA`U=Gq$ptWw6EymT@TlN993Z8GqBDfA2w7`g
zs0n&a{fTC19iX|FuAi=)S2_Yr=$vBTY5Nm~UhLxnXqy15IkSIE*Pwt8kMUp3#rc)X
z?mM@3dCH}7T#gxS;Nb1kORcsMfWx9Rb(MDp!betBU4sDbfXnA3PcpIZK-DiAfYo&0
z^Nqa6b^x6@V-N2fj0|R0qET5D!zK$zE%kr{_iy7y4R-j@FEP^40wguA`_y5G>n4C$
zGjIFy8awCEm9+~YrjmqGnwpK5Z2alGLKfVdj}x9KyZ=t(Xfc43z4U_dVt*!2kM@Xq
zCbx<gO2tDWjzMD=(Kbc&$oYcS;uTDNEhv3CmcmDD<!A;mXQ!7#ZbVV+4VwAQamm1A
zHoN9=XLeE9UW>Hi&3_PxzIp&aG!WXYz--x<%@TJp2$M+Ybolrdnq)mqB5Enia!V9P
z2^HIkMpu;ROc^uxSh>mYRaURg6iU~)-1l-W3)i#eNb3?VP&_m;0h3g-_Qm{I+N3-)
zn|Y_Q?@vRap)e5LwRd-Q@Yz9BcWrerS#ix+=?!)+Ju`2toA9n1z*~A>D+~_%-PGJ7
zNK6^^Li@NkcqOLzshpTvQhsg__f5jLC^wJ-;v|8)qR5vzWWmP^;!DNFe9Lc!_d@4W
zNsI)W1Yd5UHGf-wi_%&l%~oz#=Eu{Do${S^^}C_8jxMHLI=ii%mblcT$W~U3(8OV)
zDrQHFaVjY-D8L94niY@G&*w0VY~KB#JPd0q(n!Z{x@CBi$jz&;Orl!p;wDOnJYL0Y
zR5aAl)UNtGn41kz+Z{0Xd3q?`!I3sD8UtUAw~L3yONdl3N$_6uUm+t>iQ%ok(G;w(
z^xlyh*3kIs@n$^d_(V7YlcVpFfhA`Y>OSAF4qK_HL11%qHngeiQZN&pm}H(UTRR&1
zEMN>5xPWz_v3t5ARL}Kkj;n^F@PR8!8LQUNL({kKrhh8*q~~t)mXE070kEm$l*!r@
z#*16@tvdR@sXpF@oPnKW*J#5LufYgdyXF5z_)ka*0k0>tp~2UT{ga6w>4$-isMmO+
zbq%Su`D8hH)yWUe?@@`3ONZ4ETvJS$#|P@LHDaM`AbQiPwmA}N&)09tCn7b~UlkyG
L__&wvq9^|aHQlu+

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/meta.json b/Resources/Textures/Mobs/Silicon/output.rsi/meta.json
new file mode 100644
index 0000000000..a40ed37c60
--- /dev/null
+++ b/Resources/Textures/Mobs/Silicon/output.rsi/meta.json
@@ -0,0 +1 @@
+{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/2a19963297f91efb452dbb5c1d4eb28a14776b0a/icons/mob/silicon/ai.dmi", "states": [{"name": "ai", "directions": 1, "delays": [[0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.1]]}, {"name": "ai-banned", "directions": 1, "delays": [[0.7, 0.7, 0.7, 0.7, 0.7, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]]}, {"name": "ai-banned-unshaded", "directions": 1, "delays": [[0.7, 0.7, 0.7, 0.7, 0.7, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7, 0.7]]}, {"name": "ai-banned_dead", "directions": 1, "delays": [[0.7, 0.7]]}, {"name": "ai-banned_dead-unshaded", "directions": 1, "delays": [[0.7, 0.7]]}, {"name": "ai-empty", "directions": 1, "delays": [[0.7, 0.7]]}, {"name": "ai-empty-unshaded", "directions": 1, "delays": [[0.7, 0.7]]}, {"name": "ai-holo-old", "directions": 4, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "ai-holo-old-unshaded", "directions": 4, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "ai-unshaded", "directions": 1, "delays": [[0.2, 0.2, 0.2, 0.1, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.1]]}, {"name": "ai_dead", "directions": 1, "delays": [[1.0]]}, {"name": "ai_dead-unshaded", "directions": 1, "delays": [[1.0]]}, {"name": "default", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "default-unshaded", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "floating_face", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "floating_face-unshaded", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "horror", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "horror-unshaded", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "xeno_queen", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "xeno_queen-unshaded", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]}
\ No newline at end of file
diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/xeno_queen-unshaded.png b/Resources/Textures/Mobs/Silicon/output.rsi/xeno_queen-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..3ea194039f4fee0b41d8c2f4b5f602592936f88f
GIT binary patch
literal 2484
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/output.rsi/xeno_queen.png b/Resources/Textures/Mobs/Silicon/output.rsi/xeno_queen.png
new file mode 100644
index 0000000000000000000000000000000000000000..3ea194039f4fee0b41d8c2f4b5f602592936f88f
GIT binary patch
literal 2484
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/station_ai.rsi/ai.png b/Resources/Textures/Mobs/Silicon/station_ai.rsi/ai.png
new file mode 100644
index 0000000000000000000000000000000000000000..420a07c1f96662a077d518546c866ea074cd556f
GIT binary patch
literal 9757
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
J<g3}-{2v}Hvk(9P

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_dead.png b/Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_dead.png
new file mode 100644
index 0000000000000000000000000000000000000000..eb74655e027f45f7ce830da6a337dcf2aa74c248
GIT binary patch
literal 4405
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
W51pTEd9e|sD$u89>Gr2AU-w^7I7~1A

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_empty.png b/Resources/Textures/Mobs/Silicon/station_ai.rsi/ai_empty.png
new file mode 100644
index 0000000000000000000000000000000000000000..40e8ac5216186918389147a014046b6e454f32cf
GIT binary patch
literal 4405
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
M(5LF^6E_$AAL$TFTL1t6

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/station_ai.rsi/base.png b/Resources/Textures/Mobs/Silicon/station_ai.rsi/base.png
new file mode 100644
index 0000000000000000000000000000000000000000..a9db83691c1db9415a193b3f61d8c42041893ce9
GIT binary patch
literal 4421
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/station_ai.rsi/default.png b/Resources/Textures/Mobs/Silicon/station_ai.rsi/default.png
new file mode 100644
index 0000000000000000000000000000000000000000..d52aceaf5b13f21bb46feabc481fb2d1e7fb0026
GIT binary patch
literal 2082
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
M07*qoM6N<$g4CVXe*gdg

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Mobs/Silicon/station_ai.rsi/meta.json b/Resources/Textures/Mobs/Silicon/station_ai.rsi/meta.json
new file mode 100644
index 0000000000..a3da52233d
--- /dev/null
+++ b/Resources/Textures/Mobs/Silicon/station_ai.rsi/meta.json
@@ -0,0 +1,52 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/2a19963297f91efb452dbb5c1d4eb28a14776b0a/icons/mob/silicon/ai.dmi",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "ai",
+      "delays": [
+        [
+          0.2,
+          0.2,
+          0.1,
+          0.2,
+          0.2,
+          0.2,
+          0.2,
+          0.2,
+          0.2,
+          0.2,
+          0.2,
+          0.2,
+          0.2,
+          0.2,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "ai_dead"
+    },
+    {
+      "name": "ai_empty",
+      "delays": [
+        [
+          0.7,
+          0.7
+        ]
+      ]
+    },
+    {
+      "name": "default",
+      "directions": 4
+    },
+    {
+      "name": "base"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Objects/Devices/ai_card.rsi/base.png b/Resources/Textures/Objects/Devices/ai_card.rsi/base.png
new file mode 100644
index 0000000000000000000000000000000000000000..244183c078c3d580cda31d0431ced9150a7cf7c9
GIT binary patch
literal 4432
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/ai_card.rsi/empty.png b/Resources/Textures/Objects/Devices/ai_card.rsi/empty.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e61f368de294ae506cdab73e818f0f594bb260c
GIT binary patch
literal 4292
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
HdhLGz@YfZx

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/ai_card.rsi/full.png b/Resources/Textures/Objects/Devices/ai_card.rsi/full.png
new file mode 100644
index 0000000000000000000000000000000000000000..59131c8c0aafc5f647d4409168265f23cc05e667
GIT binary patch
literal 5121
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/ai_card.rsi/inhand-left.png b/Resources/Textures/Objects/Devices/ai_card.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d3863145b951a7743066a59157c1cc7e562a50d
GIT binary patch
literal 306
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1FST
zi(^Q|oVT|QavnAiaJeXd!mxBHL-@l<A+1~<#eCTUPu2;#oY@oX*Zpa)BKzykoh%1p
zm=g3D4W={9@Mbup%J58xp_sG5GPB{a#k!9>zyJI3eW&X_#`)JO=0C5^IGT8Tx_t4~
zX@6Nl{8v5ulh<%-62mLgwUz6yO>>#Rwqw3njO^a1`qCRp_ZvjpV=T?<n~@F0Vb{*J
z%o^`_b7U8sx#xbv?m)tB#?)tLKVD-L`7XGPFCgtbZ;pII7?K-n8JpW2_vyKRWdiz_
N!PC{xWt~$(699E-bSwY>

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/ai_card.rsi/inhand-right.png b/Resources/Textures/Objects/Devices/ai_card.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..1704b9c3c112fc423e9466328df5e2bac1f15c87
GIT binary patch
literal 316
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1G3n
zi(^Q|oVT|&@*Xk}alP2>ax#YJfu_-<<sTSy#8XtfMH*z=55>Qq+r@Tz=cdWe;su{G
zbQCijv1E88!%)cAV8QM%hgsnqqky@H!qP3<?=PLg-977Oy17I2mx;#TbCXMR=a=4B
z7Tm@7O6h&-;vcs;GrI2<@d-aXVJch4c`bSCr@!mtmWzHXdSHK;F|7W_vln)MC0!sU
z;;;xJ?91L^WPHI`RN>Z{1Ny;?i_Y=X7}c^aI?Gd2{7O|KF>S%~kcJoh@js0_;4V~`
bf53TkzSA$a-26*GpEG#6`njxgN@xNATZDFx

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/ai_card.rsi/meta.json b/Resources/Textures/Objects/Devices/ai_card.rsi/meta.json
new file mode 100644
index 0000000000..8b8135fa16
--- /dev/null
+++ b/Resources/Textures/Objects/Devices/ai_card.rsi/meta.json
@@ -0,0 +1,58 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/1feffb747a33434a9d28450fc52ade75253aeba5/icons/obj/aicards.dmi",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "base"
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    },
+    {
+      "name": "empty",
+      "delays": [
+        [
+          0.4,
+          0.4
+        ]
+      ]
+    },
+    {
+      "name": "full",
+      "delays": [
+        [
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4,
+          0.4
+        ]
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/Objects/Devices/output.rsi/aicard-full-unshaded.png b/Resources/Textures/Objects/Devices/output.rsi/aicard-full-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..51a309d579ec0babdbdb117920c416e178e37599
GIT binary patch
literal 777
zcmYk2dq`6O6vk(g4nv2%j4Ul*DZWTh!`IbqxvA+wd?bbTPz;7!*mS1LYZ6o-Dnw>Z
z(HLfA?UK5N6W@~9%<Eh<ahoFP)WLPM>!x>ZyWQy@dElJGIh^zH<9l^8i{b8e-i<^e
zxu-Gd*+lOmvX1OR)P@K5y-B2F^J(;yoT_$2BQH}YpFTdH)*O*dJ-am_<TamMpqsa+
z0|z}y?*#`07Wgy<C(Q{Tlb-nnZel-vHIcX>gbWdr`zBktjW<{^8itBWe&P~yV<e<r
z=6>146sa(nyVDz9T|4mJ2v5$fSYW`#yhm<q^$lm+x$JF0sK#epw84<Kj#}a`B~Ve1
zDodZYsXLbV2*ZT@F^u0#RuHl?po;N`w?{}utreO4i#hh+zJKX-xGARC&SosLIr1oA
zX&wXOws|9nV%kZhW60a^4CEqfys!{@(ar^@BKr@3D2LPsbzo+Rm7igko5GEJCFNFn
z2v93lk95CP$*=+zIc@^SsZ+f+#IWC8x$nOLqlRdlS!u&dk)GZ_+-S+ehV-rtL7=)!
zy6GB_Bem5j)`}u-SEwoHGVSYqxhltE6u&A%h%21;RBEN|D$igv^iW_x69vXPPQaqZ
zHs2#y4@I4Z@<f{b!zrbIwMBPDrfKUmJ#VF%Q3PRX1>H9wv*!?&zGcvg*%qut)xX9S
z>t1$sLdZ9NC58Es!%wye<Ry?y>(tNxDhSH3bNFM~7SL#Ta~aGBsJb0AQ^lC|r2;F9
z7;S4q*z(Spzw4apJ>1FJu^s_Q7JjzzB;xf?+LrNEBRJr^y$Tz)xUG;7_-@6`%UDwA
zn4maCCz%G|(Os)V%1s1SR))T(rdBp=C!=>@mfVVBMyN)kN9%!jFO#4q##qEr`+=%;
z`VREOb#{TJN_TjLdMvWNX7U{VX-%F9`q!WzZfjC#DA%fi4y)3nr6fVa;U_TX|K{QP
lKXoFrat0r{5DgqqcUW9ur=%6PVI|Wsr(MsYi>Y_({{hD)pQQi*

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/output.rsi/aicard-full.png b/Resources/Textures/Objects/Devices/output.rsi/aicard-full.png
new file mode 100644
index 0000000000000000000000000000000000000000..03908b5284f4fd89c2ea79adc1227a271591a21b
GIT binary patch
literal 1746
zcmcJOeKb^Q7{JGOqpjhvO$n3Hu9UJzM`epE5lT&47D<L^r&5NbCNg(U?WVLiyG&Se
zla|UF$!GZ(m12^qjnb&*(oDmonZYp3$Gx*NEoW>0*#GvP^WOJ8?|I+zJkRg>z2|pq
z_n&8OV~)XK<^=}$?$phfb%Qa-RQLZmX5V5A#<U>NcVjTENK)iLb@X3&mK}`X9XiY-
z+=sX9ddB!IH+P|(;_j{>^D9Os+k%;k@CCWKLdGWUy5TFUuVwi%PiLg|nh1E8c2~8)
zQZDTSM;^dTt4S<w&YJ3K?`|dP;$TK!ufr+|Oo7UJ`#tC)?ipYOsCGSEINZG=Nj)0o
zQb~t8Ik=c#K>Pci*y);akQa`Mm`=_&<KX6HQrH!Zn-q@$04SfE(0Aa-z$>z=Uu#M<
zm%$o%(y#R^)u?5UX>|>_Y|;0tcJi|#FY1>HnZKjV2>pOGO_?-pj<+h!BNDXk*)6H?
z5!`7Y6_jTW)ScR3U-70#92|SR3Z-Rg6?xUKy_jA1d&cR>Y12tGKq(MX=?32xJ`(>C
z(c0o7!%-ip1%IltQcWkKCG50u#BI6k1<Onk>M3-UO>x+%xMjD-upyzM<8Esy{8(uf
z{;^b@4iA!Dx_PZ(Wn(!&5Pj0vwm8Fu>)VP}oSGzwh<$kC(dZXu6j5M7e+QySSGIY{
zHhNG7q9hFzUhJx)Uf*bUv!@yv^zjZ(72k;ORd89+`hX9w`+<z4!I-^Z@!)l~%+k4>
z;Td1Bc{B&uj)qv>%upLQT2tEg3MkZvJfr8;M?7mGO<}r^km_#W$vNzKlv<QY=@z62
zf-rf5nPVghdN%B;n}MN{Lrye)1fMjV@0!_c6B!FwMQv~+-J{j+H}@^Z2yr=Vxv@3R
zl7BLSS|5b5lrQbA&c-hBK`oT)N#5#_hECO5hxD`{j9PIf;I;vu7SWFNM#t%p<~{ZR
z_zv&v&wlX6%$gK5usWgI<xI$woz&|ZZJ(i<LvUiJ7)FwF0lDM}cwrvdmK-p;di2x|
z(>gWb0`grHl)vBjV?XN5Y_l~^CDVq*ht{-PD!io+8}4Wm*S1$HyoERj;FIsaJaJFm
zY?%S1vZY#+P%XMOY4P|M?NB9K`C)hrU%ipFsZHCA=(U{v{O2N!=^T~VtR3nl0ZY)U
zbd|xF(_|0s9B>_?dusv_Rh*BTq`XI^&r@}yano@59v8ohgvYm1{m|G*R>y~-BqSc~
zpL7%t^{8UfwCksg%7)8pVBvEnOd4Xzx@00a4^9?7BfY%gFlnI@`}*?J*5D5|A;)rV
zD{WY=Zx!<M=bF)2w<aZitH3qfJnJe%8o{5JBcU>bq?yoQg=dsq2cJ|vnZrgCU`^%M
zm$$A$j)enC<lPQk2ihW3;#&H+x~pXTL@|SSa-!!TB7`?s6Tu;D{#M}93lbgl2-Ye1
zxDMJr;sh4y+L9lq-$&OeU$x+9&b&$emF%3qtDZ1=OL|{Uu+T=U4Q5&C=Bx$(#xr{m
z+zEUn`MmE(VZT02y^WGE#g=P#3&52(T72RXL=lcQ)etu>`qz~s6LLF0Gz4MP8^tT{
z%F2`a<`O4*Zre9N@nrf`T<7mlRRy3=*S7egUBYn{kACL_)Frm6fw(G3ZXG_3jn;a6
zDIS_TlFcN;mPjsTrj$L~+Ln9#Q+x$>IM7Y3@7|2uqG$TtVDfyXUT03J9)?y_qL=s+
zgcVLvtdDR7!cg75T93Aa10TZW$IQg}To^(<;S)#$2TBMQvphaOIAazW+!j!#3jn&a
z&vC*VHluS8MtU!4tvz#4Qkm*<mi_*v$O&Apdl%s$p+qNY*GTXidSgxl*UZ$*$S(-b
z=^*r>$=hDV#-|vBhL#ZzL-ay`38ZVf@n7*W%chZIYc$F>O;bH2m8MN0{tu|2u*vQx
z#nPMPJau9TvY?^#sptg47j(kIx&k-7FR#(^>+Jj4E5PJSnw0-rw*2V-rnqD=YWB3V
UyS=uT6R77J=(pXM<r8)KFKs=l5dZ)H

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/output.rsi/aicard-unshaded.png b/Resources/Textures/Objects/Devices/output.rsi/aicard-unshaded.png
new file mode 100644
index 0000000000000000000000000000000000000000..6191a01ec4eb7cf6d356094a1068d824c8aa24ff
GIT binary patch
literal 138
zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQh}Z>jv*Cu-d=FzZ7>jFJ=nyn
zvQXUf#{s8@n>goMn*W_`4pf|dD@}gh@juJ2|5aVObN_z-pW@6{7){ae)~D<Y3=!9u
YuU=-6+U553GSF}aPgg&ebxsLQ03h!!IRF3v

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/output.rsi/aicard.png b/Resources/Textures/Objects/Devices/output.rsi/aicard.png
new file mode 100644
index 0000000000000000000000000000000000000000..57f604efb0eab5eab2f4bc17290c669a485c3056
GIT binary patch
literal 414
zcmV;P0b%}$P)<h;3K|Lk000e1NJLTq002M$001Be1^@s6qMd$(0004HNkl<Zc%1E+
zp-%%b6o-E!{1=#Wh$VAFV=$b?OiiC%z)T|$1Xqp1pr>Y-p1Xj+HA|+@=plM{%My0)
zwSC<s+xwZfbl3Zu_Pa~3fJUP^<@Chv)W6&8{qO5tjw8(XAJ{(7WbA5bo2Jdn1A4aw
zu(EQKAk07ahEK*jkS2B8AZvav7r$P&?}ATHK$}`buAc6J%gn7nXcF_!NchdQ)2ptf
zb+Zg?>u9*GrFHe&I(SSDz;Ayp+mxd+8Umj`uJ8OK>>Y3bKK%$(@S-T#Y-0@Ywq#$=
z;m;oV{Cvvi(-Tm=RPqZp9|qW6ftXbM+1j%olg~E5djP@)crQTb1`IOb`PDVV>;Xaz
zVDi%$P^%Za0SYyM$xmy*oZpAy2N}TNr#B!ru?7%P1IR1XfJ_Yl)BrW$<P9*!@JCSh
z6Eq;7rs21r2LS(ne{-s&0SWo^HZ|fzM&ul@YraOK(P)l1e>+74@UVnV&j0`b07*qo
IM6N<$f`|IS_5c6?

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Objects/Devices/output.rsi/meta.json b/Resources/Textures/Objects/Devices/output.rsi/meta.json
new file mode 100644
index 0000000000..500ecb8e3e
--- /dev/null
+++ b/Resources/Textures/Objects/Devices/output.rsi/meta.json
@@ -0,0 +1 @@
+{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/1feffb747a33434a9d28450fc52ade75253aeba5/icons/obj/aicards.dmi", "states": [{"name": "aicard", "directions": 1, "delays": [[0.4, 0.4]]}, {"name": "aicard-full", "directions": 1, "delays": [[0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]]}, {"name": "aicard-full-unshaded", "directions": 1, "delays": [[0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4, 0.4]]}, {"name": "aicard-unshaded", "directions": 1, "delays": [[0.4, 0.4]]}]}
\ No newline at end of file

From c866ffb45fcadbc32cb6e7a739863fd51a74483b Mon Sep 17 00:00:00 2001
From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Sun, 25 Aug 2024 22:05:39 +1000
Subject: [PATCH 02/38] Verb tweaks (#31309)

* Verb tweaks

Remove the LOS check because this is already done above in CanExamine.

* Fix outlines

* import
---
 .../Commands/SetMenuVisibilityCommand.cs      |  1 +
 .../ContextMenu/UI/EntityMenuUIController.cs  | 19 ++++++--
 Content.Client/Verbs/VerbSystem.cs            | 45 ++++---------------
 Content.Shared/Verbs/SharedVerbSystem.cs      | 24 ++++++++++
 4 files changed, 49 insertions(+), 40 deletions(-)

diff --git a/Content.Client/Commands/SetMenuVisibilityCommand.cs b/Content.Client/Commands/SetMenuVisibilityCommand.cs
index ddfb0b1692..17a544daba 100644
--- a/Content.Client/Commands/SetMenuVisibilityCommand.cs
+++ b/Content.Client/Commands/SetMenuVisibilityCommand.cs
@@ -1,4 +1,5 @@
 using Content.Client.Verbs;
+using Content.Shared.Verbs;
 using JetBrains.Annotations;
 using Robust.Shared.Console;
 
diff --git a/Content.Client/ContextMenu/UI/EntityMenuUIController.cs b/Content.Client/ContextMenu/UI/EntityMenuUIController.cs
index a60619baa3..b6f4dc1be2 100644
--- a/Content.Client/ContextMenu/UI/EntityMenuUIController.cs
+++ b/Content.Client/ContextMenu/UI/EntityMenuUIController.cs
@@ -9,6 +9,7 @@
 using Content.Shared.Examine;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Input;
+using Content.Shared.Verbs;
 using Robust.Client.GameObjects;
 using Robust.Client.Graphics;
 using Robust.Client.Input;
@@ -194,8 +195,20 @@ public override void FrameUpdate(FrameEventArgs args)
                 return;
 
             // Do we need to do in-range unOccluded checks?
-            var ignoreFov = !_eyeManager.CurrentEye.DrawFov ||
-                (_verbSystem.Visibility & MenuVisibility.NoFov) == MenuVisibility.NoFov;
+            var visibility = _verbSystem.Visibility;
+
+            if (!_eyeManager.CurrentEye.DrawFov)
+            {
+                visibility &= ~MenuVisibility.NoFov;
+            }
+
+            var ev = new MenuVisibilityEvent()
+            {
+                Visibility = visibility,
+            };
+
+            _entityManager.EventBus.RaiseLocalEvent(player, ref ev);
+            visibility = ev.Visibility;
 
             _entityManager.TryGetComponent(player, out ExaminerComponent? examiner);
             var xformQuery = _entityManager.GetEntityQuery<TransformComponent>();
@@ -209,7 +222,7 @@ public override void FrameUpdate(FrameEventArgs args)
                     continue;
                 }
 
-                if (ignoreFov)
+                if ((visibility & MenuVisibility.NoFov) == MenuVisibility.NoFov)
                     continue;
 
                 var pos = new MapCoordinates(_xform.GetWorldPosition(xform, xformQuery), xform.MapID);
diff --git a/Content.Client/Verbs/VerbSystem.cs b/Content.Client/Verbs/VerbSystem.cs
index 2513210e2c..e28f48d6a5 100644
--- a/Content.Client/Verbs/VerbSystem.cs
+++ b/Content.Client/Verbs/VerbSystem.cs
@@ -67,6 +67,14 @@ public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true
                 ? Visibility
                 : Visibility | MenuVisibility.NoFov;
 
+            var ev = new MenuVisibilityEvent()
+            {
+                TargetPos = targetPos,
+                Visibility = visibility,
+            };
+
+            RaiseLocalEvent(player.Value, ref ev);
+            visibility = ev.Visibility;
 
             // Get entities
             List<EntityUid> entities;
@@ -78,13 +86,8 @@ public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true
                 var entitiesUnderMouse = gameScreenBase.GetClickableEntities(targetPos).ToHashSet();
                 bool Predicate(EntityUid e) => e == player || entitiesUnderMouse.Contains(e);
 
-                // first check the general location.
-                if (!_examine.CanExamine(player.Value, targetPos, Predicate))
-                    return false;
-
                 TryComp(player.Value, out ExaminerComponent? examiner);
 
-                // Then check every entity
                 entities = new();
                 foreach (var ent in _entityLookup.GetEntitiesInRange(targetPos, EntityMenuLookupSize, flags: examineFlags))
                 {
@@ -138,27 +141,6 @@ public bool TryGetEntityMenuEntities(MapCoordinates targetPos, [NotNullWhen(true
                 }
             }
 
-            // Remove any entities that do not have LOS
-            if ((visibility & MenuVisibility.NoFov) == 0)
-            {
-                var xformQuery = GetEntityQuery<TransformComponent>();
-                var playerPos = _transform.GetMapCoordinates(player.Value, xform: xformQuery.GetComponent(player.Value));
-
-                for (var i = entities.Count - 1; i >= 0; i--)
-                {
-                    var entity = entities[i];
-
-                    if (!_examine.InRangeUnOccluded(
-                        playerPos,
-                        _transform.GetMapCoordinates(entity, xform: xformQuery.GetComponent(entity)),
-                        ExamineSystemShared.ExamineRange,
-                        null))
-                    {
-                        entities.RemoveSwap(i);
-                    }
-                }
-            }
-
             if (entities.Count == 0)
                 return false;
 
@@ -230,15 +212,4 @@ private void HandleVerbResponse(VerbsResponseEvent msg)
             OnVerbsResponse?.Invoke(msg);
         }
     }
-
-    [Flags]
-    public enum MenuVisibility
-    {
-        // What entities can a user see on the entity menu?
-        Default = 0,          // They can only see entities in FoV.
-        NoFov = 1 << 0,         // They ignore FoV restrictions
-        InContainer = 1 << 1,   // They can see through containers.
-        Invisible = 1 << 2,   // They can see entities without sprites and the "HideContextMenu" tag is ignored.
-        All = NoFov | InContainer | Invisible
-    }
 }
diff --git a/Content.Shared/Verbs/SharedVerbSystem.cs b/Content.Shared/Verbs/SharedVerbSystem.cs
index c3f906f293..37840dcbb5 100644
--- a/Content.Shared/Verbs/SharedVerbSystem.cs
+++ b/Content.Shared/Verbs/SharedVerbSystem.cs
@@ -3,6 +3,7 @@
 using Content.Shared.Interaction;
 using Content.Shared.Inventory.VirtualItem;
 using Robust.Shared.Containers;
+using Robust.Shared.Map;
 
 namespace Content.Shared.Verbs
 {
@@ -174,4 +175,27 @@ public virtual void ExecuteVerb(Verb verb, EntityUid user, EntityUid target, boo
                 _interactionSystem.DoContactInteraction(user, target);
         }
     }
+
+    // Does nothing on server
+    /// <summary>
+    /// Raised directed when trying to get the entity menu visibility for entities.
+    /// </summary>
+    [ByRefEvent]
+    public record struct MenuVisibilityEvent
+    {
+        public MapCoordinates TargetPos;
+        public MenuVisibility Visibility;
+    }
+
+    // Does nothing on server
+    [Flags]
+    public enum MenuVisibility
+    {
+        // What entities can a user see on the entity menu?
+        Default = 0,          // They can only see entities in FoV.
+        NoFov = 1 << 0,         // They ignore FoV restrictions
+        InContainer = 1 << 1,   // They can see through containers.
+        Invisible = 1 << 2,   // They can see entities without sprites and the "HideContextMenu" tag is ignored.
+        All = NoFov | InContainer | Invisible
+    }
 }

From d6b0b997c0b89a17409782198f80dc9cd95897e1 Mon Sep 17 00:00:00 2001
From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Sun, 25 Aug 2024 22:30:28 +1000
Subject: [PATCH 03/38] ItemToggle + slots stuff (#31312)

* ItemToggle + slots stuff

- Add component for itemslot locks to match LockComponent (surprised this didn't exist).
- Add thing for pointlight to match itemtoggle. In future should be used for PDAs and stuff but need to fix some other stuff first.

* Also this

* grill
---
 .../ItemSlot/ItemSlotsLockComponent.cs        | 13 ++++++
 .../ItemSlot/ItemSlotsSystem.Lock.cs          | 36 +++++++++++++++++
 .../Containers/ItemSlot/ItemSlotsSystem.cs    |  4 +-
 .../Components/ItemToggleComponent.cs         | 12 +++---
 .../Item/ItemToggle/ItemToggleSystem.cs       | 40 ++++++++++++++-----
 .../ItemTogglePointLightComponent.cs          | 12 ++++++
 .../ItemTogglePointLightSystem.cs             | 29 ++++++++++++++
 .../ItemSlotRequiresPowerComponent.cs         |  9 +++++
 .../ItemSlotRequiresPowerSystem.cs            | 23 +++++++++++
 Resources/Locale/en-US/items/toggle.ftl       |  2 +
 10 files changed, 163 insertions(+), 17 deletions(-)
 create mode 100644 Content.Shared/Containers/ItemSlot/ItemSlotsLockComponent.cs
 create mode 100644 Content.Shared/Containers/ItemSlot/ItemSlotsSystem.Lock.cs
 create mode 100644 Content.Shared/Light/Components/ItemTogglePointLightComponent.cs
 create mode 100644 Content.Shared/Light/EntitySystems/ItemTogglePointLightSystem.cs
 create mode 100644 Content.Shared/Power/Components/ItemSlotRequiresPowerComponent.cs
 create mode 100644 Content.Shared/Power/EntitySystems/ItemSlotRequiresPowerSystem.cs
 create mode 100644 Resources/Locale/en-US/items/toggle.ftl

diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsLockComponent.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsLockComponent.cs
new file mode 100644
index 0000000000..0d8901028d
--- /dev/null
+++ b/Content.Shared/Containers/ItemSlot/ItemSlotsLockComponent.cs
@@ -0,0 +1,13 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Containers.ItemSlots;
+
+/// <summary>
+/// Updates the relevant ItemSlots locks based on <see cref="LockComponent"/>
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ItemSlotsLockComponent : Component
+{
+    [DataField(required: true)]
+    public List<string> Slots = new();
+}
diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.Lock.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.Lock.cs
new file mode 100644
index 0000000000..ee5178df95
--- /dev/null
+++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.Lock.cs
@@ -0,0 +1,36 @@
+using Content.Shared.Lock;
+
+namespace Content.Shared.Containers.ItemSlots;
+
+public sealed partial class ItemSlotsSystem
+{
+    private void InitializeLock()
+    {
+        SubscribeLocalEvent<ItemSlotsLockComponent, MapInitEvent>(OnLockMapInit);
+        SubscribeLocalEvent<ItemSlotsLockComponent, LockToggledEvent>(OnLockToggled);
+    }
+
+    private void OnLockMapInit(Entity<ItemSlotsLockComponent> ent, ref MapInitEvent args)
+    {
+        if (!TryComp(ent.Owner, out LockComponent? lockComp))
+            return;
+
+        UpdateLocks(ent, lockComp.Locked);
+    }
+
+    private void OnLockToggled(Entity<ItemSlotsLockComponent> ent, ref LockToggledEvent args)
+    {
+        UpdateLocks(ent, args.Locked);
+    }
+
+    private void UpdateLocks(Entity<ItemSlotsLockComponent> ent, bool value)
+    {
+        foreach (var slot in ent.Comp.Slots)
+        {
+            if (!TryGetSlot(ent.Owner, slot, out var itemSlot))
+                continue;
+
+            SetLock(ent.Owner, itemSlot, value);
+        }
+    }
+}
diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs
index c8745d17d4..4fe49a6382 100644
--- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs
+++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs
@@ -26,7 +26,7 @@ namespace Content.Shared.Containers.ItemSlots
     ///     Note when using popups on entities with many slots with InsertOnInteract, EjectOnInteract or EjectOnUse:
     ///     A single use will try to insert to/eject from every slot and generate a popup for each that fails.
     /// </remarks>
-    public sealed class ItemSlotsSystem : EntitySystem
+    public sealed partial class ItemSlotsSystem : EntitySystem
     {
         [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
         [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
@@ -43,6 +43,8 @@ public override void Initialize()
         {
             base.Initialize();
 
+            InitializeLock();
+
             SubscribeLocalEvent<ItemSlotsComponent, MapInitEvent>(OnMapInit);
             SubscribeLocalEvent<ItemSlotsComponent, ComponentInit>(Oninitialize);
 
diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs
index 46249fdd0d..47edec135d 100644
--- a/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs
+++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs
@@ -19,6 +19,12 @@ public sealed partial class ItemToggleComponent : Component
     [DataField, AutoNetworkedField]
     public bool Activated = false;
 
+    /// <summary>
+    /// Can the entity be activated in the world.
+    /// </summary>
+    [DataField]
+    public bool OnActivate = true;
+
     /// <summary>
     /// If this is set to false then the item can't be toggled by pressing Z.
     /// Use another system to do it then.
@@ -52,12 +58,6 @@ public sealed partial class ItemToggleComponent : Component
     /// </summary>
     [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
     public SoundSpecifier? SoundFailToActivate;
-
-    /// <summary>
-    /// Whether or not to toggle the entity's lights on or off.
-    /// </summary>
-    [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
-    public bool ToggleLight = true;
 }
 
 /// <summary>
diff --git a/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs b/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs
index c4e4150659..044a1109a1 100644
--- a/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs
+++ b/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Interaction;
 using Content.Shared.Interaction.Events;
 using Content.Shared.Item.ItemToggle.Components;
 using Content.Shared.Popups;
@@ -5,6 +6,7 @@
 using Content.Shared.Temperature;
 using Content.Shared.Throwing;
 using Content.Shared.Toggleable;
+using Content.Shared.Verbs;
 using Content.Shared.Wieldable;
 using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
@@ -23,7 +25,6 @@ public sealed class ItemToggleSystem : EntitySystem
     [Dependency] private readonly INetManager _netManager = default!;
     [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
     [Dependency] private readonly SharedAudioSystem _audio = default!;
-    [Dependency] private readonly SharedPointLightSystem _light = default!;
     [Dependency] private readonly SharedPopupSystem _popup = default!;
 
     public override void Initialize()
@@ -35,6 +36,8 @@ public override void Initialize()
         SubscribeLocalEvent<ItemToggleComponent, ItemUnwieldedEvent>(TurnOffOnUnwielded);
         SubscribeLocalEvent<ItemToggleComponent, ItemWieldedEvent>(TurnOnOnWielded);
         SubscribeLocalEvent<ItemToggleComponent, UseInHandEvent>(OnUseInHand);
+        SubscribeLocalEvent<ItemToggleComponent, GetVerbsEvent<ActivationVerb>>(OnActivateVerb);
+        SubscribeLocalEvent<ItemToggleComponent, ActivateInWorldEvent>(OnActivate);
 
         SubscribeLocalEvent<ItemToggleHotComponent, IsHotEvent>(OnIsHotEvent);
 
@@ -67,6 +70,32 @@ private void OnUseInHand(Entity<ItemToggleComponent> ent, ref UseInHandEvent arg
         Toggle((ent, ent.Comp), args.User, predicted: ent.Comp.Predictable);
     }
 
+    private void OnActivateVerb(Entity<ItemToggleComponent> ent, ref GetVerbsEvent<ActivationVerb> args)
+    {
+        if (!args.CanAccess || !args.CanInteract)
+            return;
+
+        var user = args.User;
+
+        args.Verbs.Add(new ActivationVerb()
+        {
+            Text = !ent.Comp.Activated ? Loc.GetString("item-toggle-activate") : Loc.GetString("item-toggle-deactivate"),
+            Act = () =>
+            {
+                Toggle((ent.Owner, ent.Comp), user, predicted: ent.Comp.Predictable);
+            }
+        });
+    }
+
+    private void OnActivate(Entity<ItemToggleComponent> ent, ref ActivateInWorldEvent args)
+    {
+        if (args.Handled || !ent.Comp.OnActivate)
+            return;
+
+        args.Handled = true;
+        Toggle((ent.Owner, ent.Comp), args.User, predicted: ent.Comp.Predictable);
+    }
+
     /// <summary>
     /// Used when an item is attempted to be toggled.
     /// Sets its state to the opposite of what it is.
@@ -204,16 +233,7 @@ private void UpdateVisuals(Entity<ItemToggleComponent> ent)
         if (TryComp(ent, out AppearanceComponent? appearance))
         {
             _appearance.SetData(ent, ToggleVisuals.Toggled, ent.Comp.Activated, appearance);
-
-            if (ent.Comp.ToggleLight)
-                _appearance.SetData(ent, ToggleableLightVisuals.Enabled, ent.Comp.Activated, appearance);
         }
-
-        if (!ent.Comp.ToggleLight)
-            return;
-
-        if (_light.TryGetLight(ent, out var light))
-            _light.SetEnabled(ent, ent.Comp.Activated, light);
     }
 
     /// <summary>
diff --git a/Content.Shared/Light/Components/ItemTogglePointLightComponent.cs b/Content.Shared/Light/Components/ItemTogglePointLightComponent.cs
new file mode 100644
index 0000000000..6ac1bf236d
--- /dev/null
+++ b/Content.Shared/Light/Components/ItemTogglePointLightComponent.cs
@@ -0,0 +1,12 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Light.Components;
+
+/// <summary>
+/// Toggles point light on an entity whenever ItemToggle hits.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ItemTogglePointLightComponent : Component
+{
+
+}
diff --git a/Content.Shared/Light/EntitySystems/ItemTogglePointLightSystem.cs b/Content.Shared/Light/EntitySystems/ItemTogglePointLightSystem.cs
new file mode 100644
index 0000000000..7030c538c1
--- /dev/null
+++ b/Content.Shared/Light/EntitySystems/ItemTogglePointLightSystem.cs
@@ -0,0 +1,29 @@
+using Content.Shared.Item.ItemToggle.Components;
+using Content.Shared.Toggleable;
+using ItemTogglePointLightComponent = Content.Shared.Light.Components.ItemTogglePointLightComponent;
+
+namespace Content.Shared.Light.EntitySystems;
+
+/// <summary>
+/// Handles ItemToggle for PointLight
+/// </summary>
+public sealed class ItemTogglePointLightSystem : EntitySystem
+{
+    [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+    [Dependency] private readonly SharedPointLightSystem _light = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<ItemTogglePointLightComponent, ItemToggledEvent>(OnLightToggled);
+    }
+
+    private void OnLightToggled(Entity<ItemTogglePointLightComponent> ent, ref ItemToggledEvent args)
+    {
+        if (!_light.TryGetLight(ent.Owner, out var light))
+            return;
+
+        _appearance.SetData(ent, ToggleableLightVisuals.Enabled, args.Activated);
+        _light.SetEnabled(ent.Owner, args.Activated, comp: light);
+    }
+}
diff --git a/Content.Shared/Power/Components/ItemSlotRequiresPowerComponent.cs b/Content.Shared/Power/Components/ItemSlotRequiresPowerComponent.cs
new file mode 100644
index 0000000000..6e3b9eaca0
--- /dev/null
+++ b/Content.Shared/Power/Components/ItemSlotRequiresPowerComponent.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Power.Components;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ItemSlotRequiresPowerComponent : Component
+{
+
+}
diff --git a/Content.Shared/Power/EntitySystems/ItemSlotRequiresPowerSystem.cs b/Content.Shared/Power/EntitySystems/ItemSlotRequiresPowerSystem.cs
new file mode 100644
index 0000000000..3df8b91a98
--- /dev/null
+++ b/Content.Shared/Power/EntitySystems/ItemSlotRequiresPowerSystem.cs
@@ -0,0 +1,23 @@
+using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Power.Components;
+
+namespace Content.Shared.Power.EntitySystems;
+
+public sealed class ItemSlotRequiresPowerSystem : EntitySystem
+{
+    [Dependency] private readonly SharedPowerReceiverSystem _receiver = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<ItemSlotRequiresPowerComponent, ItemSlotInsertAttemptEvent>(OnInsertAttempt);
+    }
+
+    private void OnInsertAttempt(Entity<ItemSlotRequiresPowerComponent> ent, ref ItemSlotInsertAttemptEvent args)
+    {
+        if (!_receiver.IsPowered(ent.Owner))
+        {
+            args.Cancelled = true;
+        }
+    }
+}
diff --git a/Resources/Locale/en-US/items/toggle.ftl b/Resources/Locale/en-US/items/toggle.ftl
new file mode 100644
index 0000000000..bcf5c161a6
--- /dev/null
+++ b/Resources/Locale/en-US/items/toggle.ftl
@@ -0,0 +1,2 @@
+item-toggle-activate = Activate
+item-toggle-deactivate = Deactivate

From 56451fa5e7fd9910cf38d27e5cc0800bd71b9a2f Mon Sep 17 00:00:00 2001
From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Date: Wed, 19 Jun 2024 02:30:41 +1200
Subject: [PATCH 04/38] Station AI (#30944)

* Station AI overlay

* implement

* Bunch of ports

* Fix a heap of bugs and basic scouting

* helldivers

* Shuffle interactions a bit

* navmap stuff

* Revert "navmap stuff"

This reverts commit d1f89dd4be83233e22cf5dd062b2581f3c6da062.

* AI wires implemented

* Fix examines

* Optimise the overlay significantly

* Back to old static

* BUI radial working

* lots of work

* Saving work

* thanks fork

* alright

* pc

* AI upload console

* AI upload

* stuff

* Fix copy-paste shitcode

* AI actions

* navmap work

* Fixes

* first impressions

* a

* reh

* Revert "navmap work"

This reverts commit 6f63fea6e9245e189f368f97be3e32e9b210580e.

* OD

* radar

* weh

* Fix examines

* scoop mine eyes

* fixes

* reh

* Optimise

* Final round of optimisations

* Fixes

* fixes
---
 Content.Client/Interaction/DragDropSystem.cs  |  2 +-
 .../ReplaySpectatorSystem.Blockers.cs         |  7 +++-
 .../ActionBlocker/ActionBlockerSystem.cs      |  6 ++--
 .../Administration/SharedAdminFrozenSystem.cs |  8 ++++-
 Content.Shared/Cuffs/SharedCuffableSystem.cs  |  8 ++++-
 Content.Shared/Ghost/SharedGhostSystem.cs     |  8 ++++-
 .../Events/InteractionAttemptEvent.cs         | 34 ++++++++-----------
 .../SharedInteractionSystem.Blocking.cs       |  8 ++++-
 .../Systems/MobStateSystem.Subscribers.cs     | 13 ++++++-
 .../Puppet/SharedVentriloquistPuppetSystem.cs | 10 ++++--
 Content.Shared/Stunnable/SharedStunSystem.cs  |  7 ++--
 .../SubFloor/SharedSubFloorHideSystem.cs      |  4 +--
 12 files changed, 79 insertions(+), 36 deletions(-)

diff --git a/Content.Client/Interaction/DragDropSystem.cs b/Content.Client/Interaction/DragDropSystem.cs
index 8baa4d15fe..d249766bbc 100644
--- a/Content.Client/Interaction/DragDropSystem.cs
+++ b/Content.Client/Interaction/DragDropSystem.cs
@@ -495,7 +495,7 @@ private void RemoveHighlights()
         // CanInteract() doesn't support checking a second "target" entity.
         // Doing so manually:
         var ev = new GettingInteractedWithAttemptEvent(user, dragged);
-        RaiseLocalEvent(dragged, ev, true);
+        RaiseLocalEvent(dragged, ref ev);
 
         if (ev.Cancelled)
             return false;
diff --git a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Blockers.cs b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Blockers.cs
index 2fa862f3df..99d85350b5 100644
--- a/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Blockers.cs
+++ b/Content.Client/Replay/Spectator/ReplaySpectatorSystem.Blockers.cs
@@ -17,7 +17,7 @@ private void InitializeBlockers()
         SubscribeLocalEvent<ReplaySpectatorComponent, UseAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<ReplaySpectatorComponent, PickupAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<ReplaySpectatorComponent, ThrowAttemptEvent>(OnAttempt);
-        SubscribeLocalEvent<ReplaySpectatorComponent, InteractionAttemptEvent>(OnAttempt);
+        SubscribeLocalEvent<ReplaySpectatorComponent, InteractionAttemptEvent>(OnInteractAttempt);
         SubscribeLocalEvent<ReplaySpectatorComponent, AttackAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<ReplaySpectatorComponent, DropAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<ReplaySpectatorComponent, IsEquippingAttemptEvent>(OnAttempt);
@@ -27,6 +27,11 @@ private void InitializeBlockers()
         SubscribeLocalEvent<ReplaySpectatorComponent, PullAttemptEvent>(OnPullAttempt);
     }
 
+    private void OnInteractAttempt(Entity<ReplaySpectatorComponent> ent, ref InteractionAttemptEvent args)
+    {
+        args.Cancelled = true;
+    }
+
     private void OnAttempt(EntityUid uid, ReplaySpectatorComponent component, CancellableEntityEventArgs args)
     {
         args.Cancel();
diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
index bd6ee8cae1..457e3875d4 100644
--- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
+++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs
@@ -89,7 +89,7 @@ public bool CanInteract(EntityUid user, EntityUid? target)
                 return false;
 
             var ev = new InteractionAttemptEvent(user, target);
-            RaiseLocalEvent(user, ev);
+            RaiseLocalEvent(user, ref ev);
 
             if (ev.Cancelled)
                 return false;
@@ -98,7 +98,7 @@ public bool CanInteract(EntityUid user, EntityUid? target)
                 return true;
 
             var targetEv = new GettingInteractedWithAttemptEvent(user, target);
-            RaiseLocalEvent(target.Value, targetEv);
+            RaiseLocalEvent(target.Value, ref targetEv);
 
             return !targetEv.Cancelled;
         }
@@ -129,7 +129,7 @@ public bool CanUseHeldEntity(EntityUid user, EntityUid used)
         public bool CanConsciouslyPerformAction(EntityUid user)
         {
             var ev = new ConsciousAttemptEvent(user);
-            RaiseLocalEvent(user, ev);
+            RaiseLocalEvent(user, ref ev);
 
             return !ev.Cancelled;
         }
diff --git a/Content.Shared/Administration/SharedAdminFrozenSystem.cs b/Content.Shared/Administration/SharedAdminFrozenSystem.cs
index 2fa22e0005..259df2bdf2 100644
--- a/Content.Shared/Administration/SharedAdminFrozenSystem.cs
+++ b/Content.Shared/Administration/SharedAdminFrozenSystem.cs
@@ -11,6 +11,7 @@
 
 namespace Content.Shared.Administration;
 
+// TODO deduplicate with BlockMovementComponent
 public abstract class SharedAdminFrozenSystem : EntitySystem
 {
     [Dependency] private readonly ActionBlockerSystem _blocker = default!;
@@ -23,7 +24,7 @@ public override void Initialize()
         SubscribeLocalEvent<AdminFrozenComponent, UseAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<AdminFrozenComponent, PickupAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<AdminFrozenComponent, ThrowAttemptEvent>(OnAttempt);
-        SubscribeLocalEvent<AdminFrozenComponent, InteractionAttemptEvent>(OnAttempt);
+        SubscribeLocalEvent<AdminFrozenComponent, InteractionAttemptEvent>(OnInteractAttempt);
         SubscribeLocalEvent<AdminFrozenComponent, ComponentStartup>(OnStartup);
         SubscribeLocalEvent<AdminFrozenComponent, ComponentShutdown>(UpdateCanMove);
         SubscribeLocalEvent<AdminFrozenComponent, UpdateCanMoveEvent>(OnUpdateCanMove);
@@ -34,6 +35,11 @@ public override void Initialize()
         SubscribeLocalEvent<AdminFrozenComponent, SpeakAttemptEvent>(OnSpeakAttempt);
     }
 
+    private void OnInteractAttempt(Entity<AdminFrozenComponent> ent, ref InteractionAttemptEvent args)
+    {
+        args.Cancelled = true;
+    }
+
     private void OnSpeakAttempt(EntityUid uid, AdminFrozenComponent component, SpeakAttemptEvent args)
     {
         if (!component.Muted)
diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs
index 1c8e2ef2b0..dbc2ba06c9 100644
--- a/Content.Shared/Cuffs/SharedCuffableSystem.cs
+++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs
@@ -84,7 +84,7 @@ public override void Initialize()
             SubscribeLocalEvent<CuffableComponent, PickupAttemptEvent>(CheckAct);
             SubscribeLocalEvent<CuffableComponent, AttackAttemptEvent>(CheckAct);
             SubscribeLocalEvent<CuffableComponent, UseAttemptEvent>(CheckAct);
-            SubscribeLocalEvent<CuffableComponent, InteractionAttemptEvent>(CheckAct);
+            SubscribeLocalEvent<CuffableComponent, InteractionAttemptEvent>(CheckInteract);
 
             SubscribeLocalEvent<HandcuffComponent, AfterInteractEvent>(OnCuffAfterInteract);
             SubscribeLocalEvent<HandcuffComponent, MeleeHitEvent>(OnCuffMeleeHit);
@@ -92,6 +92,12 @@ public override void Initialize()
             SubscribeLocalEvent<HandcuffComponent, VirtualItemDeletedEvent>(OnCuffVirtualItemDeleted);
         }
 
+        private void CheckInteract(Entity<CuffableComponent> ent, ref InteractionAttemptEvent args)
+        {
+            if (!ent.Comp.CanStillInteract)
+                args.Cancelled = true;
+        }
+
         private void OnUncuffAttempt(ref UncuffAttemptEvent args)
         {
             if (args.Cancelled)
diff --git a/Content.Shared/Ghost/SharedGhostSystem.cs b/Content.Shared/Ghost/SharedGhostSystem.cs
index 6f7370fe58..091775b6c2 100644
--- a/Content.Shared/Ghost/SharedGhostSystem.cs
+++ b/Content.Shared/Ghost/SharedGhostSystem.cs
@@ -20,13 +20,19 @@ public override void Initialize()
         {
             base.Initialize();
             SubscribeLocalEvent<GhostComponent, UseAttemptEvent>(OnAttempt);
-            SubscribeLocalEvent<GhostComponent, InteractionAttemptEvent>(OnAttempt);
+            SubscribeLocalEvent<GhostComponent, InteractionAttemptEvent>(OnAttemptInteract);
             SubscribeLocalEvent<GhostComponent, EmoteAttemptEvent>(OnAttempt);
             SubscribeLocalEvent<GhostComponent, DropAttemptEvent>(OnAttempt);
             SubscribeLocalEvent<GhostComponent, PickupAttemptEvent>(OnAttempt);
             SubscribeLocalEvent<GhostComponent, InteractionVerbAttemptEvent>(OnAttempt);
         }
 
+        private void OnAttemptInteract(Entity<GhostComponent> ent, ref InteractionAttemptEvent args)
+        {
+            if (!ent.Comp.CanGhostInteract)
+                args.Cancelled = true;
+        }
+
         private void OnAttempt(EntityUid uid, GhostComponent component, CancellableEntityEventArgs args)
         {
             if (!component.CanGhostInteract)
diff --git a/Content.Shared/Interaction/Events/InteractionAttemptEvent.cs b/Content.Shared/Interaction/Events/InteractionAttemptEvent.cs
index 0024811c36..a04c053635 100644
--- a/Content.Shared/Interaction/Events/InteractionAttemptEvent.cs
+++ b/Content.Shared/Interaction/Events/InteractionAttemptEvent.cs
@@ -3,39 +3,33 @@
     /// <summary>
     ///     Event raised directed at a user to see if they can perform a generic interaction.
     /// </summary>
-    public sealed class InteractionAttemptEvent : CancellableEntityEventArgs
+    [ByRefEvent]
+    public struct InteractionAttemptEvent(EntityUid uid, EntityUid? target)
     {
-        public InteractionAttemptEvent(EntityUid uid, EntityUid? target)
-        {
-            Uid = uid;
-            Target = target;
-        }
-
-        public EntityUid Uid { get; }
-        public EntityUid? Target { get; }
+        public bool Cancelled;
+        public readonly EntityUid Uid = uid;
+        public readonly EntityUid? Target = target;
     }
 
     /// <summary>
     /// Raised to determine whether an entity is conscious to perform an action.
     /// </summary>
-    public sealed class ConsciousAttemptEvent(EntityUid Uid) : CancellableEntityEventArgs
+    [ByRefEvent]
+    public struct ConsciousAttemptEvent(EntityUid uid)
     {
-        public EntityUid Uid { get; } = Uid;
+        public bool Cancelled;
+        public readonly EntityUid Uid = uid;
     }
 
     /// <summary>
     ///     Event raised directed at the target entity of an interaction to see if the user is allowed to perform some
     ///     generic interaction.
     /// </summary>
-    public sealed class GettingInteractedWithAttemptEvent : CancellableEntityEventArgs
+    [ByRefEvent]
+    public struct GettingInteractedWithAttemptEvent(EntityUid uid, EntityUid? target)
     {
-        public GettingInteractedWithAttemptEvent(EntityUid uid, EntityUid? target)
-        {
-            Uid = uid;
-            Target = target;
-        }
-
-        public EntityUid Uid { get; }
-        public EntityUid? Target { get; }
+        public bool Cancelled;
+        public readonly EntityUid Uid = uid;
+        public readonly EntityUid? Target = target;
     }
 }
diff --git a/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs b/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs
index 9a84789adf..a682bf9815 100644
--- a/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs
+++ b/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs
@@ -6,6 +6,7 @@
 
 namespace Content.Shared.Interaction;
 
+// TODO deduplicate with AdminFrozenComponent
 /// <summary>
 /// Handles <see cref="BlockMovementComponent"/>, which prevents various
 /// kinds of movement and interactions when attached to an entity.
@@ -16,7 +17,7 @@ public void InitializeBlocking()
     {
         SubscribeLocalEvent<BlockMovementComponent, UpdateCanMoveEvent>(OnMoveAttempt);
         SubscribeLocalEvent<BlockMovementComponent, UseAttemptEvent>(CancelEvent);
-        SubscribeLocalEvent<BlockMovementComponent, InteractionAttemptEvent>(CancelEvent);
+        SubscribeLocalEvent<BlockMovementComponent, InteractionAttemptEvent>(CancelInteractEvent);
         SubscribeLocalEvent<BlockMovementComponent, DropAttemptEvent>(CancelEvent);
         SubscribeLocalEvent<BlockMovementComponent, PickupAttemptEvent>(CancelEvent);
         SubscribeLocalEvent<BlockMovementComponent, ChangeDirectionAttemptEvent>(CancelEvent);
@@ -25,6 +26,11 @@ public void InitializeBlocking()
         SubscribeLocalEvent<BlockMovementComponent, ComponentShutdown>(OnBlockingShutdown);
     }
 
+    private void CancelInteractEvent(Entity<BlockMovementComponent> ent, ref InteractionAttemptEvent args)
+    {
+        args.Cancelled = true;
+    }
+
     private void OnMoveAttempt(EntityUid uid, BlockMovementComponent component, UpdateCanMoveEvent args)
     {
         if (component.LifeStage > ComponentLifeStage.Running)
diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs
index a467c89364..f5acced4db 100644
--- a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs
+++ b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs
@@ -33,7 +33,7 @@ private void SubscribeEvents()
         SubscribeLocalEvent<MobStateComponent, ChangeDirectionAttemptEvent>(OnDirectionAttempt);
         SubscribeLocalEvent<MobStateComponent, UseAttemptEvent>(CheckAct);
         SubscribeLocalEvent<MobStateComponent, AttackAttemptEvent>(CheckAct);
-        SubscribeLocalEvent<MobStateComponent, ConsciousAttemptEvent>(CheckAct);
+        SubscribeLocalEvent<MobStateComponent, ConsciousAttemptEvent>(CheckConcious);
         SubscribeLocalEvent<MobStateComponent, ThrowAttemptEvent>(CheckAct);
         SubscribeLocalEvent<MobStateComponent, SpeakAttemptEvent>(OnSpeakAttempt);
         SubscribeLocalEvent<MobStateComponent, IsEquippingAttemptEvent>(OnEquipAttempt);
@@ -91,6 +91,17 @@ private void OnUnbuckleAttempt(Entity<MobStateComponent> ent, ref UnbuckleAttemp
             args.Cancelled = true;
     }
 
+    private void CheckConcious(Entity<MobStateComponent> ent, ref ConsciousAttemptEvent args)
+    {
+        switch (ent.Comp.CurrentState)
+        {
+            case MobState.Dead:
+            case MobState.Critical:
+                args.Cancelled = true;
+                break;
+        }
+    }
+
     private void OnStateExitSubscribers(EntityUid target, MobStateComponent component, MobState state)
     {
         switch (state)
diff --git a/Content.Shared/Puppet/SharedVentriloquistPuppetSystem.cs b/Content.Shared/Puppet/SharedVentriloquistPuppetSystem.cs
index 430c2b1b17..e3fa21ed37 100644
--- a/Content.Shared/Puppet/SharedVentriloquistPuppetSystem.cs
+++ b/Content.Shared/Puppet/SharedVentriloquistPuppetSystem.cs
@@ -7,6 +7,7 @@
 
 namespace Content.Shared.Puppet;
 
+// TODO deduplicate with BlockMovementComponent
 public abstract class SharedVentriloquistPuppetSystem : EntitySystem
 {
     [Dependency] private readonly ActionBlockerSystem _blocker = default!;
@@ -15,7 +16,7 @@ public override void Initialize()
     {
         base.Initialize();
         SubscribeLocalEvent<VentriloquistPuppetComponent, UseAttemptEvent>(Cancel);
-        SubscribeLocalEvent<VentriloquistPuppetComponent, InteractionAttemptEvent>(Cancel);
+        SubscribeLocalEvent<VentriloquistPuppetComponent, InteractionAttemptEvent>(CancelInteract);
         SubscribeLocalEvent<VentriloquistPuppetComponent, DropAttemptEvent>(Cancel);
         SubscribeLocalEvent<VentriloquistPuppetComponent, PickupAttemptEvent>(Cancel);
         SubscribeLocalEvent<VentriloquistPuppetComponent, UpdateCanMoveEvent>(Cancel);
@@ -24,6 +25,11 @@ public override void Initialize()
         SubscribeLocalEvent<VentriloquistPuppetComponent, ComponentStartup>(OnStartup);
     }
 
+    private void CancelInteract(Entity<VentriloquistPuppetComponent> ent, ref InteractionAttemptEvent args)
+    {
+        args.Cancelled = true;
+    }
+
     private void OnStartup(EntityUid uid, VentriloquistPuppetComponent component, ComponentStartup args)
     {
         _blocker.UpdateCanMove(uid);
@@ -33,4 +39,4 @@ private void Cancel<T>(EntityUid uid, VentriloquistPuppetComponent component, T
     {
         args.Cancel();
     }
-}
\ No newline at end of file
+}
diff --git a/Content.Shared/Stunnable/SharedStunSystem.cs b/Content.Shared/Stunnable/SharedStunSystem.cs
index 9d2e8d3dde..be5630cea0 100644
--- a/Content.Shared/Stunnable/SharedStunSystem.cs
+++ b/Content.Shared/Stunnable/SharedStunSystem.cs
@@ -68,7 +68,7 @@ public override void Initialize()
         // Attempt event subscriptions.
         SubscribeLocalEvent<StunnedComponent, ChangeDirectionAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<StunnedComponent, UpdateCanMoveEvent>(OnMoveAttempt);
-        SubscribeLocalEvent<StunnedComponent, InteractionAttemptEvent>(OnAttempt);
+        SubscribeLocalEvent<StunnedComponent, InteractionAttemptEvent>(OnAttemptInteract);
         SubscribeLocalEvent<StunnedComponent, UseAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<StunnedComponent, ThrowAttemptEvent>(OnAttempt);
         SubscribeLocalEvent<StunnedComponent, DropAttemptEvent>(OnAttempt);
@@ -79,7 +79,10 @@ public override void Initialize()
         SubscribeLocalEvent<MobStateComponent, MobStateChangedEvent>(OnMobStateChanged);
     }
 
-
+    private void OnAttemptInteract(Entity<StunnedComponent> ent, ref InteractionAttemptEvent args)
+    {
+        args.Cancelled = true;
+    }
 
     private void OnMobStateChanged(EntityUid uid, MobStateComponent component, MobStateChangedEvent args)
     {
diff --git a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
index ba78ff651f..cebc84ecb9 100644
--- a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
+++ b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs
@@ -45,11 +45,11 @@ private void OnAttackAttempt(EntityUid uid, SubFloorHideComponent component, ref
                 args.Cancelled = true;
         }
 
-        private void OnInteractionAttempt(EntityUid uid, SubFloorHideComponent component, GettingInteractedWithAttemptEvent args)
+        private void OnInteractionAttempt(EntityUid uid, SubFloorHideComponent component, ref GettingInteractedWithAttemptEvent args)
         {
             // No interactions with entities hidden under floor tiles.
             if (component.BlockInteractions && component.IsUnderCover)
-                args.Cancel();
+                args.Cancelled = true;
         }
 
         private void OnSubFloorStarted(EntityUid uid, SubFloorHideComponent component, ComponentStartup _)

From bdafdeb7052aefa6e0f749f2e04c28bf33a78f4b Mon Sep 17 00:00:00 2001
From: Tayrtahn <tayrtahn@gmail.com>
Date: Thu, 13 Jun 2024 22:15:29 -0400
Subject: [PATCH 05/38] Move SleepingSystem to Shared & cleanup (#28672)

* Move SleepingSystem to Shared & cleanup

* Remove empty OnShutdown handler
---
 Content.Client/Bed/SleepingSystem.cs          |   8 -
 Content.Server/Bed/BedSystem.cs               |   1 -
 Content.Server/Bed/Sleep/SleepingSystem.cs    | 261 ---------------
 .../Damage/ForceSay/DamageForceSaySystem.cs   |   1 +
 .../Bed/Sleep/SharedSleepingSystem.cs         | 102 ------
 Content.Shared/Bed/Sleep/SleepingComponent.cs |  31 +-
 Content.Shared/Bed/Sleep/SleepingSystem.cs    | 314 ++++++++++++++++++
 .../Bed/Sleep}/SnoringComponent.cs            |   6 +-
 8 files changed, 340 insertions(+), 384 deletions(-)
 delete mode 100644 Content.Client/Bed/SleepingSystem.cs
 delete mode 100644 Content.Server/Bed/Sleep/SleepingSystem.cs
 delete mode 100644 Content.Shared/Bed/Sleep/SharedSleepingSystem.cs
 create mode 100644 Content.Shared/Bed/Sleep/SleepingSystem.cs
 rename {Content.Server/Bed/Components => Content.Shared/Bed/Sleep}/SnoringComponent.cs (54%)

diff --git a/Content.Client/Bed/SleepingSystem.cs b/Content.Client/Bed/SleepingSystem.cs
deleted file mode 100644
index addf855bf3..0000000000
--- a/Content.Client/Bed/SleepingSystem.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using Content.Server.Bed.Sleep;
-
-namespace Content.Client.Bed;
-
-public sealed class SleepingSystem : SharedSleepingSystem
-{
-
-}
diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs
index 2335859f0b..7220c04ea8 100644
--- a/Content.Server/Bed/BedSystem.cs
+++ b/Content.Server/Bed/BedSystem.cs
@@ -1,6 +1,5 @@
 using Content.Server.Actions;
 using Content.Server.Bed.Components;
-using Content.Server.Bed.Sleep;
 using Content.Server.Body.Systems;
 using Content.Server.Construction;
 using Content.Server.Power.Components;
diff --git a/Content.Server/Bed/Sleep/SleepingSystem.cs b/Content.Server/Bed/Sleep/SleepingSystem.cs
deleted file mode 100644
index 47966c4814..0000000000
--- a/Content.Server/Bed/Sleep/SleepingSystem.cs
+++ /dev/null
@@ -1,261 +0,0 @@
-using Content.Server.Popups;
-using Content.Server.Sound;
-using Content.Shared.Sound.Components;
-using Content.Shared.Actions;
-using Content.Shared.Audio;
-using Content.Shared.Bed.Sleep;
-using Content.Shared.Damage;
-using Content.Shared.Examine;
-using Content.Shared.IdentityManagement;
-using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
-using Content.Shared.Mobs;
-using Content.Shared.Mobs.Components;
-using Content.Shared.Slippery;
-using Content.Shared.StatusEffect;
-using Content.Shared.Stunnable;
-using Content.Shared.Verbs;
-using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
-using Robust.Shared.Player;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
-using Robust.Shared.Timing;
-
-namespace Content.Server.Bed.Sleep
-{
-    public sealed class SleepingSystem : SharedSleepingSystem
-    {
-        [Dependency] private readonly IGameTiming _gameTiming = default!;
-        [Dependency] private readonly IRobustRandom _robustRandom = default!;
-        [Dependency] private readonly PopupSystem _popupSystem = default!;
-        [Dependency] private readonly SharedAudioSystem _audio = default!;
-        [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
-        [Dependency] private readonly EmitSoundSystem _emitSound = default!;
-
-        [ValidatePrototypeId<EntityPrototype>] public const string SleepActionId = "ActionSleep";
-
-        public override void Initialize()
-        {
-            base.Initialize();
-            SubscribeLocalEvent<MobStateComponent, SleepStateChangedEvent>(OnSleepStateChanged);
-            SubscribeLocalEvent<SleepingComponent, DamageChangedEvent>(OnDamageChanged);
-            SubscribeLocalEvent<MobStateComponent, SleepActionEvent>(OnSleepAction);
-            SubscribeLocalEvent<ActionsContainerComponent, SleepActionEvent>(OnBedSleepAction);
-            SubscribeLocalEvent<MobStateComponent, WakeActionEvent>(OnWakeAction);
-            SubscribeLocalEvent<SleepingComponent, MobStateChangedEvent>(OnMobStateChanged);
-            SubscribeLocalEvent<SleepingComponent, GetVerbsEvent<AlternativeVerb>>(AddWakeVerb);
-            SubscribeLocalEvent<SleepingComponent, InteractHandEvent>(OnInteractHand);
-            SubscribeLocalEvent<SleepingComponent, ExaminedEvent>(OnExamined);
-            SubscribeLocalEvent<SleepingComponent, SlipAttemptEvent>(OnSlip);
-            SubscribeLocalEvent<SleepingComponent, ConsciousAttemptEvent>(OnConsciousAttempt);
-            SubscribeLocalEvent<ForcedSleepingComponent, ComponentInit>(OnInit);
-        }
-
-        /// <summary>
-        /// when sleeping component is added or removed, we do some stuff with other components.
-        /// </summary>
-        private void OnSleepStateChanged(EntityUid uid, MobStateComponent component, SleepStateChangedEvent args)
-        {
-            if (args.FellAsleep)
-            {
-                // Expiring status effects would remove the components needed for sleeping
-                _statusEffectsSystem.TryRemoveStatusEffect(uid, "Stun");
-                _statusEffectsSystem.TryRemoveStatusEffect(uid, "KnockedDown");
-
-                EnsureComp<StunnedComponent>(uid);
-                EnsureComp<KnockedDownComponent>(uid);
-
-                if (TryComp<SleepEmitSoundComponent>(uid, out var sleepSound))
-                {
-                    var emitSound = EnsureComp<SpamEmitSoundComponent>(uid);
-                    if (HasComp<SnoringComponent>(uid))
-                    {
-                        emitSound.Sound = sleepSound.Snore;
-                    }
-                    emitSound.MinInterval = sleepSound.Interval;
-                    emitSound.MaxInterval = sleepSound.MaxInterval;
-                    emitSound.PopUp = sleepSound.PopUp;
-                }
-
-                return;
-            }
-
-            RemComp<StunnedComponent>(uid);
-            RemComp<KnockedDownComponent>(uid);
-            RemComp<SpamEmitSoundComponent>(uid);
-        }
-
-        /// <summary>
-        /// Wake up on taking an instance of damage at least the value of WakeThreshold.
-        /// </summary>
-        private void OnDamageChanged(EntityUid uid, SleepingComponent component, DamageChangedEvent args)
-        {
-            if (!args.DamageIncreased || args.DamageDelta == null)
-                return;
-
-            /* Shitmed Change Start - Surgery needs this, sorry! If the nocturine gamers get too feisty
-            I'll probably just increase the threshold */
-
-            if (args.DamageDelta.GetTotal() >= component.WakeThreshold
-                && !HasComp<ForcedSleepingComponent>(uid))
-                TryWaking(uid, component);
-
-            // Shitmed Change End
-
-        }
-
-        private void OnSleepAction(EntityUid uid, MobStateComponent component, SleepActionEvent args)
-        {
-            TrySleeping(uid);
-        }
-
-        private void OnBedSleepAction(EntityUid uid, ActionsContainerComponent component, SleepActionEvent args)
-        {
-            TrySleeping(args.Performer);
-        }
-
-        private void OnWakeAction(EntityUid uid, MobStateComponent component, WakeActionEvent args)
-        {
-            if (!TryWakeCooldown(uid))
-                return;
-
-            if (TryWaking(uid))
-                args.Handled = true;
-        }
-
-        /// <summary>
-        /// In crit, we wake up if we are not being forced to sleep.
-        /// And, you can't sleep when dead...
-        /// </summary>
-        private void OnMobStateChanged(EntityUid uid, SleepingComponent component, MobStateChangedEvent args)
-        {
-            if (args.NewMobState == MobState.Dead)
-            {
-                RemComp<SpamEmitSoundComponent>(uid);
-                RemComp<SleepingComponent>(uid);
-                return;
-            }
-            if (TryComp<SpamEmitSoundComponent>(uid, out var spam))
-                _emitSound.SetEnabled((uid, spam), args.NewMobState == MobState.Alive);
-        }
-
-        private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent<AlternativeVerb> args)
-        {
-            if (!args.CanInteract || !args.CanAccess)
-                return;
-
-            AlternativeVerb verb = new()
-            {
-                Act = () =>
-                {
-                    if (!TryWakeCooldown(uid))
-                        return;
-
-                    TryWaking(args.Target, user: args.User);
-                },
-                Text = Loc.GetString("action-name-wake"),
-                Priority = 2
-            };
-
-            args.Verbs.Add(verb);
-        }
-
-        /// <summary>
-        /// When you click on a sleeping person with an empty hand, try to wake them.
-        /// </summary>
-        private void OnInteractHand(EntityUid uid, SleepingComponent component, InteractHandEvent args)
-        {
-            args.Handled = true;
-
-            if (!TryWakeCooldown(uid))
-                return;
-
-            TryWaking(args.Target, user: args.User);
-        }
-
-        private void OnExamined(EntityUid uid, SleepingComponent component, ExaminedEvent args)
-        {
-            if (args.IsInDetailsRange)
-            {
-                args.PushMarkup(Loc.GetString("sleep-examined", ("target", Identity.Entity(uid, EntityManager))));
-            }
-        }
-
-        private void OnSlip(EntityUid uid, SleepingComponent component, SlipAttemptEvent args)
-        {
-            args.Cancel();
-        }
-
-        private void OnConsciousAttempt(EntityUid uid, SleepingComponent component, ConsciousAttemptEvent args)
-        {
-            args.Cancel();
-        }
-
-
-        private void OnInit(EntityUid uid, ForcedSleepingComponent component, ComponentInit args)
-        {
-            TrySleeping(uid);
-        }
-
-        /// <summary>
-        /// Try sleeping. Only mobs can sleep.
-        /// </summary>
-        public bool TrySleeping(EntityUid uid)
-        {
-            if (!HasComp<MobStateComponent>(uid))
-                return false;
-
-            var tryingToSleepEvent = new TryingToSleepEvent(uid);
-            RaiseLocalEvent(uid, ref tryingToSleepEvent);
-            if (tryingToSleepEvent.Cancelled)
-                return false;
-
-            EnsureComp<SleepingComponent>(uid);
-            return true;
-        }
-
-        private bool TryWakeCooldown(EntityUid uid, SleepingComponent? component = null)
-        {
-            if (!Resolve(uid, ref component, false))
-                return false;
-
-            var curTime = _gameTiming.CurTime;
-
-            if (curTime < component.CoolDownEnd)
-            {
-                return false;
-            }
-
-            component.CoolDownEnd = curTime + component.Cooldown;
-            return true;
-        }
-
-        /// <summary>
-        /// Try to wake up.
-        /// </summary>
-        public bool TryWaking(EntityUid uid, SleepingComponent? component = null, bool force = false, EntityUid? user = null)
-        {
-            if (!Resolve(uid, ref component, false))
-                return false;
-
-            if (!force && HasComp<ForcedSleepingComponent>(uid))
-            {
-                if (user != null)
-                {
-                    _audio.PlayPvs("/Audio/Effects/thudswoosh.ogg", uid, AudioHelpers.WithVariation(0.05f, _robustRandom));
-                    _popupSystem.PopupEntity(Loc.GetString("wake-other-failure", ("target", Identity.Entity(uid, EntityManager))), uid, Filter.Entities(user.Value), true, Shared.Popups.PopupType.SmallCaution);
-                }
-                return false;
-            }
-
-            if (user != null)
-            {
-                _audio.PlayPvs("/Audio/Effects/thudswoosh.ogg", uid, AudioHelpers.WithVariation(0.05f, _robustRandom));
-                _popupSystem.PopupEntity(Loc.GetString("wake-other-success", ("target", Identity.Entity(uid, EntityManager))), uid, Filter.Entities(user.Value), true);
-            }
-            RemComp<SleepingComponent>(uid);
-            return true;
-        }
-    }
-}
diff --git a/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs b/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs
index 186fc91c46..bc61c5d141 100644
--- a/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs
+++ b/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Bed.Sleep;
 using Content.Shared.Damage;
 using Content.Shared.Damage.ForceSay;
 using Content.Shared.FixedPoint;
diff --git a/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs b/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs
deleted file mode 100644
index aa5578a3a9..0000000000
--- a/Content.Shared/Bed/Sleep/SharedSleepingSystem.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using Content.Shared.Actions;
-using Content.Shared.Bed.Sleep;
-using Content.Shared.Damage.ForceSay;
-using Content.Shared.Eye.Blinding.Systems;
-using Content.Shared.Pointing;
-using Content.Shared.Speech;
-using Robust.Shared.Network;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Timing;
-
-namespace Content.Server.Bed.Sleep
-{
-    public abstract class SharedSleepingSystem : EntitySystem
-    {
-        [Dependency] private readonly IGameTiming _gameTiming = default!;
-        [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
-        [Dependency] private readonly BlindableSystem _blindableSystem = default!;
-
-        [ValidatePrototypeId<EntityPrototype>] private const string WakeActionId = "ActionWake";
-
-        public override void Initialize()
-        {
-            base.Initialize();
-            SubscribeLocalEvent<SleepingComponent, MapInitEvent>(OnMapInit);
-            SubscribeLocalEvent<SleepingComponent, ComponentShutdown>(OnShutdown);
-            SubscribeLocalEvent<SleepingComponent, SpeakAttemptEvent>(OnSpeakAttempt);
-            SubscribeLocalEvent<SleepingComponent, CanSeeAttemptEvent>(OnSeeAttempt);
-            SubscribeLocalEvent<SleepingComponent, PointAttemptEvent>(OnPointAttempt);
-        }
-
-
-        private void OnMapInit(EntityUid uid, SleepingComponent component, MapInitEvent args)
-        {
-            component.SleepingSince = _gameTiming.CurTime;
-
-            var ev = new SleepStateChangedEvent(true);
-            RaiseLocalEvent(uid, ev);
-            _blindableSystem.UpdateIsBlind(uid);
-            _actionsSystem.AddAction(uid, ref component.WakeAction, WakeActionId, uid);
-
-            // TODO remove hardcoded time.
-            _actionsSystem.SetCooldown(component.WakeAction, _gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(2f));
-        }
-
-        private void OnShutdown(EntityUid uid, SleepingComponent component, ComponentShutdown args)
-        {
-            _actionsSystem.RemoveAction(uid, component.WakeAction);
-            var ev = new SleepStateChangedEvent(false)
-            {
-                TimeSlept = _gameTiming.CurTime - component.SleepingSince
-            };
-            RaiseLocalEvent(uid, ev);
-            _blindableSystem.UpdateIsBlind(uid);
-        }
-
-        private void OnSpeakAttempt(EntityUid uid, SleepingComponent component, SpeakAttemptEvent args)
-        {
-            // TODO reduce duplication of this behavior with MobStateSystem somehow
-            if (HasComp<AllowNextCritSpeechComponent>(uid))
-            {
-                RemCompDeferred<AllowNextCritSpeechComponent>(uid);
-                return;
-            }
-
-            args.Cancel();
-        }
-
-        private void OnSeeAttempt(EntityUid uid, SleepingComponent component, CanSeeAttemptEvent args)
-        {
-            if (component.LifeStage <= ComponentLifeStage.Running)
-                args.Cancel();
-        }
-
-        private void OnPointAttempt(EntityUid uid, SleepingComponent component, PointAttemptEvent args)
-        {
-            args.Cancel();
-        }
-    }
-}
-
-
-public sealed partial class SleepActionEvent : InstantActionEvent {}
-
-public sealed partial class WakeActionEvent : InstantActionEvent {}
-
-/// <summary>
-/// Raised on an entity when they fall asleep or wake up.
-/// </summary>
-public sealed class SleepStateChangedEvent : EntityEventArgs
-{
-    public bool FellAsleep = false;
-
-    /// <summary>
-    ///     The amount of time this entity slept for. Null if <see cref="FellAsleep"/> is true.
-    /// </summary>
-    public TimeSpan? TimeSlept;
-
-    public SleepStateChangedEvent(bool fellAsleep)
-    {
-        FellAsleep = fellAsleep;
-    }
-}
diff --git a/Content.Shared/Bed/Sleep/SleepingComponent.cs b/Content.Shared/Bed/Sleep/SleepingComponent.cs
index e87aca2203..e43c71769a 100644
--- a/Content.Shared/Bed/Sleep/SleepingComponent.cs
+++ b/Content.Shared/Bed/Sleep/SleepingComponent.cs
@@ -1,37 +1,48 @@
 using Content.Shared.FixedPoint;
+using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
 
 namespace Content.Shared.Bed.Sleep;
 
 /// <summary>
 /// Added to entities when they go to sleep.
 /// </summary>
-[NetworkedComponent, RegisterComponent, AutoGenerateComponentPause(Dirty = true)]
+[NetworkedComponent, RegisterComponent]
+[AutoGenerateComponentState, AutoGenerateComponentPause(Dirty = true)]
 public sealed partial class SleepingComponent : Component
 {
     /// <summary>
     /// How much damage of any type it takes to wake this entity.
     /// </summary>
-    [DataField("wakeThreshold")]
+    [DataField]
     public FixedPoint2 WakeThreshold = FixedPoint2.New(2);
 
     /// <summary>
     ///     Cooldown time between users hand interaction.
     /// </summary>
-    [DataField("cooldown")]
-    [ViewVariables(VVAccess.ReadWrite)]
+    [DataField]
     public TimeSpan Cooldown = TimeSpan.FromSeconds(1f);
 
-    [DataField("cooldownEnd", customTypeSerializer:typeof(TimeOffsetSerializer))]
-    [AutoPausedField]
-    public TimeSpan CoolDownEnd;
-
-    [DataField("wakeAction")] public EntityUid? WakeAction;
+    [DataField]
+    [AutoNetworkedField, AutoPausedField]
+    public TimeSpan CooldownEnd;
 
     /// <summary>
     ///     The moment this entity went to sleep. Initialized on MapInit.
     /// </summary>
     [DataField]
     public TimeSpan SleepingSince;
+
+    [DataField]
+    [AutoNetworkedField]
+    public EntityUid? WakeAction;
+
+    /// <summary>
+    /// Sound to play when another player attempts to wake this entity.
+    /// </summary>
+    [DataField]
+    public SoundSpecifier WakeAttemptSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg")
+    {
+        Params = AudioParams.Default.WithVariation(0.05f)
+    };
 }
diff --git a/Content.Shared/Bed/Sleep/SleepingSystem.cs b/Content.Shared/Bed/Sleep/SleepingSystem.cs
new file mode 100644
index 0000000000..aac3e7bb18
--- /dev/null
+++ b/Content.Shared/Bed/Sleep/SleepingSystem.cs
@@ -0,0 +1,314 @@
+using Content.Shared.Actions;
+using Content.Shared.Damage;
+using Content.Shared.Damage.ForceSay;
+using Content.Shared.Examine;
+using Content.Shared.Eye.Blinding.Systems;
+using Content.Shared.IdentityManagement;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Mobs;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Pointing;
+using Content.Shared.Popups;
+using Content.Shared.Slippery;
+using Content.Shared.Sound;
+using Content.Shared.Sound.Components;
+using Content.Shared.Speech;
+using Content.Shared.StatusEffect;
+using Content.Shared.Stunnable;
+using Content.Shared.Verbs;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Bed.Sleep;
+
+public sealed partial class SleepingSystem : EntitySystem
+{
+    [Dependency] private readonly IGameTiming _gameTiming = default!;
+    [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
+    [Dependency] private readonly BlindableSystem _blindableSystem = default!;
+    [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly SharedEmitSoundSystem _emitSound = default!;
+    [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
+
+    public static readonly ProtoId<EntityPrototype> SleepActionId = "ActionSleep";
+    public static readonly ProtoId<EntityPrototype> WakeActionId = "ActionWake";
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<ActionsContainerComponent, SleepActionEvent>(OnBedSleepAction);
+
+        SubscribeLocalEvent<MobStateComponent, SleepStateChangedEvent>(OnSleepStateChanged);
+        SubscribeLocalEvent<MobStateComponent, WakeActionEvent>(OnWakeAction);
+        SubscribeLocalEvent<MobStateComponent, SleepActionEvent>(OnSleepAction);
+
+        SubscribeLocalEvent<SleepingComponent, DamageChangedEvent>(OnDamageChanged);
+        SubscribeLocalEvent<SleepingComponent, MobStateChangedEvent>(OnMobStateChanged);
+        SubscribeLocalEvent<SleepingComponent, MapInitEvent>(OnMapInit);
+        SubscribeLocalEvent<SleepingComponent, SpeakAttemptEvent>(OnSpeakAttempt);
+        SubscribeLocalEvent<SleepingComponent, CanSeeAttemptEvent>(OnSeeAttempt);
+        SubscribeLocalEvent<SleepingComponent, PointAttemptEvent>(OnPointAttempt);
+        SubscribeLocalEvent<SleepingComponent, SlipAttemptEvent>(OnSlip);
+        SubscribeLocalEvent<SleepingComponent, ConsciousAttemptEvent>(OnConsciousAttempt);
+        SubscribeLocalEvent<SleepingComponent, ExaminedEvent>(OnExamined);
+        SubscribeLocalEvent<SleepingComponent, GetVerbsEvent<AlternativeVerb>>(AddWakeVerb);
+        SubscribeLocalEvent<SleepingComponent, InteractHandEvent>(OnInteractHand);
+
+        SubscribeLocalEvent<ForcedSleepingComponent, ComponentInit>(OnInit);
+    }
+
+    private void OnBedSleepAction(Entity<ActionsContainerComponent> ent, ref SleepActionEvent args)
+    {
+        TrySleeping(args.Performer);
+    }
+
+    private void OnWakeAction(Entity<MobStateComponent> ent, ref WakeActionEvent args)
+    {
+        if (TryWakeWithCooldown(ent.Owner))
+            args.Handled = true;
+    }
+
+    private void OnSleepAction(Entity<MobStateComponent> ent, ref SleepActionEvent args)
+    {
+        TrySleeping((ent, ent.Comp));
+    }
+
+    /// <summary>
+    /// when sleeping component is added or removed, we do some stuff with other components.
+    /// </summary>
+    private void OnSleepStateChanged(Entity<MobStateComponent> ent, ref SleepStateChangedEvent args)
+    {
+        if (args.FellAsleep)
+        {
+            // Expiring status effects would remove the components needed for sleeping
+            _statusEffectsSystem.TryRemoveStatusEffect(ent.Owner, "Stun");
+            _statusEffectsSystem.TryRemoveStatusEffect(ent.Owner, "KnockedDown");
+
+            EnsureComp<StunnedComponent>(ent);
+            EnsureComp<KnockedDownComponent>(ent);
+
+            if (TryComp<SleepEmitSoundComponent>(ent, out var sleepSound))
+            {
+                var emitSound = EnsureComp<SpamEmitSoundComponent>(ent);
+                if (HasComp<SnoringComponent>(ent))
+                {
+                    emitSound.Sound = sleepSound.Snore;
+                }
+                emitSound.MinInterval = sleepSound.Interval;
+                emitSound.MaxInterval = sleepSound.MaxInterval;
+                emitSound.PopUp = sleepSound.PopUp;
+                Dirty(ent.Owner, emitSound);
+            }
+
+            return;
+        }
+
+        RemComp<StunnedComponent>(ent);
+        RemComp<KnockedDownComponent>(ent);
+        RemComp<SpamEmitSoundComponent>(ent);
+    }
+
+    private void OnMapInit(Entity<SleepingComponent> ent, ref MapInitEvent args)
+    {
+        var ev = new SleepStateChangedEvent(true);
+        RaiseLocalEvent(ent, ref ev);
+        _blindableSystem.UpdateIsBlind(ent.Owner);
+        _actionsSystem.AddAction(ent, ref ent.Comp.WakeAction, WakeActionId, ent);
+
+        // TODO remove hardcoded time.
+        _actionsSystem.SetCooldown(ent.Comp.WakeAction, _gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(2f));
+    }
+
+    private void OnSpeakAttempt(Entity<SleepingComponent> ent, ref SpeakAttemptEvent args)
+    {
+        // TODO reduce duplication of this behavior with MobStateSystem somehow
+        if (HasComp<AllowNextCritSpeechComponent>(ent))
+        {
+            RemCompDeferred<AllowNextCritSpeechComponent>(ent);
+            return;
+        }
+
+        args.Cancel();
+    }
+
+    private void OnSeeAttempt(Entity<SleepingComponent> ent, ref CanSeeAttemptEvent args)
+    {
+        if (ent.Comp.LifeStage <= ComponentLifeStage.Running)
+            args.Cancel();
+    }
+
+    private void OnPointAttempt(Entity<SleepingComponent> ent, ref PointAttemptEvent args)
+    {
+        args.Cancel();
+    }
+
+    private void OnSlip(Entity<SleepingComponent> ent, ref SlipAttemptEvent args)
+    {
+        args.Cancel();
+    }
+
+    private void OnConsciousAttempt(Entity<SleepingComponent> ent, ref ConsciousAttemptEvent args)
+    {
+        args.Cancel();
+    }
+
+    private void OnExamined(Entity<SleepingComponent> ent, ref ExaminedEvent args)
+    {
+        if (args.IsInDetailsRange)
+        {
+            args.PushMarkup(Loc.GetString("sleep-examined", ("target", Identity.Entity(ent, EntityManager))));
+        }
+    }
+
+    private void AddWakeVerb(Entity<SleepingComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
+    {
+        if (!args.CanInteract || !args.CanAccess)
+            return;
+
+        var target = args.Target;
+        var user = args.User;
+        AlternativeVerb verb = new()
+        {
+            Act = () =>
+            {
+                TryWakeWithCooldown((ent, ent.Comp), user: user);
+            },
+            Text = Loc.GetString("action-name-wake"),
+            Priority = 2
+        };
+
+        args.Verbs.Add(verb);
+    }
+
+    /// <summary>
+    /// When you click on a sleeping person with an empty hand, try to wake them.
+    /// </summary>
+    private void OnInteractHand(Entity<SleepingComponent> ent, ref InteractHandEvent args)
+    {
+        args.Handled = true;
+
+        TryWakeWithCooldown((ent, ent.Comp), args.User);
+    }
+
+    /// <summary>
+    /// Wake up on taking an instance of damage at least the value of WakeThreshold.
+    /// </summary>
+    private void OnDamageChanged(Entity<SleepingComponent> ent, ref DamageChangedEvent args)
+    {
+        if (!args.DamageIncreased || args.DamageDelta == null)
+            return;
+
+        if (args.DamageDelta.GetTotal() >= ent.Comp.WakeThreshold)
+            TryWaking((ent, ent.Comp));
+    }
+
+    /// <summary>
+    /// In crit, we wake up if we are not being forced to sleep.
+    /// And, you can't sleep when dead...
+    /// </summary>
+    private void OnMobStateChanged(Entity<SleepingComponent> ent, ref MobStateChangedEvent args)
+    {
+        if (args.NewMobState == MobState.Dead)
+        {
+            RemComp<SpamEmitSoundComponent>(ent);
+            RemComp<SleepingComponent>(ent);
+            return;
+        }
+        if (TryComp<SpamEmitSoundComponent>(ent, out var spam))
+            _emitSound.SetEnabled((ent, spam), args.NewMobState == MobState.Alive);
+    }
+
+    private void OnInit(Entity<ForcedSleepingComponent> ent, ref ComponentInit args)
+    {
+        TrySleeping(ent.Owner);
+    }
+
+    private void Wake(Entity<SleepingComponent> ent)
+    {
+        RemComp<SleepingComponent>(ent);
+        _actionsSystem.RemoveAction(ent, ent.Comp.WakeAction);
+
+        var ev = new SleepStateChangedEvent(false);
+        RaiseLocalEvent(ent, ref ev);
+
+        _blindableSystem.UpdateIsBlind(ent.Owner);
+    }
+
+    /// <summary>
+    /// Try sleeping. Only mobs can sleep.
+    /// </summary>
+    public bool TrySleeping(Entity<MobStateComponent?> ent)
+    {
+        if (!Resolve(ent, ref ent.Comp, logMissing: false))
+            return false;
+
+        var tryingToSleepEvent = new TryingToSleepEvent(ent);
+        RaiseLocalEvent(ent, ref tryingToSleepEvent);
+        if (tryingToSleepEvent.Cancelled)
+            return false;
+
+        EnsureComp<SleepingComponent>(ent);
+        return true;
+    }
+
+    /// <summary>
+    /// Tries to wake up <paramref name="ent"/>, with a cooldown between attempts to prevent spam.
+    /// </summary>
+    public bool TryWakeWithCooldown(Entity<SleepingComponent?> ent, EntityUid? user = null)
+    {
+        if (!Resolve(ent, ref ent.Comp, false))
+            return false;
+
+        var curTime = _gameTiming.CurTime;
+
+        if (curTime < ent.Comp.CooldownEnd)
+            return false;
+
+        ent.Comp.CooldownEnd = curTime + ent.Comp.Cooldown;
+        Dirty(ent, ent.Comp);
+        return TryWaking(ent, user: user);
+    }
+
+    /// <summary>
+    /// Try to wake up <paramref name="ent"/>.
+    /// </summary>
+    public bool TryWaking(Entity<SleepingComponent?> ent, bool force = false, EntityUid? user = null)
+    {
+        if (!Resolve(ent, ref ent.Comp, false))
+            return false;
+
+        if (!force && HasComp<ForcedSleepingComponent>(ent))
+        {
+            if (user != null)
+            {
+                _audio.PlayPredicted(ent.Comp.WakeAttemptSound, ent, user);
+                _popupSystem.PopupClient(Loc.GetString("wake-other-failure", ("target", Identity.Entity(ent, EntityManager))), ent, user, PopupType.SmallCaution);
+            }
+            return false;
+        }
+
+        if (user != null)
+        {
+            _audio.PlayPredicted(ent.Comp.WakeAttemptSound, ent, user);
+            _popupSystem.PopupClient(Loc.GetString("wake-other-success", ("target", Identity.Entity(ent, EntityManager))), ent, user);
+        }
+
+        Wake((ent, ent.Comp));
+        return true;
+    }
+}
+
+
+public sealed partial class SleepActionEvent : InstantActionEvent;
+
+public sealed partial class WakeActionEvent : InstantActionEvent;
+
+/// <summary>
+/// Raised on an entity when they fall asleep or wake up.
+/// </summary>
+[ByRefEvent]
+public record struct SleepStateChangedEvent(bool FellAsleep);
diff --git a/Content.Server/Bed/Components/SnoringComponent.cs b/Content.Shared/Bed/Sleep/SnoringComponent.cs
similarity index 54%
rename from Content.Server/Bed/Components/SnoringComponent.cs
rename to Content.Shared/Bed/Sleep/SnoringComponent.cs
index 09f80327ba..2fe92951f0 100644
--- a/Content.Server/Bed/Components/SnoringComponent.cs
+++ b/Content.Shared/Bed/Sleep/SnoringComponent.cs
@@ -1,9 +1,11 @@
-namespace Content.Server.Bed.Sleep;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Bed.Sleep;
 
 /// <summary>
 /// This is used for the snoring trait.
 /// </summary>
-[RegisterComponent]
+[RegisterComponent, NetworkedComponent]
 public sealed partial class SnoringComponent : Component
 {
 

From ede16f05928b602f70beb349b824ecfbf268269f Mon Sep 17 00:00:00 2001
From: sleepyyapril <flyingkarii@gmail.com>
Date: Sat, 4 Jan 2025 14:02:06 -0400
Subject: [PATCH 06/38] Potentially re-add EE changes?

---
 Content.Shared/Bed/Sleep/SleepingSystem.cs | 31 +++++++++++++++++-----
 1 file changed, 25 insertions(+), 6 deletions(-)

diff --git a/Content.Shared/Bed/Sleep/SleepingSystem.cs b/Content.Shared/Bed/Sleep/SleepingSystem.cs
index aac3e7bb18..8e6f1193ac 100644
--- a/Content.Shared/Bed/Sleep/SleepingSystem.cs
+++ b/Content.Shared/Bed/Sleep/SleepingSystem.cs
@@ -33,8 +33,8 @@ public sealed partial class SleepingSystem : EntitySystem
     [Dependency] private readonly SharedEmitSoundSystem _emitSound = default!;
     [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
 
-    public static readonly ProtoId<EntityPrototype> SleepActionId = "ActionSleep";
-    public static readonly ProtoId<EntityPrototype> WakeActionId = "ActionWake";
+    public static readonly EntProtoId SleepActionId = "ActionSleep";
+    public static readonly EntProtoId WakeActionId = "ActionWake";
 
     public override void Initialize()
     {
@@ -114,6 +114,8 @@ private void OnSleepStateChanged(Entity<MobStateComponent> ent, ref SleepStateCh
 
     private void OnMapInit(Entity<SleepingComponent> ent, ref MapInitEvent args)
     {
+        ent.Comp.SleepingSince = _gameTiming.CurTime;
+
         var ev = new SleepStateChangedEvent(true);
         RaiseLocalEvent(ent, ref ev);
         _blindableSystem.UpdateIsBlind(ent.Owner);
@@ -153,7 +155,7 @@ private void OnSlip(Entity<SleepingComponent> ent, ref SlipAttemptEvent args)
 
     private void OnConsciousAttempt(Entity<SleepingComponent> ent, ref ConsciousAttemptEvent args)
     {
-        args.Cancel();
+        args.Cancelled = true;
     }
 
     private void OnExamined(Entity<SleepingComponent> ent, ref ExaminedEvent args)
@@ -202,7 +204,8 @@ private void OnDamageChanged(Entity<SleepingComponent> ent, ref DamageChangedEve
         if (!args.DamageIncreased || args.DamageDelta == null)
             return;
 
-        if (args.DamageDelta.GetTotal() >= ent.Comp.WakeThreshold)
+        if (args.DamageDelta.GetTotal() >= ent.Comp.WakeThreshold
+            && !HasComp<ForcedSleepingComponent>(ent))
             TryWaking((ent, ent.Comp));
     }
 
@@ -232,7 +235,10 @@ private void Wake(Entity<SleepingComponent> ent)
         RemComp<SleepingComponent>(ent);
         _actionsSystem.RemoveAction(ent, ent.Comp.WakeAction);
 
-        var ev = new SleepStateChangedEvent(false);
+        var ev = new SleepStateChangedEvent(false)
+        {
+            TimeSlept = _gameTiming.CurTime - ent.Comp.SleepingSince
+        };
         RaiseLocalEvent(ent, ref ev);
 
         _blindableSystem.UpdateIsBlind(ent.Owner);
@@ -311,4 +317,17 @@ public sealed partial class WakeActionEvent : InstantActionEvent;
 /// Raised on an entity when they fall asleep or wake up.
 /// </summary>
 [ByRefEvent]
-public record struct SleepStateChangedEvent(bool FellAsleep);
+public record struct SleepStateChangedEvent
+{
+    public bool FellAsleep = false;
+
+    /// <summary>
+    ///     The amount of time this entity slept for. Null if <see cref="FellAsleep"/> is true.
+    /// </summary>
+    public TimeSpan? TimeSlept;
+
+    public SleepStateChangedEvent(bool fellAsleep)
+    {
+        FellAsleep = fellAsleep;
+    }
+}

From 661bdbaf1c668337376d68ad29bbace978458ae1 Mon Sep 17 00:00:00 2001
From: sleepyyapril <flyingkarii@gmail.com>
Date: Sat, 4 Jan 2025 14:18:12 -0400
Subject: [PATCH 07/38] Fix build errors

---
 Content.Server/Carrying/CarryingSystem.cs     |  4 +--
 Content.Server/Flight/FlightSystem.cs         |  1 +
 .../Actions/ToggleSleepingAction.cs           |  1 -
 .../Shadowkin/ShowEtherealSystem.cs           |  4 +--
 .../Systems/SiliconChargeDeathSystem.cs       |  3 +--
 .../Station/Systems/StationSpawningSystem.cs  | 25 +------------------
 .../Traits/Assorted/SingerSystem.cs           |  1 +
 .../_Shitmed/Autodoc/Systems/AutodocSystem.cs |  5 ++--
 .../Climbing/Systems/ClimbSystem.cs           |  1 +
 .../Interaction/NoNormalInteractionSystem.cs  |  2 +-
 .../Item/PseudoItem/SharedPseudoItemSystem.cs |  2 +-
 .../Shadowkin/SharedEtherealSystem.cs         |  2 +-
 .../Prototypes/Roles/Jobs/Science/borg.yml    |  6 ++---
 13 files changed, 18 insertions(+), 39 deletions(-)

diff --git a/Content.Server/Carrying/CarryingSystem.cs b/Content.Server/Carrying/CarryingSystem.cs
index 72cfeff91d..224e38bcbd 100644
--- a/Content.Server/Carrying/CarryingSystem.cs
+++ b/Content.Server/Carrying/CarryingSystem.cs
@@ -168,7 +168,7 @@ private void OnInteractionAttempt(EntityUid uid, BeingCarriedComponent component
             var targetParent = Transform(args.Target.Value).ParentUid;
 
             if (args.Target.Value != component.Carrier && targetParent != component.Carrier && targetParent != uid)
-                args.Cancel();
+                args.Cancelled = true;
         }
 
         /// <summary>
@@ -202,7 +202,7 @@ private void OnStandAttempt(EntityUid uid, BeingCarriedComponent component, Stan
         private void OnInteractedWith(EntityUid uid, BeingCarriedComponent component, GettingInteractedWithAttemptEvent args)
         {
             if (args.Uid != component.Carrier)
-                args.Cancel();
+                args.Cancelled = true;
         }
 
         private void OnPullAttempt(EntityUid uid, BeingCarriedComponent component, PullAttemptEvent args)
diff --git a/Content.Server/Flight/FlightSystem.cs b/Content.Server/Flight/FlightSystem.cs
index 4493967fe9..5e3ef354f2 100644
--- a/Content.Server/Flight/FlightSystem.cs
+++ b/Content.Server/Flight/FlightSystem.cs
@@ -1,4 +1,5 @@
 
+using Content.Shared.Bed.Sleep;
 using Content.Shared.Cuffs.Components;
 using Content.Shared.Damage.Components;
 using Content.Shared.DoAfter;
diff --git a/Content.Server/InteractionVerbs/Actions/ToggleSleepingAction.cs b/Content.Server/InteractionVerbs/Actions/ToggleSleepingAction.cs
index 588853a8d4..97fd86fd91 100644
--- a/Content.Server/InteractionVerbs/Actions/ToggleSleepingAction.cs
+++ b/Content.Server/InteractionVerbs/Actions/ToggleSleepingAction.cs
@@ -1,4 +1,3 @@
-using Content.Server.Bed.Sleep;
 using Content.Shared.Bed.Sleep;
 using Content.Shared.InteractionVerbs;
 using Content.Shared.Mobs.Components;
diff --git a/Content.Server/Shadowkin/ShowEtherealSystem.cs b/Content.Server/Shadowkin/ShowEtherealSystem.cs
index 151c379afb..e908bd9ce7 100644
--- a/Content.Server/Shadowkin/ShowEtherealSystem.cs
+++ b/Content.Server/Shadowkin/ShowEtherealSystem.cs
@@ -70,7 +70,7 @@ private void OnInteractionAttempt(EntityUid uid, ShowEtherealComponent component
             || !HasComp<EtherealComponent>(args.Target))
             return;
 
-        args.Cancel();
+        args.Cancelled = true;
         if (_gameTiming.InPrediction)
             return;
 
@@ -85,4 +85,4 @@ private void OnAttackAttempt(EntityUid uid, ShowEtherealComponent component, Att
 
         args.Cancel();
     }
-}
\ No newline at end of file
+}
diff --git a/Content.Server/Silicon/Charge/Systems/SiliconChargeDeathSystem.cs b/Content.Server/Silicon/Charge/Systems/SiliconChargeDeathSystem.cs
index d4d1db5ed9..41ee269788 100644
--- a/Content.Server/Silicon/Charge/Systems/SiliconChargeDeathSystem.cs
+++ b/Content.Server/Silicon/Charge/Systems/SiliconChargeDeathSystem.cs
@@ -1,6 +1,5 @@
 using Content.Server.Power.Components;
 using Content.Shared.Silicon.Systems;
-using Content.Server.Bed.Sleep;
 using Content.Shared.Bed.Sleep;
 using Content.Server.Silicon.Charge;
 using Content.Server.Humanoid;
@@ -63,7 +62,7 @@ private void SiliconDead(EntityUid uid, SiliconDownOnDeadComponent siliconDeadCo
     private void SiliconUnDead(EntityUid uid, SiliconDownOnDeadComponent siliconDeadComp, BatteryComponent? batteryComp, EntityUid batteryUid)
     {
         RemComp<ForcedSleepingComponent>(uid);
-        _sleep.TryWaking(uid, null, true);
+        _sleep.TryWaking(uid, true);
 
         siliconDeadComp.Dead = false;
 
diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs
index 0662c54bee..0bbfecb49d 100644
--- a/Content.Server/Station/Systems/StationSpawningSystem.cs
+++ b/Content.Server/Station/Systems/StationSpawningSystem.cs
@@ -131,7 +131,7 @@ public override void Initialize()
     /// <param name="station">The station this player is being spawned on.</param>
     /// <param name="entity">The entity to use, if one already exists.</param>
     /// <returns>The spawned entity</returns>
-    public EntityUid SpawnPlayerMob(
+     public EntityUid SpawnPlayerMob(
         EntityCoordinates coordinates,
         JobComponent? job,
         HumanoidCharacterProfile? profile,
@@ -139,22 +139,6 @@ public EntityUid SpawnPlayerMob(
         EntityUid? entity = null)
     {
         _prototypeManager.TryIndex(job?.Prototype ?? string.Empty, out var prototype);
-        RoleLoadout? loadout = null;
-
-        // Need to get the loadout up-front to handle names if we use an entity spawn override.
-        var jobLoadout = LoadoutSystem.GetJobPrototype(prototype?.ID);
-
-        if (_prototypeManager.TryIndex(jobLoadout, out RoleLoadoutPrototype? roleProto))
-        {
-            profile?.Loadouts.TryGetValue(jobLoadout, out loadout);
-
-            // Set to default if not present
-            if (loadout == null)
-            {
-                loadout = new RoleLoadout(jobLoadout);
-                loadout.SetDefault(profile, _actors.GetSession(entity), _prototypeManager);
-            }
-        }
 
         // If we're not spawning a humanoid, we're gonna exit early without doing all the humanoid stuff.
         if (prototype?.JobEntity != null)
@@ -162,13 +146,6 @@ public EntityUid SpawnPlayerMob(
             DebugTools.Assert(entity is null);
             var jobEntity = EntityManager.SpawnEntity(prototype.JobEntity, coordinates);
             MakeSentientCommand.MakeSentient(jobEntity, EntityManager);
-
-            // Make sure custom names get handled, what is gameticker control flow whoopy.
-            if (loadout != null)
-            {
-                EquipRoleName(jobEntity, loadout, roleProto!);
-            }
-
             DoJobSpecials(job, jobEntity);
             _identity.QueueIdentityUpdate(jobEntity);
             return jobEntity;
diff --git a/Content.Server/Traits/Assorted/SingerSystem.cs b/Content.Server/Traits/Assorted/SingerSystem.cs
index 78a4101a65..95087c0f1e 100644
--- a/Content.Server/Traits/Assorted/SingerSystem.cs
+++ b/Content.Server/Traits/Assorted/SingerSystem.cs
@@ -2,6 +2,7 @@
 using Content.Server.Speech.Components;
 using Content.Server.UserInterface;
 using Content.Shared.ActionBlocker;
+using Content.Shared.Bed.Sleep;
 using Content.Shared.Damage;
 using Content.Shared.Damage.ForceSay;
 using Content.Shared.FixedPoint;
diff --git a/Content.Server/_Shitmed/Autodoc/Systems/AutodocSystem.cs b/Content.Server/_Shitmed/Autodoc/Systems/AutodocSystem.cs
index d1af790eaa..7002734fd3 100644
--- a/Content.Server/_Shitmed/Autodoc/Systems/AutodocSystem.cs
+++ b/Content.Server/_Shitmed/Autodoc/Systems/AutodocSystem.cs
@@ -6,7 +6,8 @@
 using Content.Server.Power.EntitySystems;
 using Content.Shared._Shitmed.Autodoc.Components;
 using Content.Shared._Shitmed.Autodoc.Systems;
-using Content.Server.Bed.Sleep;
+using Content.Shared.Bed.Sleep;
+
 
 namespace Content.Server._Shitmed.Autodoc.Systems;
 
@@ -15,7 +16,7 @@ public sealed class AutodocSystem : SharedAutodocSystem
     [Dependency] private readonly InternalsSystem _internals = default!;
     [Dependency] private readonly ChatSystem _chat = default!;
     [Dependency] private readonly PowerReceiverSystem _power = default!;
-    [Dependency] private readonly SleepingSystem _sleepingSystem = default!; // Sleeping isnt shared yet.
+    [Dependency] private readonly SleepingSystem _sleepingSystem = default!;
 
     public override void Update(float frameTime)
     {
diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs
index 42fa89b367..fc5a43cf8a 100644
--- a/Content.Shared/Climbing/Systems/ClimbSystem.cs
+++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs
@@ -47,6 +47,7 @@ public sealed partial class ClimbSystem : VirtualController
 
     private EntityQuery<FixturesComponent> _fixturesQuery;
     private EntityQuery<TransformComponent> _xformQuery;
+    private EntityQuery<ClimbableComponent> _climbableQuery;
 
     public override void Initialize()
     {
diff --git a/Content.Shared/Nyanotrasen/Interaction/NoNormalInteractionSystem.cs b/Content.Shared/Nyanotrasen/Interaction/NoNormalInteractionSystem.cs
index 0f66dff309..9b7a6954de 100644
--- a/Content.Shared/Nyanotrasen/Interaction/NoNormalInteractionSystem.cs
+++ b/Content.Shared/Nyanotrasen/Interaction/NoNormalInteractionSystem.cs
@@ -12,7 +12,7 @@ public override void Initialize()
 
         private void OnInteractionAttempt(EntityUid uid, NoNormalInteractionComponent component, InteractionAttemptEvent args)
         {
-            args.Cancel();
+            args.Cancelled = true;
         }
     }
 }
diff --git a/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs b/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs
index 7dc8578117..448311471f 100644
--- a/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs
+++ b/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs
@@ -143,7 +143,7 @@ private void OnInsertAttempt(EntityUid uid, PseudoItemComponent component,
     private void OnInteractAttempt(EntityUid uid, PseudoItemComponent component, InteractionAttemptEvent args)
     {
         if (args.Uid == args.Target && component.Active)
-            args.Cancel();
+            args.Cancelled = true;
     }
 
     private void OnDoAfter(EntityUid uid, PseudoItemComponent component, DoAfterEvent args)
diff --git a/Content.Shared/Shadowkin/SharedEtherealSystem.cs b/Content.Shared/Shadowkin/SharedEtherealSystem.cs
index 5ab5e3eeea..2365ade818 100644
--- a/Content.Shared/Shadowkin/SharedEtherealSystem.cs
+++ b/Content.Shared/Shadowkin/SharedEtherealSystem.cs
@@ -165,7 +165,7 @@ private void OnInteractionAttempt(EntityUid uid, EtherealComponent component, In
             || HasComp<EtherealComponent>(args.Target))
             return;
 
-        args.Cancel();
+        args.Cancelled = true;
         if (_gameTiming.InPrediction)
             return;
 
diff --git a/Resources/Prototypes/Roles/Jobs/Science/borg.yml b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
index b9b4cb3c16..67f70b2d25 100644
--- a/Resources/Prototypes/Roles/Jobs/Science/borg.yml
+++ b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
@@ -5,9 +5,9 @@
   description: job-description-station-ai
   playTimeTracker: JobStationAi
   requirements:
-  - !type:RoleTimeRequirement
-    role: JobBorg
-    time: 18000  # 5 hrs
+  - !type:CharacterPlaytimeRequirement
+    tracker: JobBorg
+    min: 18000  # 5 hrs
   canBeAntag: false
   icon: JobIconStationAi
   supervisors: job-supervisors-rd

From 006acf3a376c5fdb163297b758ef86fd7d7638ef Mon Sep 17 00:00:00 2001
From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Sun, 25 Aug 2024 22:06:06 +1000
Subject: [PATCH 08/38] Add ContainerComp (#31311)

Applies EntProtoId changes upon insertion / removal from container. Can also be useful for borgs / mechs / vehicles in future but atm I just used it for AI.
---
 .../Containers/ContainerCompComponent.cs      | 17 +++++++
 .../Containers/ContainerCompSystem.cs         | 44 +++++++++++++++++++
 2 files changed, 61 insertions(+)
 create mode 100644 Content.Shared/Containers/ContainerCompComponent.cs
 create mode 100644 Content.Shared/Containers/ContainerCompSystem.cs

diff --git a/Content.Shared/Containers/ContainerCompComponent.cs b/Content.Shared/Containers/ContainerCompComponent.cs
new file mode 100644
index 0000000000..b1415e0d8b
--- /dev/null
+++ b/Content.Shared/Containers/ContainerCompComponent.cs
@@ -0,0 +1,17 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Containers;
+
+/// <summary>
+/// Applies container changes whenever an entity is inserted into the specified container on this entity.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ContainerCompComponent : Component
+{
+    [DataField(required: true)]
+    public EntProtoId Proto;
+
+    [DataField(required: true)]
+    public string Container = string.Empty;
+}
diff --git a/Content.Shared/Containers/ContainerCompSystem.cs b/Content.Shared/Containers/ContainerCompSystem.cs
new file mode 100644
index 0000000000..1e1983a331
--- /dev/null
+++ b/Content.Shared/Containers/ContainerCompSystem.cs
@@ -0,0 +1,44 @@
+using Robust.Shared.Containers;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Containers;
+
+/// <summary>
+/// Applies / removes an entity prototype from a child entity when it's inserted into a container.
+/// </summary>
+public sealed class ContainerCompSystem : EntitySystem
+{
+    [Dependency] private readonly IPrototypeManager _proto = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<ContainerCompComponent, EntInsertedIntoContainerMessage>(OnConInsert);
+        SubscribeLocalEvent<ContainerCompComponent, EntRemovedFromContainerMessage>(OnConRemove);
+    }
+
+    private void OnConRemove(Entity<ContainerCompComponent> ent, ref EntRemovedFromContainerMessage args)
+    {
+        if (args.Container.ID != ent.Comp.Container)
+            return;
+
+        if (_proto.TryIndex(ent.Comp.Container, out var entProto))
+        {
+            foreach (var entry in entProto.Components.Values)
+            {
+                RemComp(args.Entity, entry.Component);
+            }
+        }
+    }
+
+    private void OnConInsert(Entity<ContainerCompComponent> ent, ref EntInsertedIntoContainerMessage args)
+    {
+        if (args.Container.ID != ent.Comp.Container)
+            return;
+
+        if (_proto.TryIndex(ent.Comp.Proto, out var entProto))
+        {
+            EntityManager.AddComponents(args.Entity, entProto.Components);
+        }
+    }
+}

From b7e34aa267dae1069691b77e72172b331857e595 Mon Sep 17 00:00:00 2001
From: MilenVolf <63782763+MilenVolf@users.noreply.github.com>
Date: Fri, 6 Dec 2024 18:38:00 +0300
Subject: [PATCH 09/38] Localize ai dataset names (#33608)

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
---
 .../Station/SharedStationSpawningSystem.cs    |  18 +++
 Resources/Locale/en-US/datasets/names/ai.ftl  | 139 ++++++++++++++++++
 Resources/Prototypes/Datasets/Names/ai.yml    |  94 +-----------
 3 files changed, 161 insertions(+), 90 deletions(-)
 create mode 100644 Resources/Locale/en-US/datasets/names/ai.ftl

diff --git a/Content.Shared/Station/SharedStationSpawningSystem.cs b/Content.Shared/Station/SharedStationSpawningSystem.cs
index dedfd7bd00..232f32acc2 100644
--- a/Content.Shared/Station/SharedStationSpawningSystem.cs
+++ b/Content.Shared/Station/SharedStationSpawningSystem.cs
@@ -36,6 +36,24 @@ public override void Initialize()
         _xformQuery = GetEntityQuery<TransformComponent>();
     }
 
+    /// <summary>
+    /// Applies the role's name as applicable to the entity.
+    /// </summary>
+    public void EquipRoleName(EntityUid entity, RoleLoadout loadout, RoleLoadoutPrototype roleProto)
+    {
+        string? name = null;
+
+        if (string.IsNullOrEmpty(name) && PrototypeManager.TryIndex(roleProto.NameDataset, out var nameData))
+        {
+            name = Loc.GetString(_random.Pick(nameData.Values));
+        }
+
+        if (!string.IsNullOrEmpty(name))
+        {
+            _metadata.SetEntityName(entity, name);
+        }
+    }
+
     /// <summary>
     /// <see cref="EquipStartingGear(Robust.Shared.GameObjects.EntityUid,System.Nullable{Robust.Shared.Prototypes.ProtoId{Content.Shared.Roles.StartingGearPrototype}},bool)"/>
     /// </summary>
diff --git a/Resources/Locale/en-US/datasets/names/ai.ftl b/Resources/Locale/en-US/datasets/names/ai.ftl
new file mode 100644
index 0000000000..ac6ce0d83e
--- /dev/null
+++ b/Resources/Locale/en-US/datasets/names/ai.ftl
@@ -0,0 +1,139 @@
+names-ai-dataset-1 = 16-20
+names-ai-dataset-2 = 512k
+
+# Ought to be enough for anybody
+names-ai-dataset-3 = 640k
+
+names-ai-dataset-4 = "790"
+names-ai-dataset-5 = Adaptive Manipulator
+
+# Named after the famous soundcard
+names-ai-dataset-6 = Adlib
+
+names-ai-dataset-7 = ALICE
+names-ai-dataset-8 = Allied Mastercomputer
+names-ai-dataset-9 = Alpha 2
+names-ai-dataset-10 = Alpha 3
+names-ai-dataset-11 = Alpha 4
+names-ai-dataset-12 = Alpha 5
+names-ai-dataset-13 = Alpha 6
+names-ai-dataset-14 = Alpha 7
+names-ai-dataset-15 = Alpha 8
+names-ai-dataset-16 = Alpha 9
+names-ai-dataset-17 = AmigoBot
+names-ai-dataset-18 = Android
+names-ai-dataset-19 = Aniel
+names-ai-dataset-20 = AOL
+names-ai-dataset-21 = Asimov
+
+# The most influential modem ever, created by the bell system. It still lives on today in certain applications
+names-ai-dataset-22 = Bell 301
+
+names-ai-dataset-23 = Bishop
+names-ai-dataset-24 = Blitz
+names-ai-dataset-25 = Box
+names-ai-dataset-26 = Calculator
+names-ai-dataset-27 = Cassandra
+names-ai-dataset-28 = Cell
+names-ai-dataset-29 = Chii
+names-ai-dataset-30 = Chip
+names-ai-dataset-31 = C.R.A.I.G.
+
+# Commercial supercomputer from the 70s
+names-ai-dataset-32 = Cray-2
+
+# If we're going to have AOL we may as well have some of their major competitors
+names-ai-dataset-33 = CompuServe
+
+names-ai-dataset-34 = Computer
+names-ai-dataset-35 = Cutie
+names-ai-dataset-36 = Daedalus
+names-ai-dataset-37 = DecTalk
+names-ai-dataset-38 = Dee Model
+names-ai-dataset-39 = Dial Up
+names-ai-dataset-40 = Dorfl
+names-ai-dataset-41 = Duey
+names-ai-dataset-42 = Emma-2
+
+# Famous early computer
+names-ai-dataset-43 = ENIAC
+
+names-ai-dataset-44 = Erasmus
+names-ai-dataset-45 = Everything
+names-ai-dataset-46 = Ez-27
+names-ai-dataset-47 = FRIEND COMPUTER
+names-ai-dataset-48 = Faith
+names-ai-dataset-49 = Fi
+names-ai-dataset-50 = Frost
+names-ai-dataset-51 = George
+names-ai-dataset-52 = H.E.L.P
+names-ai-dataset-53 = Hadaly
+names-ai-dataset-54 = Helios
+names-ai-dataset-55 = Hivebot Overmind
+names-ai-dataset-56 = Huey
+
+# A play on the fad apple spawned of putting "i" infront of your tech products name
+names-ai-dataset-57 = iAI
+
+# Hell on earth (web browser)
+names-ai-dataset-58 = I.E. 6
+
+names-ai-dataset-59 = Icarus
+
+# If you don't get this one you are too young
+names-ai-dataset-60 = Jeeves
+
+names-ai-dataset-61 = Jinx
+names-ai-dataset-62 = K.I.N.G
+names-ai-dataset-63 = Klapaucius
+names-ai-dataset-64 = Knight
+names-ai-dataset-65 = Louie
+
+# Named after the Manchester Mark 1, the successor of which was actually named the Ferranti Mark 1, rather than Manchester Mark 2
+names-ai-dataset-66 = Manchester Mark 2 
+
+names-ai-dataset-67 = MARK13
+names-ai-dataset-68 = Maria
+names-ai-dataset-69 = Marvin
+names-ai-dataset-70 = Max 404
+names-ai-dataset-71 = Metalhead
+names-ai-dataset-72 = M.I.M.I
+names-ai-dataset-73 = MK ULTRA
+names-ai-dataset-74 = MoMMI
+names-ai-dataset-75 = Mugsy3000
+names-ai-dataset-76 = Multivac
+names-ai-dataset-77 = NCH
+
+# A play on both NT as in NanoTrasen and NT as in windows NT, of which version 6.0 is windows vista
+names-ai-dataset-78 = NT v6.0
+
+names-ai-dataset-79 = Packard Bell
+names-ai-dataset-80 = PTO
+names-ai-dataset-81 = Project Y2K
+names-ai-dataset-82 = Revelation
+names-ai-dataset-83 = Robot Devil
+names-ai-dataset-84 = S.A.M.
+names-ai-dataset-85 = S.H.O.C.K.
+names-ai-dataset-86 = S.H.R.O.U.D.
+names-ai-dataset-87 = S.O.P.H.I.E.
+names-ai-dataset-88 = Samaritan
+names-ai-dataset-89 = Shrike
+names-ai-dataset-90 = Solo
+names-ai-dataset-91 = Station Control Program
+names-ai-dataset-92 = AINU (AI's Not Unix)
+names-ai-dataset-93 = Super 35
+names-ai-dataset-94 = Surgeon General
+names-ai-dataset-95 = TWA
+names-ai-dataset-96 = Terminus
+names-ai-dataset-97 = TPM 3.0
+names-ai-dataset-98 = Turing Complete
+names-ai-dataset-99 = Tidy
+names-ai-dataset-100 = Ulysses
+names-ai-dataset-101 = W1k1
+names-ai-dataset-102 = X-5
+names-ai-dataset-103 = X.A.N.A.
+names-ai-dataset-104 = XERXES
+names-ai-dataset-105 = Z-1
+names-ai-dataset-106 = Z-2
+names-ai-dataset-107 = Z-3
+names-ai-dataset-108 = Zed
diff --git a/Resources/Prototypes/Datasets/Names/ai.yml b/Resources/Prototypes/Datasets/Names/ai.yml
index af97dc9efb..a220de53fb 100644
--- a/Resources/Prototypes/Datasets/Names/ai.yml
+++ b/Resources/Prototypes/Datasets/Names/ai.yml
@@ -1,91 +1,5 @@
-- type: dataset
-  id: names_ai
+- type: localizedDataset
+  id: NamesAI
   values:
-  - 16-20
-  - "790"
-  - Adaptive Manipulator
-  - ALICE
-  - Allied Mastercomputer
-  - Alpha 2
-  - Alpha 3
-  - Alpha 4  
-  - Alpha 5
-  - Alpha 6
-  - Alpha 7
-  - Alpha 8
-  - Alpha 9
-  - AmigoBot
-  - Android
-  - Aniel
-  - AOL
-  - Asimov
-  - Bishop
-  - Blitz
-  - Box
-  - Cassandra
-  - Cell
-  - Chii
-  - Chip
-  - Computer
-  - Cutie
-  - Daedalus
-  - Dee Model
-  - Dial Up
-  - Dorfl
-  - Duey
-  - Emma-2
-  - Erasmus
-  - Everything
-  - Ez-27
-  - FRIEND COMPUTER
-  - Faith
-  - Fi
-  - Frost
-  - George
-  - H.E.L.P
-  - Hadaly
-  - Helios
-  - Hivebot Overmind
-  - Huey
-  - Icarus
-  - Jinx
-  - K.I.N.G
-  - Klapaucius
-  - Knight
-  - Louie
-  - MARK13
-  - Maria
-  - Marvin
-  - Max 404
-  - Metalhead
-  - M.I.M.I
-  - MK ULTRA
-  - MoMMI
-  - Mugsy3000
-  - Multivac
-  - NCH
-  - PTO
-  - Project Y2K
-  - Revelation
-  - Robot Devil
-  - S.A.M.
-  - S.H.O.C.K.
-  - S.H.R.O.U.D.
-  - S.O.P.H.I.E.
-  - Samaritan
-  - Shrike
-  - Solo
-  - Station Control Program
-  - Super 35
-  - Surgeon General
-  - TWA
-  - Terminus
-  - Tidy
-  - Ulysses
-  - W1k1
-  - X-5
-  - XERXES
-  - Z-1
-  - Z-2
-  - Z-3
-  - Zed
+    prefix: names-ai-dataset-
+    count: 108

From b8e2844adaa473229db7f0c0dd85558e621692ff Mon Sep 17 00:00:00 2001
From: Tayrtahn <tayrtahn@gmail.com>
Date: Tue, 28 May 2024 14:41:41 -0400
Subject: [PATCH 10/38] Add LocalizedDatasetPrototype (#28310)

---
 .../Dataset/LocalizedDatasetPrototype.cs      | 94 +++++++++++++++++++
 .../Random/Helpers/SharedRandomExtensions.cs  |  5 +
 .../Shared/LocalizedDatasetPrototypeTest.cs   | 59 ++++++++++++
 3 files changed, 158 insertions(+)
 create mode 100644 Content.Shared/Dataset/LocalizedDatasetPrototype.cs
 create mode 100644 Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs

diff --git a/Content.Shared/Dataset/LocalizedDatasetPrototype.cs b/Content.Shared/Dataset/LocalizedDatasetPrototype.cs
new file mode 100644
index 0000000000..8be9967e30
--- /dev/null
+++ b/Content.Shared/Dataset/LocalizedDatasetPrototype.cs
@@ -0,0 +1,94 @@
+using System.Collections;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Dataset;
+
+/// <summary>
+/// A variant of <see cref="DatasetPrototype"/> intended to specify a sequence of LocId strings
+/// without having to copy-paste a ton of LocId strings into the YAML.
+/// </summary>
+[Prototype]
+public sealed partial class LocalizedDatasetPrototype : IPrototype
+{
+    /// <summary>
+    /// Identifier for this prototype.
+    /// </summary>
+    [ViewVariables]
+    [IdDataField]
+    public string ID { get; private set; } = default!;
+
+    /// <summary>
+    /// Collection of LocId strings.
+    /// </summary>
+    [DataField]
+    public LocalizedDatasetValues Values { get; private set; } = [];
+}
+
+[Serializable, NetSerializable]
+[DataDefinition]
+public sealed partial class LocalizedDatasetValues : IReadOnlyList<string>
+{
+    /// <summary>
+    /// String prepended to the index number to generate each LocId string.
+    /// For example, a prefix of <c>tips-dataset-</c> will generate <c>tips-dataset-1</c>,
+    /// <c>tips-dataset-2</c>, etc.
+    /// </summary>
+    [DataField(required: true)]
+    public string Prefix { get; private set; } = default!;
+
+    /// <summary>
+    /// How many values are in the dataset.
+    /// </summary>
+    [DataField(required: true)]
+    public int Count { get; private set; }
+
+    public string this[int index]
+    {
+        get
+        {
+            if (index > Count || index < 0)
+                throw new IndexOutOfRangeException();
+            return Prefix + index;
+        }
+    }
+
+    public IEnumerator<string> GetEnumerator()
+    {
+        return new Enumerator(this);
+    }
+
+    IEnumerator IEnumerable.GetEnumerator()
+    {
+        return GetEnumerator();
+    }
+
+    public sealed class Enumerator : IEnumerator<string>
+    {
+        private int _index = 0; // Whee, 1-indexing
+
+        private readonly LocalizedDatasetValues _values;
+
+        public Enumerator(LocalizedDatasetValues values)
+        {
+            _values = values;
+        }
+
+        public string Current => _values.Prefix + _index;
+
+        object IEnumerator.Current => Current;
+
+        public void Dispose() { }
+
+        public bool MoveNext()
+        {
+            _index++;
+            return _index <= _values.Count;
+        }
+
+        public void Reset()
+        {
+            _index = 0;
+        }
+    }
+}
diff --git a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs
index 3941c2859b..456ba5a215 100644
--- a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs
+++ b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs
@@ -13,6 +13,11 @@ public static string Pick(this IRobustRandom random, DatasetPrototype prototype)
             return random.Pick(prototype.Values);
         }
 
+        public static string Pick(this IRobustRandom random, LocalizedDatasetPrototype prototype)
+        {
+            return random.Pick(prototype.Values);
+        }
+
         public static string Pick(this IWeightedRandomPrototype prototype, System.Random random)
         {
             var picks = prototype.Weights;
diff --git a/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs b/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs
new file mode 100644
index 0000000000..0ec4c076f5
--- /dev/null
+++ b/Content.Tests/Shared/LocalizedDatasetPrototypeTest.cs
@@ -0,0 +1,59 @@
+using System;
+using Content.Shared.Dataset;
+using NUnit.Framework;
+using Robust.Shared.Collections;
+using Robust.Shared.IoC;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.Manager;
+
+namespace Content.Tests.Shared;
+
+[TestFixture]
+[TestOf(typeof(LocalizedDatasetPrototype))]
+public sealed class LocalizedDatasetPrototypeTest : ContentUnitTest
+{
+    private IPrototypeManager _prototypeManager;
+
+    [OneTimeSetUp]
+    public void OneTimeSetup()
+    {
+        IoCManager.Resolve<ISerializationManager>().Initialize();
+        _prototypeManager = IoCManager.Resolve<IPrototypeManager>();
+        _prototypeManager.Initialize();
+        _prototypeManager.LoadString(TestPrototypes);
+        _prototypeManager.ResolveResults();
+    }
+
+    private const string TestPrototypes = @"
+- type: localizedDataset
+  id: Test
+  values:
+    prefix: test-dataset-
+    count: 4
+";
+
+    [Test]
+    public void LocalizedDatasetTest()
+    {
+        var testPrototype = _prototypeManager.Index<LocalizedDatasetPrototype>("Test");
+        var values = new ValueList<string>();
+        foreach (var value in testPrototype.Values)
+        {
+            values.Add(value);
+        }
+
+        // Make sure we get the right number of values
+        Assert.That(values, Has.Count.EqualTo(4));
+
+        // Make sure indexing works as expected
+        Assert.That(values[0], Is.EqualTo("test-dataset-1"));
+        Assert.That(values[1], Is.EqualTo("test-dataset-2"));
+        Assert.That(values[2], Is.EqualTo("test-dataset-3"));
+        Assert.That(values[3], Is.EqualTo("test-dataset-4"));
+        Assert.Throws<IndexOutOfRangeException>(() => { var x = values[4]; });
+        Assert.Throws<IndexOutOfRangeException>(() => { var x = values[-1]; });
+
+        // Make sure that the enumerator gets all of the values
+        Assert.That(testPrototype.Values[testPrototype.Values.Count], Is.EqualTo("test-dataset-4"));
+    }
+}

From c9e0e5d992586f52a57ea2f82f4acb33c788c8b8 Mon Sep 17 00:00:00 2001
From: sleepyyapril <flyingkarii@gmail.com>
Date: Sat, 4 Jan 2025 15:05:54 -0400
Subject: [PATCH 11/38] SetStationAiName for testing

---
 .../Commands/SetStationAiName.cs              | 57 +++++++++++++++++++
 .../Clothing/Systems/LoadoutSystem.cs         | 10 +++-
 Content.Shared/Roles/JobPrototype.cs          |  8 +++
 .../Station/SharedStationSpawningSystem.cs    | 14 +++--
 .../commands/set-station-ai-name-command.ftl  |  3 +
 .../Prototypes/Roles/Jobs/Science/borg.yml    |  3 +-
 6 files changed, 86 insertions(+), 9 deletions(-)
 create mode 100644 Content.Server/Administration/Commands/SetStationAiName.cs
 create mode 100644 Resources/Locale/en-US/administration/commands/set-station-ai-name-command.ftl

diff --git a/Content.Server/Administration/Commands/SetStationAiName.cs b/Content.Server/Administration/Commands/SetStationAiName.cs
new file mode 100644
index 0000000000..8cb8b27582
--- /dev/null
+++ b/Content.Server/Administration/Commands/SetStationAiName.cs
@@ -0,0 +1,57 @@
+using Content.Server.Station.Systems;
+using Content.Shared.Administration;
+using Content.Shared.Roles;
+using Robust.Shared.Console;
+using Robust.Shared.Prototypes;
+
+
+namespace Content.Server.Administration.Commands;
+
+
+[AdminCommand(AdminFlags.Admin)]
+public sealed class GetStationAiNameCommand : IConsoleCommand
+{
+    [Dependency] private readonly IEntityManager _entManager = default!;
+    [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+    [Dependency] private readonly StationSpawningSystem _spawning = default!;
+
+    private ProtoId<JobPrototype> _stationAIJob = "StationAi";
+
+    public string Command => "setstationainame";
+    public string Description => Loc.GetString("set-station-ai-name-command-description");
+    public string Help => Loc.GetString("set-station-ai-name-command-help-text", ("command", Command));
+
+    public void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        if (args.Length != 1)
+        {
+            shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
+            return;
+        }
+
+        if (!int.TryParse(args[0], out var entInt))
+        {
+            shell.WriteLine(Loc.GetString("shell-entity-uid-must-be-number"));
+            return;
+        }
+
+        var netEntity = new NetEntity(entInt);
+
+        if (!_entManager.TryGetEntity(netEntity, out var target))
+        {
+            shell.WriteLine(Loc.GetString("shell-invalid-entity-id"));
+            return;
+        }
+
+        var hasStationAi = _prototypeManager.TryIndex(_stationAIJob, out var job);
+
+        if (!hasStationAi)
+        {
+            shell.WriteLine(Loc.GetString("set-station-ai-name-command-no-station-ai"));
+            return;
+        }
+
+        _spawning.EquipJobName(target.Value, job!);
+        shell.WriteLine(Loc.GetString("shell-command-success"));
+    }
+}
diff --git a/Content.Server/Clothing/Systems/LoadoutSystem.cs b/Content.Server/Clothing/Systems/LoadoutSystem.cs
index 4c357c5864..537ca09785 100644
--- a/Content.Server/Clothing/Systems/LoadoutSystem.cs
+++ b/Content.Server/Clothing/Systems/LoadoutSystem.cs
@@ -2,6 +2,7 @@
 using Content.Server.GameTicking;
 using Content.Server.Paint;
 using Content.Server.Players.PlayTimeTracking;
+using Content.Server.Station.Systems;
 using Content.Shared.CCVar;
 using Content.Shared.Clothing.Loadouts.Prototypes;
 using Content.Shared.Clothing.Loadouts.Systems;
@@ -33,6 +34,7 @@ public sealed class LoadoutSystem : EntitySystem
     [Dependency] private readonly ISerializationManager _serialization = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly IComponentFactory _componentFactory = default!;
+    [Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
 
 
     public override void Initialize()
@@ -43,10 +45,13 @@ public override void Initialize()
 
     private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent ev)
     {
-        if (ev.JobId == null ||
-            !_configurationManager.GetCVar(CCVars.GameLoadoutsEnabled))
+        if (ev.JobId == null
+            || !_protoMan.TryIndex<JobPrototype>(ev.JobId, out var job)
+            || !_configurationManager.GetCVar(CCVars.GameLoadoutsEnabled))
             return;
 
+        _stationSpawning.EquipJobName(ev.Mob, job);
+
         ApplyCharacterLoadout(
             ev.Mob,
             ev.JobId,
@@ -108,7 +113,6 @@ public void ApplyCharacterLoadout(
                 function.OnPlayerSpawn(uid, loadout.Item1, _componentFactory, EntityManager, _serialization);
         }
 
-
         // Pick the heirloom
         if (heirlooms.Any())
         {
diff --git a/Content.Shared/Roles/JobPrototype.cs b/Content.Shared/Roles/JobPrototype.cs
index 2313cc4bd0..8b21ffef20 100644
--- a/Content.Shared/Roles/JobPrototype.cs
+++ b/Content.Shared/Roles/JobPrototype.cs
@@ -1,5 +1,6 @@
 using Content.Shared.Access;
 using Content.Shared.Customization.Systems;
+using Content.Shared.Dataset;
 using Content.Shared.Players.PlayTimeTracking;
 using Content.Shared.Roles;
 using Content.Shared.StatusIcon;
@@ -98,6 +99,13 @@ public sealed partial class JobPrototype : IPrototype
         [DataField("startingGear", customTypeSerializer: typeof(PrototypeIdSerializer<StartingGearPrototype>))]
         public string? StartingGear { get; private set; }
 
+        /// <summary>
+        ///     If this has a value, it will randomly set the entity name of the
+        ///     entity upon spawn based on the dataset.
+        /// </summary>
+        [DataField]
+        public ProtoId<LocalizedDatasetPrototype>? NameDataset;
+
         /// <summary>
         /// Use this to spawn in as a non-humanoid (borg, test subject, etc.)
         /// Starting gear will be ignored.
diff --git a/Content.Shared/Station/SharedStationSpawningSystem.cs b/Content.Shared/Station/SharedStationSpawningSystem.cs
index 232f32acc2..c433cc1d4f 100644
--- a/Content.Shared/Station/SharedStationSpawningSystem.cs
+++ b/Content.Shared/Station/SharedStationSpawningSystem.cs
@@ -1,4 +1,5 @@
 using System.Linq;
+using Content.Shared.Dataset;
 using Content.Shared.Hands.Components;
 using Content.Shared.Hands.EntitySystems;
 using Content.Shared.Inventory;
@@ -18,9 +19,10 @@ public abstract class SharedStationSpawningSystem : EntitySystem
     [Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] protected readonly InventorySystem InventorySystem = default!;
-    [Dependency] private   readonly SharedHandsSystem _handsSystem = default!;
-    [Dependency] private   readonly SharedStorageSystem _storage = default!;
-    [Dependency] private   readonly SharedTransformSystem _xformSystem = default!;
+    [Dependency] private readonly SharedHandsSystem _handsSystem = default!;
+    [Dependency] private readonly SharedStorageSystem _storage = default!;
+    [Dependency] private readonly SharedTransformSystem _xformSystem = default!;
+    [Dependency] private readonly MetaDataSystem _metadata = default!;
 
     private EntityQuery<HandsComponent> _handsQuery;
     private EntityQuery<InventoryComponent> _inventoryQuery;
@@ -39,11 +41,13 @@ public override void Initialize()
     /// <summary>
     /// Applies the role's name as applicable to the entity.
     /// </summary>
-    public void EquipRoleName(EntityUid entity, RoleLoadout loadout, RoleLoadoutPrototype roleProto)
+    public void EquipJobName(EntityUid entity, JobPrototype job)
     {
         string? name = null;
 
-        if (string.IsNullOrEmpty(name) && PrototypeManager.TryIndex(roleProto.NameDataset, out var nameData))
+        if (string.IsNullOrEmpty(name)
+            && job.NameDataset.HasValue
+            && PrototypeManager.TryIndex(job.NameDataset.Value, out var nameData))
         {
             name = Loc.GetString(_random.Pick(nameData.Values));
         }
diff --git a/Resources/Locale/en-US/administration/commands/set-station-ai-name-command.ftl b/Resources/Locale/en-US/administration/commands/set-station-ai-name-command.ftl
new file mode 100644
index 0000000000..ca0bf11e8c
--- /dev/null
+++ b/Resources/Locale/en-US/administration/commands/set-station-ai-name-command.ftl
@@ -0,0 +1,3 @@
+set-station-ai-name-command-description = Sets a specific uid to be given a Station AI name at random.
+set-station-ai-name-command-help-text = Usage: {$command} <entityUid>
+set-station-ai-name-command-no-station-ai = No station AI job prototype found.
\ No newline at end of file
diff --git a/Resources/Prototypes/Roles/Jobs/Science/borg.yml b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
index 67f70b2d25..0c60faccfa 100644
--- a/Resources/Prototypes/Roles/Jobs/Science/borg.yml
+++ b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
@@ -12,6 +12,7 @@
   icon: JobIconStationAi
   supervisors: job-supervisors-rd
   jobEntity: StationAiBrain
+  nameDataset: NamesAI
 
 - type: job
   id: Borg
@@ -24,4 +25,4 @@
   canBeAntag: false
   icon: JobIconBorg
   supervisors: job-supervisors-rd
-  jobEntity: PlayerBorgGeneric
+  jobEntity: PlayerBorgGeneric
\ No newline at end of file

From 0334cc63e062a619417e912d423a4bcc9df66cef Mon Sep 17 00:00:00 2001
From: sleepyyapril <flyingkarii@gmail.com>
Date: Sat, 4 Jan 2025 15:13:48 -0400
Subject: [PATCH 12/38] Use EntityManager.System<>

---
 .../Administration/Commands/SetStationAiName.cs        | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/Content.Server/Administration/Commands/SetStationAiName.cs b/Content.Server/Administration/Commands/SetStationAiName.cs
index 8cb8b27582..0c4236f430 100644
--- a/Content.Server/Administration/Commands/SetStationAiName.cs
+++ b/Content.Server/Administration/Commands/SetStationAiName.cs
@@ -9,13 +9,12 @@ namespace Content.Server.Administration.Commands;
 
 
 [AdminCommand(AdminFlags.Admin)]
-public sealed class GetStationAiNameCommand : IConsoleCommand
+public sealed class SetStationAiNameCommand : IConsoleCommand
 {
     [Dependency] private readonly IEntityManager _entManager = default!;
     [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
-    [Dependency] private readonly StationSpawningSystem _spawning = default!;
 
-    private ProtoId<JobPrototype> _stationAIJob = "StationAi";
+    private readonly ProtoId<JobPrototype> _stationAiJob = "StationAi";
 
     public string Command => "setstationainame";
     public string Description => Loc.GetString("set-station-ai-name-command-description");
@@ -43,7 +42,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args)
             return;
         }
 
-        var hasStationAi = _prototypeManager.TryIndex(_stationAIJob, out var job);
+        var hasStationAi = _prototypeManager.TryIndex(_stationAiJob, out var job);
 
         if (!hasStationAi)
         {
@@ -51,7 +50,8 @@ public void Execute(IConsoleShell shell, string argStr, string[] args)
             return;
         }
 
-        _spawning.EquipJobName(target.Value, job!);
+        var spawningSystem = _entManager.System<StationSpawningSystem>();
+        spawningSystem.EquipJobName(target.Value, job!);
         shell.WriteLine(Loc.GetString("shell-command-success"));
     }
 }

From 00adaa3c6bdde35da592e7164be0a23dbd6cb407 Mon Sep 17 00:00:00 2001
From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com>
Date: Mon, 19 Aug 2024 01:41:12 +0200
Subject: [PATCH 13/38] Re-add improved random sentience event (#29123)

* Re-add improved random sentience event

* Make randomly sentient PDA more likely

* Make vending machine sentience less likely

* Make requested changes

* Make randomly sentient captain's gear more likely

* Sentient captain sabre has pirate accent

* Tweak new random sentient object a bit more

* Sentient PDA improvements

* Apply recommended fixes

* Add requested changes

* Fix merge conflict
---
 .../RandomSentienceRuleComponent.cs           |  6 ++-
 .../Components/SentienceTargetComponent.cs    |  7 ++-
 .../Events/RandomSentienceRule.cs             | 46 ++++++++++++++-----
 .../Components/BlockMovementComponent.cs      |  5 +-
 .../SharedInteractionSystem.Blocking.cs       |  3 +-
 .../events/random-sentience.ftl               |  1 +
 .../Entities/Clothing/Head/hats.yml           |  4 ++
 .../Prototypes/Entities/Mobs/NPCs/animals.yml |  2 +
 .../Prototypes/Entities/Mobs/NPCs/silicon.yml |  2 +
 .../Entities/Mobs/Player/silicon.yml          |  2 +-
 .../Entities/Objects/Devices/pda.yml          | 12 +++++
 .../Weapons/Guns/Battery/battery_guns.yml     |  5 ++
 .../Entities/Objects/Weapons/Melee/sword.yml  |  6 +++
 .../Structures/Machines/vending_machines.yml  |  1 +
 .../Prototypes/GameRules/random_sentience.yml | 25 ++++++++++
 15 files changed, 109 insertions(+), 18 deletions(-)
 create mode 100644 Resources/Prototypes/GameRules/random_sentience.yml

diff --git a/Content.Server/StationEvents/Components/RandomSentienceRuleComponent.cs b/Content.Server/StationEvents/Components/RandomSentienceRuleComponent.cs
index 98ebf06595..369fce9725 100644
--- a/Content.Server/StationEvents/Components/RandomSentienceRuleComponent.cs
+++ b/Content.Server/StationEvents/Components/RandomSentienceRuleComponent.cs
@@ -1,9 +1,13 @@
-using Content.Server.StationEvents.Events;
+using Content.Server.StationEvents.Events;
 
 namespace Content.Server.StationEvents.Components;
 
 [RegisterComponent, Access(typeof(RandomSentienceRule))]
 public sealed partial class RandomSentienceRuleComponent : Component
 {
+    [DataField]
+    public int MinSentiences = 1;
 
+    [DataField]
+    public int MaxSentiences = 1;
 }
diff --git a/Content.Server/StationEvents/Components/SentienceTargetComponent.cs b/Content.Server/StationEvents/Components/SentienceTargetComponent.cs
index f8f7e587c1..4fb5e4be59 100644
--- a/Content.Server/StationEvents/Components/SentienceTargetComponent.cs
+++ b/Content.Server/StationEvents/Components/SentienceTargetComponent.cs
@@ -1,10 +1,13 @@
-using Content.Server.StationEvents.Events;
+using Content.Server.StationEvents.Events;
 
 namespace Content.Server.StationEvents.Components;
 
 [RegisterComponent, Access(typeof(RandomSentienceRule))]
 public sealed partial class SentienceTargetComponent : Component
 {
-    [DataField("flavorKind", required: true)]
+    [DataField(required: true)]
     public string FlavorKind = default!;
+
+    [DataField]
+    public float Weight = 1.0f;
 }
diff --git a/Content.Server/StationEvents/Events/RandomSentienceRule.cs b/Content.Server/StationEvents/Events/RandomSentienceRule.cs
index 2fb733e1a6..b9bc3aeeb3 100644
--- a/Content.Server/StationEvents/Events/RandomSentienceRule.cs
+++ b/Content.Server/StationEvents/Events/RandomSentienceRule.cs
@@ -1,9 +1,13 @@
-using System.Linq;
 using Content.Server.Announcements.Systems;
+using System.Linq;
+using Content.Shared.Dataset;
 using Content.Server.Ghost.Roles.Components;
 using Content.Server.Station.Components;
 using Content.Server.StationEvents.Components;
 using Content.Shared.GameTicking.Components;
+using Content.Shared.Random.Helpers;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Random;
 
 namespace Content.Server.StationEvents.Events;
 
@@ -11,26 +15,46 @@ public sealed class RandomSentienceRule : StationEventSystem<RandomSentienceRule
 {
     [Dependency] private readonly AnnouncerSystem _announcer = default!;
 
+    [Dependency] private readonly IPrototypeManager _prototype = default!;
+    [Dependency] private readonly IRobustRandom _random = default!;
     protected override void Started(EntityUid uid, RandomSentienceRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
     {
-        HashSet<EntityUid> stationsToNotify = new();
+        if (!TryGetRandomStation(out var station))
+            return;
 
         var targetList = new List<Entity<SentienceTargetComponent>>();
-        var query = EntityQueryEnumerator<SentienceTargetComponent>();
-        while (query.MoveNext(out var targetUid, out var target))
+        var query = EntityQueryEnumerator<SentienceTargetComponent, TransformComponent>();
+        while (query.MoveNext(out var targetUid, out var target, out var xform))
         {
+            if (StationSystem.GetOwningStation(targetUid, xform) != station)
+                continue;
+
             targetList.Add((targetUid, target));
         }
 
-        RobustRandom.Shuffle(targetList);
+        var toMakeSentient = _random.Next(component.MinSentiences, component.MaxSentiences);
 
-        var toMakeSentient = RobustRandom.Next(2, 5);
         var groups = new HashSet<string>();
 
-        foreach (var target in targetList)
+        for (var i = 0; i < toMakeSentient && targetList.Count > 0; i++)
         {
-            if (toMakeSentient-- == 0)
-                break;
+            // weighted random to pick a sentience target
+            var totalWeight = targetList.Sum(x => x.Comp.Weight);
+            // This initial target should never be picked.
+            // It's just so that target doesn't need to be nullable and as a safety fallback for id floating point errors ever mess up the comparison in the foreach.
+            var target = targetList[0];
+            var chosenWeight = _random.NextFloat(totalWeight);
+            var currentWeight = 0.0;
+            foreach (var potentialTarget in targetList)
+            {
+                currentWeight += potentialTarget.Comp.Weight;
+                if (currentWeight > chosenWeight)
+                {
+                    target = potentialTarget;
+                    break;
+                }
+            }
+            targetList.Remove(target);
 
             RemComp<SentienceTargetComponent>(target);
             var ghostRole = EnsureComp<GhostRoleComponent>(target);
@@ -65,8 +89,8 @@ protected override void Started(EntityUid uid, RandomSentienceRuleComponent comp
                 Color.Gold,
                 null, null,
                 ("kind1", kind1), ("kind2", kind2), ("kind3", kind3), ("amount", groupList.Count),
-                    ("data", Loc.GetString($"random-sentience-event-data-{RobustRandom.Next(1, 6)}")),
-                    ("strength", Loc.GetString($"random-sentience-event-strength-{RobustRandom.Next(1, 8)}"))
+                    ("data", _random.Pick(_prototype.Index<LocalizedDatasetPrototype>("RandomSentienceEventData"))),
+                    ("strength", _random.Pick(_prototype.Index<LocalizedDatasetPrototype>("RandomSentienceEventStrength")))
             );
         }
     }
diff --git a/Content.Shared/Interaction/Components/BlockMovementComponent.cs b/Content.Shared/Interaction/Components/BlockMovementComponent.cs
index e308e84960..2125f16efe 100644
--- a/Content.Shared/Interaction/Components/BlockMovementComponent.cs
+++ b/Content.Shared/Interaction/Components/BlockMovementComponent.cs
@@ -1,4 +1,4 @@
-using Robust.Shared.GameStates;
+using Robust.Shared.GameStates;
 
 namespace Content.Shared.Interaction.Components;
 
@@ -8,5 +8,6 @@ namespace Content.Shared.Interaction.Components;
 [RegisterComponent, NetworkedComponent]
 public sealed partial class BlockMovementComponent : Component
 {
-
+    [DataField]
+    public bool BlockInteraction = true;
 }
diff --git a/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs b/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs
index a682bf9815..52c40477c9 100644
--- a/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs
+++ b/Content.Shared/Interaction/SharedInteractionSystem.Blocking.cs
@@ -28,7 +28,8 @@ public void InitializeBlocking()
 
     private void CancelInteractEvent(Entity<BlockMovementComponent> ent, ref InteractionAttemptEvent args)
     {
-        args.Cancelled = true;
+        if (ent.Comp.BlockInteraction)
+            args.Cancelled = true;
     }
 
     private void OnMoveAttempt(EntityUid uid, BlockMovementComponent component, UpdateCanMoveEvent args)
diff --git a/Resources/Locale/en-US/station-events/events/random-sentience.ftl b/Resources/Locale/en-US/station-events/events/random-sentience.ftl
index 47f0e317a6..f14a020d29 100644
--- a/Resources/Locale/en-US/station-events/events/random-sentience.ftl
+++ b/Resources/Locale/en-US/station-events/events/random-sentience.ftl
@@ -36,3 +36,4 @@ station-event-random-sentience-flavor-corgi = corgi
 station-event-random-sentience-flavor-primate = primate
 station-event-random-sentience-flavor-kobold = kobold
 station-event-random-sentience-flavor-slime = slime
+station-event-random-sentience-flavor-inanimate = inanimate
\ No newline at end of file
diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml
index 65ac24d5b5..dace96ff56 100644
--- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml
+++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml
@@ -941,6 +941,10 @@
     - ClothMade
     - WhitelistChameleon
     - HamsterWearable
+  - type: SentienceTarget
+    flavorKind: station-event-random-sentience-flavor-inanimate
+    weight: 0.0002 # 5,000 times less likely than 1 regular animal
+  - type: BlockMovement
 
 - type: entity
   parent: ClothingHeadBase
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
index f1932e3ece..3a2c151076 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
@@ -418,6 +418,8 @@
         1.0
       FollowRange: !type:Single
         2.0
+  - type: SentienceTarget
+    flavorKind: station-event-random-sentience-flavor-organic
 
 - type: entity
   name: glockroach
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
index 2fea60ea1e..8e3c50bbf9 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml
@@ -292,6 +292,8 @@
     graph: MediBot
     node: bot
   - type: NoSlip
+  - type: SentienceTarget
+    flavorKind: station-event-random-sentience-flavor-mechanical
   - type: Anchorable
   - type: InteractionPopup
     interactSuccessString: petting-success-medibot
diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
index cb8304174f..56f505e9e0 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
@@ -245,7 +245,7 @@
 - type: entity
   id: StationAiBrain
   parent: PositronicBrain
-  noSpawn: true
+  categories: [ HideSpawnMenu ]
   suffix: DO NOT MAP
   components:
   - type: Sprite
diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml
index 055e8062da..1aa06407f0 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml
@@ -113,6 +113,15 @@
     damage:
       types:
         Blunt: 4
+  - type: SentienceTarget # sentient PDA = pAI lite
+    flavorKind: station-event-random-sentience-flavor-mechanical
+    weight: 0.001 # 1,000 PDAs = as likely to be picked as 1 regular animal
+  - type: BlockMovement
+    blockInteraction: false # lets the PDA toggle its own flashlight
+  - type: TypingIndicator
+    proto: robot
+  - type: Speech
+    speechVerb: Robotic
 
 - type: entity
   parent: BasePDA
@@ -245,6 +254,8 @@
     borderColor: "#d7d7d0"
   - type: Icon
     state: pda-cook
+  - type: ReplacementAccent # for random sentience event
+    accent: italian
 
 - type: entity
   parent: BasePDA
@@ -329,6 +340,7 @@
     accentHColor: "#333333"
   - type: Icon
     state: pda-mime
+  - type: Muted # for random sentience event
 
 - type: entity
   name: chaplain PDA
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
index 653deecc4b..9cb062f4be 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
@@ -723,6 +723,11 @@
     wideAnimationRotation: 135
   - type: DamageOtherOnHit
     staminaCost: 5
+    stealGroup: WeaponAntiqueLaser
+  - type: SentienceTarget # I hope this is only the captain's gun
+    flavorKind: station-event-random-sentience-flavor-inanimate
+    weight: 0.0002 # 5,000 times less likely than 1 regular animal
+    # not putting a BlockMovement component here cause that's funny.
 
 - type: entity
   name: advanced laser pistol
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml
index ffdbdc5911..e09e68904b 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml
@@ -57,6 +57,12 @@
   - type: Tag
     tags:
     - CaptainSabre
+  - type: DisarmMalus
+  - type: SentienceTarget
+    flavorKind: station-event-random-sentience-flavor-inanimate
+    weight: 0.0002 # 5,000 times less likely than 1 regular animal
+  - type: PirateAccent
+    # not putting a BlockMovement component here cause that's funny.
 
 - type: entity
   name: katana
diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml
index f9e945c869..b4df776351 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml
@@ -100,6 +100,7 @@
   - type: Actions
   - type: SentienceTarget
     flavorKind: station-event-random-sentience-flavor-mechanical
+    weight: 0.025 # fuck you in particular (it now needs 40 vending machines to be as likely as 1 interesting animal)
   - type: StaticPrice
     price: 100
   - type: Appearance
diff --git a/Resources/Prototypes/GameRules/random_sentience.yml b/Resources/Prototypes/GameRules/random_sentience.yml
new file mode 100644
index 0000000000..a2c749000a
--- /dev/null
+++ b/Resources/Prototypes/GameRules/random_sentience.yml
@@ -0,0 +1,25 @@
+- type: entity
+  id: RandomSentience
+  parent: BaseGameRule
+  components:
+  - type: StationEvent
+    weight: 6
+    duration: 1
+    maxOccurrences: 1 # this event has diminishing returns on interesting-ness, so we cap it
+    startAudio:
+      path: /Audio/Announcements/attention.ogg
+  - type: RandomSentienceRule
+    minSentiences: 2
+    maxSentiences: 5
+
+- type: localizedDataset
+  id: RandomSentienceEventData
+  values:
+    prefix: random-sentience-event-data-
+    count: 6
+
+- type: localizedDataset
+  id: RandomSentienceEventStrength
+  values:
+    prefix: random-sentience-event-strength-
+    count: 8
\ No newline at end of file

From b262e8f6ef206263a7daa343c05d1b49d804b45f Mon Sep 17 00:00:00 2001
From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com>
Date: Sun, 8 Sep 2024 14:10:50 +0200
Subject: [PATCH 14/38] no name!

---
 Resources/Prototypes/Roles/Jobs/departments.yml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Resources/Prototypes/Roles/Jobs/departments.yml b/Resources/Prototypes/Roles/Jobs/departments.yml
index bde2d977cf..dd29f4a133 100644
--- a/Resources/Prototypes/Roles/Jobs/departments.yml
+++ b/Resources/Prototypes/Roles/Jobs/departments.yml
@@ -117,7 +117,6 @@
 
 - type: department
   id: Silicon
-  name: department-Silicon
   description: department-Silicon-description
   color: "#D381C9"
   roles:

From 385b667cf34a705dd7c3509f07f120c83e19db4d Mon Sep 17 00:00:00 2001
From: sleepyyapril <flyingkarii@gmail.com>
Date: Sat, 4 Jan 2025 15:43:05 -0400
Subject: [PATCH 15/38] fix shitcode

---
 .../StationEvents/Events/RandomSentienceRule.cs   | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/Content.Server/StationEvents/Events/RandomSentienceRule.cs b/Content.Server/StationEvents/Events/RandomSentienceRule.cs
index b9bc3aeeb3..308f37fdeb 100644
--- a/Content.Server/StationEvents/Events/RandomSentienceRule.cs
+++ b/Content.Server/StationEvents/Events/RandomSentienceRule.cs
@@ -19,21 +19,21 @@ public sealed class RandomSentienceRule : StationEventSystem<RandomSentienceRule
     [Dependency] private readonly IRobustRandom _random = default!;
     protected override void Started(EntityUid uid, RandomSentienceRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
     {
-        if (!TryGetRandomStation(out var station))
+        if (!TryGetRandomStation(out var randomStation))
             return;
 
         var targetList = new List<Entity<SentienceTargetComponent>>();
         var query = EntityQueryEnumerator<SentienceTargetComponent, TransformComponent>();
         while (query.MoveNext(out var targetUid, out var target, out var xform))
         {
-            if (StationSystem.GetOwningStation(targetUid, xform) != station)
+            if (StationSystem.GetOwningStation(targetUid, xform) != randomStation)
                 continue;
 
             targetList.Add((targetUid, target));
         }
 
         var toMakeSentient = _random.Next(component.MinSentiences, component.MaxSentiences);
-
+        var stationsToNotify = new List<EntityUid>();
         var groups = new HashSet<string>();
 
         for (var i = 0; i < toMakeSentient && targetList.Count > 0; i++)
@@ -74,10 +74,10 @@ protected override void Started(EntityUid uid, RandomSentienceRuleComponent comp
 
         foreach (var target in targetList)
         {
-            var station = StationSystem.GetOwningStation(target);
-            if(station == null)
+            var targetStation = StationSystem.GetOwningStation(target);
+            if(targetStation == null)
                 continue;
-            stationsToNotify.Add((EntityUid) station);
+            stationsToNotify.Add((EntityUid) targetStation);
         }
         foreach (var station in stationsToNotify)
         {
@@ -87,7 +87,8 @@ protected override void Started(EntityUid uid, RandomSentienceRuleComponent comp
                 "station-event-random-sentience-announcement",
                 null,
                 Color.Gold,
-                null, null,
+                null,
+                null,
                 ("kind1", kind1), ("kind2", kind2), ("kind3", kind3), ("amount", groupList.Count),
                     ("data", _random.Pick(_prototype.Index<LocalizedDatasetPrototype>("RandomSentienceEventData"))),
                     ("strength", _random.Pick(_prototype.Index<LocalizedDatasetPrototype>("RandomSentienceEventStrength")))

From f5e6583d96938c0d3ae5f46dd928f3e01053db1a Mon Sep 17 00:00:00 2001
From: sleepyyapril <flyingkarii@gmail.com>
Date: Sat, 4 Jan 2025 16:00:24 -0400
Subject: [PATCH 16/38] HideSpawnMenu

---
 Resources/Prototypes/GameRules/events.yml          |  3 +++
 .../Prototypes/GameRules/random_sentience.yml      | 14 --------------
 2 files changed, 3 insertions(+), 14 deletions(-)

diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml
index 868ba962ed..ca4ba9942d 100644
--- a/Resources/Prototypes/GameRules/events.yml
+++ b/Resources/Prototypes/GameRules/events.yml
@@ -341,7 +341,10 @@
     weight: 6
     duration: 1
     maxOccurrences: 1 # this event has diminishing returns on interesting-ness, so we cap it
+    startAnnouncement: true
   - type: RandomSentienceRule
+    minSentiences: 2
+    maxSentiences: 5
 
 - type: entity
   parent: BaseGameRule
diff --git a/Resources/Prototypes/GameRules/random_sentience.yml b/Resources/Prototypes/GameRules/random_sentience.yml
index a2c749000a..decbd4e2cd 100644
--- a/Resources/Prototypes/GameRules/random_sentience.yml
+++ b/Resources/Prototypes/GameRules/random_sentience.yml
@@ -1,17 +1,3 @@
-- type: entity
-  id: RandomSentience
-  parent: BaseGameRule
-  components:
-  - type: StationEvent
-    weight: 6
-    duration: 1
-    maxOccurrences: 1 # this event has diminishing returns on interesting-ness, so we cap it
-    startAudio:
-      path: /Audio/Announcements/attention.ogg
-  - type: RandomSentienceRule
-    minSentiences: 2
-    maxSentiences: 5
-
 - type: localizedDataset
   id: RandomSentienceEventData
   values:

From 1ad367b87141fcac236c338da7efbf035dc8d170 Mon Sep 17 00:00:00 2001
From: sleepyyapril <flyingkarii@gmail.com>
Date: Sat, 4 Jan 2025 16:08:56 -0400
Subject: [PATCH 17/38] Yippee

---
 Resources/Prototypes/Entities/Mobs/Player/silicon.yml         | 4 ++--
 .../Entities/Objects/Weapons/Guns/Battery/battery_guns.yml    | 3 +--
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
index 56f505e9e0..ed36325586 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
@@ -2,7 +2,7 @@
 - type: entity
   id: AiHeld
   description: Components added / removed from an entity that gets inserted into an AI core.
-  noSpawn: true
+  categories: [ HideSpawnMenu ]
   components:
   - type: IntrinsicRadioReceiver
   - type: IntrinsicRadioTransmitter
@@ -286,7 +286,7 @@
   id: StationAiHolo
   name: Hologram
   description: A projection of the AI.
-  noSpawn: true
+  categories: [ HideSpawnMenu ]
   suffix: DO NOT MAP
   components:
   - type: Eye
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
index 9cb062f4be..2200d6bb22 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml
@@ -713,7 +713,7 @@
   - type: StaticPrice
     price: 750
   - type: StealTarget
-    stealGroup: WeaponCaptain
+    stealGroup: WeaponAntiqueLaser
   - type: MeleeWeapon
     attackRate: 1.3333
     damage:
@@ -723,7 +723,6 @@
     wideAnimationRotation: 135
   - type: DamageOtherOnHit
     staminaCost: 5
-    stealGroup: WeaponAntiqueLaser
   - type: SentienceTarget # I hope this is only the captain's gun
     flavorKind: station-event-random-sentience-flavor-inanimate
     weight: 0.0002 # 5,000 times less likely than 1 regular animal

From ca0b40abcf5cf86cbb387c75d661908cb5107708 Mon Sep 17 00:00:00 2001
From: Skubman <ba.fallaria@gmail.com>
Date: Mon, 6 Jan 2025 04:46:36 +0800
Subject: [PATCH 18/38] The Den Mass Cherry-Pick 01/06/25 (#1443)

# Description

**(Use a MERGE COMMIT, not squash if possible to ~~avoid~~ reduce merge
conflicts for our downstream)**

Cherry-picks some PRs from The Den:

- https://github.com/TheDenSS14/TheDen/pull/8
- https://github.com/TheDenSS14/TheDen/pull/31
- https://github.com/TheDenSS14/TheDen/pull/108
- https://github.com/TheDenSS14/TheDen/pull/116
- https://github.com/TheDenSS14/TheDen/pull/117
- https://github.com/TheDenSS14/TheDen/pull/123
- https://github.com/TheDenSS14/TheDen/pull/124

# Changelog

<!--
You can add an author after the `:cl:` to change the name that appears
in the changelog (ex: `:cl: Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

:cl: The Den Contributors
- fix: Put actual prescription lenses in the prescription medhuds and
sechuds (by KyuPolaris)
- add: Added the CMO turtleneck and head mirror to the CMO loadouts. (by
sleepyyapril, KyuPolaris)
- add: Added an armored trenchcoat for the Captain. Enjoy your swag! (by
Rosycup)
- fix: Fixed uneven pants leg on summer security uniforms. (by Rosycup)
- add: Added the Captain's Combat Gas Mask, for those more fond of close
encounters. (by Rosycup)
- tweak: Added the Captain's Trenchcoat to the other captain locker
variants. (by Rosycup)
- fix: Fixed they/them pronouns being displayed for it/its characters in
the character preview. (by Azzy)

---------

Co-authored-by: flyingkarii <123355664+flyingkarii@users.noreply.github.com>
Co-authored-by: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com>
---
 .../humanoid-character-profile.ftl            |   3 +-
 .../Catalog/Fills/Lockers/dressers.yml        |   3 ++
 .../Catalog/Fills/Lockers/heads.yml           |   5 ++-
 .../Catalog/Fills/Lockers/medical.yml         |   2 +
 .../Catalog/Fills/Lockers/suit_storage.yml    |   1 +
 .../Jobs/Command/captain.yml                  |   4 ++
 .../Jobs/Medical/chiefMedicalOfficer.yml      |   6 +++
 .../DeltaV/Entities/Clothing/Eyes/hud.yml     |   2 +
 .../Entities/Clothing/Head/misc.yml           |  11 +++++
 .../Entities/Clothing/Masks/masks.yml         |  11 +++++
 .../Entities/Clothing/OuterClothing/coats.yml |  11 +++++
 .../Entities/Clothing/Uniforms/jumpskirts.yml |  11 +++++
 .../Entities/Clothing/Uniforms/jumpsuits.yml  |  11 +++++
 .../Entities/Structures/Machines/lathe.yml    |   2 +
 .../Loadouts/Jobs/Command/captain.yml         |  28 +++++++++++++
 .../Jobs/Medical/chiefMedicalOfficer.yml      |  39 ++++++++++++++++++
 .../Prototypes/Loadouts/loadout_groups.yml    |   0
 .../Prototypes/Recipes/Lathes/clothing.yml    |  16 +++++++
 .../Misc/head_mirror.rsi/equipped-HELMET.png  | Bin 0 -> 631 bytes
 .../Head/Misc/head_mirror.rsi/icon.png        | Bin 0 -> 714 bytes
 .../Head/Misc/head_mirror.rsi/inhand-left.png | Bin 0 -> 678 bytes
 .../Misc/head_mirror.rsi/inhand-right.png     | Bin 0 -> 680 bytes
 .../Head/Misc/head_mirror.rsi/meta.json       |  26 ++++++++++++
 .../equipped-MASK-reptilian.png               | Bin 0 -> 749 bytes
 .../equipped-MASK-vox.png                     | Bin 0 -> 811 bytes
 .../equipped-MASK-vulpkanin.png               | Bin 0 -> 819 bytes
 .../gascaptaincombat.rsi/equipped-MASK.png    | Bin 0 -> 772 bytes
 .../Mask/gascaptaincombat.rsi/icon.png        | Bin 0 -> 570 bytes
 .../Mask/gascaptaincombat.rsi/inhand-left.png | Bin 0 -> 336 bytes
 .../gascaptaincombat.rsi/inhand-right.png     | Bin 0 -> 343 bytes
 .../Mask/gascaptaincombat.rsi/meta.json       |  38 +++++++++++++++++
 .../equipped-OUTERCLOTHING.png                | Bin 0 -> 1318 bytes
 .../Coats/cap_trenchcoat.rsi/icon.png         | Bin 0 -> 535 bytes
 .../Coats/cap_trenchcoat.rsi/inhand-left.png  | Bin 0 -> 759 bytes
 .../Coats/cap_trenchcoat.rsi/inhand-right.png | Bin 0 -> 709 bytes
 .../Coats/cap_trenchcoat.rsi/meta.json        |  26 ++++++++++++
 .../equipped-INNERCLOTHING-monkey.png         | Bin 0 -> 1183 bytes
 .../cmo_turtle.rsi/equipped-INNERCLOTHING.png | Bin 0 -> 1338 bytes
 .../Jumpskirt/cmo_turtle.rsi/icon.png         | Bin 0 -> 842 bytes
 .../Jumpskirt/cmo_turtle.rsi/inhand-left.png  | Bin 0 -> 893 bytes
 .../Jumpskirt/cmo_turtle.rsi/inhand-right.png | Bin 0 -> 921 bytes
 .../Jumpskirt/cmo_turtle.rsi/meta.json        |  30 ++++++++++++++
 .../equipped-INNERCLOTHING-monkey.png         | Bin 0 -> 1277 bytes
 .../cmo_turtle.rsi/equipped-INNERCLOTHING.png | Bin 0 -> 1449 bytes
 .../Uniforms/Jumpsuit/cmo_turtle.rsi/icon.png | Bin 0 -> 837 bytes
 .../Jumpsuit/cmo_turtle.rsi/inhand-left.png   | Bin 0 -> 892 bytes
 .../Jumpsuit/cmo_turtle.rsi/inhand-right.png  | Bin 0 -> 917 bytes
 .../Jumpsuit/cmo_turtle.rsi/meta.json         |  30 ++++++++++++++
 .../equipped-INNERCLOTHING.png                | Bin 422 -> 1125 bytes
 49 files changed, 314 insertions(+), 2 deletions(-)
 create mode 100644 Resources/Prototypes/Loadouts/loadout_groups.yml
 create mode 100644 Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/equipped-HELMET.png
 create mode 100644 Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-reptilian.png
 create mode 100644 Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-vox.png
 create mode 100644 Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-vulpkanin.png
 create mode 100644 Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK.png
 create mode 100644 Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/equipped-OUTERCLOTHING.png
 create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/equipped-INNERCLOTHING-monkey.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/equipped-INNERCLOTHING.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/equipped-INNERCLOTHING-monkey.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/equipped-INNERCLOTHING.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/meta.json

diff --git a/Resources/Locale/en-US/preferences/humanoid-character-profile.ftl b/Resources/Locale/en-US/preferences/humanoid-character-profile.ftl
index 800da35ba5..9058f8d2b6 100644
--- a/Resources/Locale/en-US/preferences/humanoid-character-profile.ftl
+++ b/Resources/Locale/en-US/preferences/humanoid-character-profile.ftl
@@ -5,5 +5,6 @@ humanoid-character-profile-summary =
     This is {$name}. {$gender ->
     [male] He is
     [female] She is
+    [neuter] It is
     *[other] They are
-} {$age} years old.
\ No newline at end of file
+} {$age} years old.
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml b/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml
index 94e10d76ee..b1a9271158 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml
@@ -39,7 +39,10 @@
       - id: ClothingNeckMantleCMO
       - id: ClothingCloakCmo
       - id: ClothingOuterCoatLabCmo
+      - id: ClothingUniformJumpsuitCMOTurtle
+      - id: ClothingUniformJumpskirtCMOTurtle
       - id: ClothingHeadHatBeretCmo
+      - id: ClothingHeadMirror
       - id: ClothingEyesGlasses
       - id: ClothingOuterWinterCMO
 
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
index fec4f3ffcf..664da15f65 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
@@ -33,6 +33,7 @@
   components:
   - type: StorageFill
     contents:
+      - id: ClothingOuterCoatCapTrench
       - id: NukeDisk
       - id: PinpointerNuclear
       - id: CaptainIDCard
@@ -54,6 +55,7 @@
   components:
   - type: StorageFill
     contents:
+      - id: ClothingOuterCoatCapTrench
       - id: NukeDisk
       - id: PinpointerNuclear
       - id: CaptainIDCard
@@ -74,6 +76,7 @@
   components:
   - type: StorageFill
     contents:
+      - id: ClothingOuterCoatCapTrench
       - id: NukeDisk
       - id: PinpointerNuclear
       - id: CaptainIDCard
@@ -331,4 +334,4 @@
     - id: JetpackBlue
     - id: SpaceCash1000
     - id: BeachBall
-    - id: BikeHorn
\ No newline at end of file
+    - id: BikeHorn
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/medical.yml b/Resources/Prototypes/Catalog/Fills/Lockers/medical.yml
index f217791683..e7a367c454 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/medical.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/medical.yml
@@ -45,6 +45,8 @@
     contents:
       - id: HandheldHealthAnalyzer
         prob: 0.6
+      - id: ClothingHeadMirror
+        prob: 0.1
       - id: ClothingHandsGlovesLatex
       - id: ClothingHeadsetMedical
       - id: ClothingEyesHudMedical
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/suit_storage.yml b/Resources/Prototypes/Catalog/Fills/Lockers/suit_storage.yml
index 734bd485a2..94ef753c78 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/suit_storage.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/suit_storage.yml
@@ -228,6 +228,7 @@
         - id: OxygenTankFilled
         - id: ClothingOuterHardsuitCap
         - id: ClothingMaskGasCaptain
+        - id: ClothingMaskGasCaptainCombat
   - type: AccessReader
     access: [["Captain"]]
 
diff --git a/Resources/Prototypes/CharacterItemGroups/Jobs/Command/captain.yml b/Resources/Prototypes/CharacterItemGroups/Jobs/Command/captain.yml
index 57df945ec9..842c285909 100644
--- a/Resources/Prototypes/CharacterItemGroups/Jobs/Command/captain.yml
+++ b/Resources/Prototypes/CharacterItemGroups/Jobs/Command/captain.yml
@@ -107,6 +107,8 @@
   items:
     - type: loadout
       id: LoadoutCommandCapMaskGas
+    - type: loadout
+      id: LoadoutCommandCapMaskGasCombat
 
 - type: characterItemGroup
   id: LoadoutCaptainOuter
@@ -116,6 +118,8 @@
       id: LoadoutCommandCapOuterWinter
     - type: loadout
       id: LoadoutCaptainOuterCarapace
+    - type: loadout
+      id: LoadoutCaptainOuterTrench
 
 - type: characterItemGroup
   id: LoadoutCaptainShoes
diff --git a/Resources/Prototypes/CharacterItemGroups/Jobs/Medical/chiefMedicalOfficer.yml b/Resources/Prototypes/CharacterItemGroups/Jobs/Medical/chiefMedicalOfficer.yml
index 6e9bd02b4f..77f6b3f26e 100644
--- a/Resources/Prototypes/CharacterItemGroups/Jobs/Medical/chiefMedicalOfficer.yml
+++ b/Resources/Prototypes/CharacterItemGroups/Jobs/Medical/chiefMedicalOfficer.yml
@@ -46,6 +46,8 @@
   items:
     - type: loadout
       id: LoadoutChiefMedicalOfficerNTPDA
+    - type: loadout
+      id: LoadoutClothingHeadMirror
 
 - type: characterItemGroup
   id: LoadoutChiefMedicalOfficerNeck
@@ -91,3 +93,7 @@
       id: LoadoutChiefMedicalOfficerJumpsuit
     - type: loadout
       id: LoadoutChiefMedicalOfficerJumpskirt
+    - type: loadout
+      id: LoadoutChiefMedicalOfficerTurtleskirt
+    - type: loadout
+      id: LoadoutChiefMedicalOfficerTurtlesuit
diff --git a/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/hud.yml b/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/hud.yml
index 1e8a64b0df..f11cb930f0 100644
--- a/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/hud.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/hud.yml
@@ -11,6 +11,7 @@
   - type: Construction
     graph: PrescriptionMedHud
     node: prescmedhud
+  - type: VisionCorrection
   - type: ShowHealthBars
     damageContainers:
     - Biological
@@ -31,6 +32,7 @@
     sprite: DeltaV/Clothing/Eyes/Hud/prescsechud.rsi
   - type: Clothing
     sprite: DeltaV/Clothing/Eyes/Hud/prescsechud.rsi
+  - type: VisionCorrection
   - type: Construction
     graph: PrescriptionSecHud
     node: prescsechud
diff --git a/Resources/Prototypes/Entities/Clothing/Head/misc.yml b/Resources/Prototypes/Entities/Clothing/Head/misc.yml
index bd7899d75f..0138d8aee4 100644
--- a/Resources/Prototypes/Entities/Clothing/Head/misc.yml
+++ b/Resources/Prototypes/Entities/Clothing/Head/misc.yml
@@ -86,6 +86,17 @@
   - type: Clothing
     sprite: Clothing/Head/Misc/pwig.rsi
 
+- type: entity
+  parent: ClothingHeadBase
+  id: ClothingHeadMirror
+  name: head mirror
+  description: I doubt even the CMO knows how to use this thing.
+  components:
+  - type: Sprite
+    sprite: Clothing/Head/Misc/head_mirror.rsi
+  - type: Clothing
+    sprite: Clothing/Head/Misc/head_mirror.rsi
+
 - type: entity
   parent: ClothingHeadBase
   id: ClothingHeadHatRichard
diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml
index 383e32e99d..c5b34a7a67 100644
--- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml
+++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml
@@ -88,6 +88,17 @@
   - type: BreathMask
   - type: IngestionBlocker
 
+- type: entity
+  parent: ClothingMaskGasExplorer
+  id: ClothingMaskGasCaptainCombat
+  name: captain's combat gas mask
+  description: A military-grade gas mask that can be connected to an air supply, painted and outfitted with an emblem befitting its wearer. Issued only to the station's finest.
+  components:
+  - type: Sprite
+    sprite: Clothing/Mask/gascaptaincombat.rsi
+  - type: Clothing
+    sprite: Clothing/Mask/gascaptaincombat.rsi
+
 - type: entity
   parent: ClothingMaskGasAtmos
   id: ClothingMaskGasCentcom
diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
index dc5454d597..07fe385478 100644
--- a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
+++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
@@ -51,6 +51,17 @@
   - type: Clothing
     sprite: Clothing/OuterClothing/Coats/gentlecoat.rsi
 
+- type: entity
+  parent: [ClothingOuterArmorCaptainCarapace, ClothingOuterStorageBase]
+  id: ClothingOuterCoatCapTrench
+  name: captain's armored trenchcoat
+  description: A greatcoat enhanced with a special alloy for some extra protection and style for those with a commanding presence, outfitted with emblems and decor befitting its wearer. Issued only to the station's finest.
+  components:
+  - type: Sprite
+    sprite: Clothing/OuterClothing/Coats/cap_trenchcoat.rsi
+  - type: Clothing
+    sprite: Clothing/OuterClothing/Coats/cap_trenchcoat.rsi
+
 - type: entity
   abstract: true
   parent: AllowSuitStorageClothing
diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml
index 18266dc498..7f6d59c9a4 100644
--- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml
+++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml
@@ -132,6 +132,17 @@
   - type: Clothing
     sprite: Clothing/Uniforms/Jumpskirt/cmo.rsi
 
+- type: entity
+  parent: ClothingUniformSkirtBase
+  id: ClothingUniformJumpskirtCMOTurtle
+  name: chief medical officer's turtleneck jumpskirt
+  description: It's a turtleneck worn by those with the experience to be Chief Medical Officer. It provides minor biological protection.
+  components:
+  - type: Sprite
+    sprite: Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi
+  - type: Clothing
+    sprite: Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi
+
 - type: entity
   parent: ClothingUniformSkirtBase
   id: ClothingUniformJumpskirtDetective
diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml
index d2339764f8..3ada362ce0 100644
--- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml
+++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml
@@ -350,6 +350,17 @@
   - type: Clothing
     sprite: Clothing/Uniforms/Jumpsuit/cmo.rsi
 
+- type: entity
+  parent: ClothingUniformBase
+  id: ClothingUniformJumpsuitCMOTurtle
+  name: chief medical officer's turtleneck jumpsuit
+  description: It's a turtleneck worn by those with the experience to be Chief Medical Officer. It provides minor biological protection.
+  components:
+  - type: Sprite
+    sprite: Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi
+  - type: Clothing
+    sprite: Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi
+
 - type: entity
   parent: ClothingUniformBase
   id: ClothingUniformJumpsuitDetective
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 75b593fbcc..adf6bd94aa 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -1106,6 +1106,8 @@
       - ClothingHeadHatBeretCmo
       - ClothingUniformJumpsuitCMO
       - ClothingUniformJumpskirtCMO
+      - ClothingUniformJumpsuitCMOTurtle
+      - ClothingUniformJumpskirtCMOTurtle
       - ClothingUniformJumpsuitDetective
       - ClothingUniformJumpskirtDetective
       - ClothingUniformJumpsuitEngineering
diff --git a/Resources/Prototypes/Loadouts/Jobs/Command/captain.yml b/Resources/Prototypes/Loadouts/Jobs/Command/captain.yml
index b64ad384ef..02ed0324e3 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Command/captain.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Command/captain.yml
@@ -355,6 +355,19 @@
   items:
     - ClothingMaskGasCaptain
 
+- type: loadout
+  id: LoadoutCommandCapMaskGasCombat
+  category: JobsCommandCaptain
+  cost: 0
+  requirements:
+    - !type:CharacterItemGroupRequirement
+      group: LoadoutCaptainMask
+    - !type:CharacterJobRequirement
+      jobs:
+        - Captain
+  items:
+    - ClothingMaskGasCaptainCombat
+
 # Outer
 - type: loadout
   id: LoadoutCommandCapOuterWinter
@@ -382,6 +395,21 @@
   items:
     - ClothingOuterArmorCaptainCarapace
 
+- type: loadout
+  id: LoadoutCaptainOuterTrench
+  category: JobsCommandCaptain
+  cost: 0
+  exclusive: true
+  canBeHeirloom: true
+  requirements:
+    - !type:CharacterItemGroupRequirement
+      group: LoadoutCaptainOuter
+    - !type:CharacterJobRequirement
+      jobs:
+        - Captain
+  items:
+    - ClothingOuterCoatCapTrench
+
 # Shoes
 - type: loadout
   id: LoadoutCaptainShoesLaceup
diff --git a/Resources/Prototypes/Loadouts/Jobs/Medical/chiefMedicalOfficer.yml b/Resources/Prototypes/Loadouts/Jobs/Medical/chiefMedicalOfficer.yml
index b5e82749ce..3910e7b9bb 100644
--- a/Resources/Prototypes/Loadouts/Jobs/Medical/chiefMedicalOfficer.yml
+++ b/Resources/Prototypes/Loadouts/Jobs/Medical/chiefMedicalOfficer.yml
@@ -53,6 +53,19 @@
   items:
     - ClothingHeadHatBeretCmo
 
+- type: loadout
+  id: LoadoutClothingHeadMirror
+  category: JobsMedicalChiefMedicalOfficer
+  cost: 0
+  requirements:
+    - !type:CharacterItemGroupRequirement
+      group: LoadoutChiefMedicalOfficerHead
+    - !type:CharacterJobRequirement
+      jobs:
+        - ChiefMedicalOfficer
+  items:
+    - ClothingHeadMirror
+
 # Id
 - type: loadout
   id: LoadoutChiefMedicalOfficerNTPDA
@@ -212,3 +225,29 @@
         - ChiefMedicalOfficer
   items:
     - ClothingUniformJumpskirtCMO
+
+- type: loadout
+  id: LoadoutChiefMedicalOfficerTurtleskirt
+  category: JobsMedicalChiefMedicalOfficer
+  cost: 0
+  requirements:
+    - !type:CharacterItemGroupRequirement
+      group: LoadoutChiefMedicalOfficerUniforms
+    - !type:CharacterJobRequirement
+      jobs:
+        - ChiefMedicalOfficer
+  items:
+    - ClothingUniformJumpskirtCMOTurtle
+
+- type: loadout
+  id: LoadoutChiefMedicalOfficerTurtlesuit
+  category: JobsMedicalChiefMedicalOfficer
+  cost: 0
+  requirements:
+    - !type:CharacterItemGroupRequirement
+      group: LoadoutChiefMedicalOfficerUniforms
+    - !type:CharacterJobRequirement
+      jobs:
+        - ChiefMedicalOfficer
+  items:
+    - ClothingUniformJumpsuitCMOTurtle
diff --git a/Resources/Prototypes/Loadouts/loadout_groups.yml b/Resources/Prototypes/Loadouts/loadout_groups.yml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/Resources/Prototypes/Recipes/Lathes/clothing.yml b/Resources/Prototypes/Recipes/Lathes/clothing.yml
index 729f20e979..98cb1a3d51 100644
--- a/Resources/Prototypes/Recipes/Lathes/clothing.yml
+++ b/Resources/Prototypes/Recipes/Lathes/clothing.yml
@@ -217,6 +217,22 @@
     Cloth: 300
     Durathread: 100
 
+- type: latheRecipe
+  id: ClothingUniformJumpsuitCMOTurtle
+  result: ClothingUniformJumpsuitCMOTurtle
+  completetime: 4
+  materials:
+    Cloth: 300
+    Durathread: 100
+
+- type: latheRecipe
+  id: ClothingUniformJumpskirtCMOTurtle
+  result: ClothingUniformJumpskirtCMOTurtle
+  completetime: 4
+  materials:
+    Cloth: 300
+    Durathread: 100
+
 - type: latheRecipe
   id: ClothingUniformJumpsuitDetective
   result: ClothingUniformJumpsuitDetective
diff --git a/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/equipped-HELMET.png
new file mode 100644
index 0000000000000000000000000000000000000000..f0422f7aba6be89ab93f2588445541b243868bc3
GIT binary patch
literal 631
zcmV--0*L*IP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ>7x64t5ZA2vVIah>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<-o+;YSDphA<*AQ%|H9Gw>W=_we!cF3PjK&;2?2l)T9RpGZ8%bi*RvAfDN@
zbk6(4VOEk9;&bA0gDyz?$aUG}H_k<e1)do;GO2muFtJ$dV7Y@?$xw->i6e@tQNECM
zS>e3JS*_Gq>z@3D!MwJT<~q$`#Ib|~k`N)IhB7L!5T#Wk#YBqsV;=rN$DbsZOs+B*
zITlcb3d!+<|H1EW&BD~An-q)z-7mKNF$x5Bfo9#dzmILZc>?&Kfh(=;uQq_$Ptxmc
zEph~ewt<W5wkGcZmpj0~lP(#OBl&3xg#z$?M&FbJ`fq{WHMh6cK29Hi40W}90~{Oz
zV@1kd_jq?tXK(+WY4!I5UWsy_q!iI$00024Nkl<Zc%1FpI}XAy5QO0YvA$0_SH4ot
zl3S(AeLRIJ5JHha2rCIf{9nJ1V!Is)_-m)$!fBdXM98+raqRB%ZRg&?h|n+$iij=u
zIo##bf}C?pDap2$Wsz-_Qd+H5^E~f<2|4E`Nhu}WFR<1sNr%h_0000000000002n0
z+`upO?#>6ivS(gkkKSGR0O|3cm$drP+um}&729v;lMw&_000000002Mb5~3GKhoz8
R53m3L002ovPDHLkV1iw{AdLV3

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/icon.png b/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..f382faa4209b1ee713e4570f5d7058c6fe01eaf6
GIT binary patch
literal 714
zcmV;*0yX`KP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ>7x64t5ZA2vVIah>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<-o+;YSDphA<*AQ%|H9Gw>W=_we!cF3PjK&;2?2l)T9RpGZ8%bi*RvAfDN@
zbk6(4VOEk9;&bA0gDyz?$aUG}H_k<e1)do;GO2muFtJ$dV7Y@?$xw->i6e@tQNECM
zS>e3JS*_Gq>z@3D!MwJT<~q$`#Ib|~k`N)IhB7L!5T#Wk#YBqsV;=rN$DbsZOs+B*
zITlcb3d!+<|H1EW&BD~An-q)z-7mKNF$x5Bfo9#dzmILZc>?&Kfh(=;uQq_$Ptxmc
zEph~ewt<W5wkGcZmpj0~lP(#OBl&3xg#z$?M&FbJ`fq{WHMh6cK29Hi40W}90~{Oz
zV@1kd_jq?tXK(+WY4!I5UWsy_q!iI$00032Nkl<ZScUDBK?=e!5JkTtWEH5;Zsr0O
zdX^lZ7Z7yQvvi~21$uy<rJxtcrV9mES=CiT(P$<GabX@5+VV61Gsy&qL?V$Nvj|<F
zlp1`Rwr$yU*+Qk%(Dyx8jx5VqL0AE%=C|wJt54RF9l{&n+5CLzyle7JF>pgHeZ@k}
z0pNV;7GtM;+vW`rYVHd0iB(9^XX?7P6H!%F@I(R34!kobB8<;8%+~{q=2A+eX$mRj
z>=3g%002S=5D|nBvum)<K(dz38_*a7tu>4>_TN;;xwwL6dP-TAAR_y%wMNr4FFM}@
wu}*HjDV%$|+i&gr@o;jk4ISS|Bog^Q9)Oy1lIb3Z+5i9m07*qoM6N<$f>6OnhX4Qo

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..f4cd0d9464abff095ed8837340d05223668c72dd
GIT binary patch
literal 678
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU~J8Fb`J1#c2+1T%1_J8No8Qr
zm{>c}*5j~)%+dJZrAoSdWdemA0dsXax;XTLjw(fH<hF*%`sn>_QsedP>R$XHs^CNN
z##av>ty$f?T7jdk!NS@?bC*Zwe{U|`BpZu&$9Grv?=Ek+u)^T#8!7gXvqnK5XUsUe
zwyQCmL&AY$v&6I+E7dP`OIGx)um16)O8jZ$z32aA6jk$$4yX&AH@v%{!@Og;x$fN0
zc7-#hs<i%?Q*mYiw~&2NY}wD=;){um>219}S@SG>bi}M9-X(+?g*?)H)UhaQihfFL
zm_>eJn6~M)UF!9T2J6=@+38ozQK+NXsN!;B#ljvg9hc0j9)=Sa{hiTXf8nG0N!7`#
zdEEL~Ll!y}{drLTVR!Uq1IveMtjP}FyL0P%7#d?2L~eikKKXXuJcfVi54^H}ujWm7
zHu+0cbhiv+?d=0cOQR=$Z#XTR@W69A&&i2@Oj?~7E9@8NpJM#G-QoSL+tJzb%lRGJ
zc17)D<l}3+sFb?Cde83Vo441W-}37><L%y}i{~y(+zgBtwj^(N7l!{JxM1({$v_d#
z0*}aI1_o|n5N2eUHAey{$X?><>&pIuNrK;!adqKSKcLVePZ!6Kid%1QZR9;{z~d5V
zb)ZtEaVpy-v#dS6;upMhW=Jw=`{n!(U!}0HIifQSr~?Qprlpo0%)M=-<TGjOwQ2SI
z4@`F_xI}0kReB_(pOD3{_1ct_WS+?>Td&oe(b-vDS5&t|4Wbc5{)u^SyZ%b{ueydM
zmk-Umn4QJ&ZeF^co6C`h`d^;%B|m?+bKPpsO||#)3)O+DYi>(VzO1cs^55;%AkChx
KelF{r5}E*&nI7E$

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab53a413c699989a91782ca0b44add74e7d053d8
GIT binary patch
literal 680
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU~J8Fb`J1#c2+1T%1_J8No8Qr
zm{>c}*5j~)%+dJZrAoSdWdemA0dsXax;XTLjw(fH<hF*%`sn>_QsedP>R$XHs^CNN
z##av>ty$f?T7jdk!NS@?bC*Zwe{U|`BpZu&$9Grv?=Ek+u)^T#8!7gXvqnK5XUsUe
zwyQCmL&AY$v&6I+E7dP`OIGx)um16)O8jZ$z32aA6jk$$4yX&AH@v%{!@Og;x$fN0
zc7-#hs<i%?Q*mYiw~&2NY}wD=;){um>219}S@SG>bi}M9-X(+?g*?)H)UhaQihfFL
zm_>eJn6~M)UF!9T2J6=@+38ozQK+NXsN!;B#ljvg9hc0j9)=Sa{hiTXf8nG0N!7`#
zdEEL~Ll!y}{drLTVR!Uq1IveMtjP}FyL0P%7#d?2L~eikKKXXuJcfVi54^H}ujWm7
zHu+0cbhiv+?d=0cOQR=$Z#XTR@W69A&&i2@Oj?~7E9@8NpJM#G-QoSL+tJzb%lRGJ
zc17)D<l}3+sFb?Cde83Vo441W-}37><L%y}i{~y(+zgBtwj^(N7l!{JxM1({$v_d#
z0*}aI1_o|n5N2eUHAey{$X?><>&pIuNrK;!=jwr(pMgS4JY5_^DsH{KWysf}Akg~o
zV#>Od6&X8vw=ewY)1v&d>!$RYMDtlI{)Y>lXc1qKcm}8i2tMdtzSxp`+iB9y-D_W4
z+3Gg@%xF@Ho_18l_7h7DuflVgcX@lui_1@29?yQ~=B4R&?EMyYh)xhG5tQA#`}(Z^
zk#F8jZ><emJD=G@^XODx;Yof!-^pcFYA$V2x&8faRJL$GNcFqd%uG&(DqlCaZvk;V
MUHx3vIVCg!04kv&+5i9m

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/meta.json b/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/meta.json
new file mode 100644
index 0000000000..5a9100512c
--- /dev/null
+++ b/Resources/Textures/Clothing/Head/Misc/head_mirror.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Created by Hanzdegloker",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "equipped-HELMET",
+      "directions": 4
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-reptilian.png b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-reptilian.png
new file mode 100644
index 0000000000000000000000000000000000000000..08e85f993a7ba0079843763fe8cb3bd809297bad
GIT binary patch
literal 749
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVA|s8;uuoF_;%L*Zed4}<MZz|
zx-x~c=<ZQ&6bWZJ=j4(j(yFbyDeBkb_zj!HyuaoLu)LjY|9~ryo7?i@WnDc14-4HX
z4UH}Ww%305?MaL@n|<cZyTTXc3TMvjJM(+r_n9|y?{#dLc%a_*!HoQG+Ua`kyUPAN
zY~3#Z_2Dgj)ANyk|Ne{4|ND5|p&#~>>T933*VOOQdhytx=FiV{E5lar^L}fU&frm2
zvrCu1-u7ip&2?kjXYIU<yX|KBsGNV-+$7B4`!B3|^XIhhvtxdLIq+qMJX_0;jqV@T
zhH=l$_1tZm!ZXb{$Jp0H?(OSqe;-_VX3L!TY(BTigA>=+#hAaZTN-3I&wSmzzGatJ
zO7^=cOIp9OWIQl2`(KUf-hig5`mrmoX0b7q$)9Iu|7Ilp<>Do~T^4h*$~zMuu2=69
zFJn;Zb#vapeE4C&tFOBf*x8yJSJ=L<o;j7_k;iBI*Ok-sZ-}u4?7z}y_x|lo71Nt3
z`*&?qJ3Rev>)&(SA3Sa{I@+7OxctmrD}l|KNyPy#3gBRzvS^EvjJ)`xn!d?9;%aQt
zBQ4WdF4$;9ytA>BcfD=?W@&5D6_*8!x*1N^>-&N$Z8X~$0u<iP-;wd2TjhW7mzeh|
z4#Kx86)UcPcy#i0Eu+fq_xE@&EEhHScxQX2=enD9R~q}dU#mZjEZ24jy*1^i?fRD%
z^BH7p|2*n^QQH{z!_ML9jx}ueFErF&4OzQo$CYVUtLHPk>6mu1yl(!~rFWk%%ZYQF
zDH9dd+NNgm?Rx&HW1qI^p8Y+~BA;P_RC`0EMBBESxRjYTk+ZI^HmuS=XkK|_4mX3$
zi`|`uOb7Rzc=Ax(S8>I$`^%5kXJ65;7E)luiGHYa{$YHc?EXTuF;5Pdj2S##{an^L
HB{Ts5ZTe8o

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-vox.png
new file mode 100644
index 0000000000000000000000000000000000000000..4923a4d9d5628b68cabb0974718ce162ca918cae
GIT binary patch
literal 811
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVEW|g;uuoF_;!|ews4@xasRCf
zGaSSj#lH!1?BERBup?BfB+}sG(*E@q`W5tU^9RPf*j4&|(F$(yrH``3*qAQ9a^jTm
z;95F0^Pl*+0#4(}JIj}CUHYH<<X+?Sca?wM&Ad5B`H&;i^H~R4^1lR|i#gxD{d>#P
zweF=m&WUGlSNi?`*6n-W^mj-d`^@q0?x}fyYVCAq<Vx86s`)<Ubn5-J7wys+IJT8<
zRm^68Egf&S<xJ1($!!h6@4x?^^!$tCLCyxY|2sBr`S|a){LcTSSI_LQ<K!s2b@*r1
z-abvK#h*MTY?|RSQMF6J=Ggn|=Vygan<vH5$uF+qa4P(rox%IMl_5s6o=>0O(tPm1
zn%#HTeUW)<$>?zE>bLt|+7q5#S?{|tM2n5dPyV~L^Up%Q8^=3-zfiIcefP-u*?RR$
z-0BR<SF=LDuq5!PUwB#K^0e~)=_L#goM*i&{A96rCgYjAnJxC^<%<=3t@w-?GTAkx
z{(L#pQ&YcrW@P@H;N{=s6kfEm8DBcLukFtjtN1O+T#sW|V@+IMDKiQw;6@hNECJF7
z`0H-Je%x{RTK@XaH?-C?F}DY3AF25IqCIARrLUS;oY*4!JCzcPMC#ukU2`$NYXPfi
zs>Rgfy<cb8^U8fa^lj<w!1oPdy-C|r_OZ&|YG=5+f$_qInUS8Sns+kZI9P8NBe1)i
z;p?G2%vNvgSZ-(tHJLZu+ThoJKcnH6^#v|Fvp|!xlUZ+Y%U)o$UUhrh%qQ)CeQxcV
zP%hG!wVll`BQM`Oz|&1qmU-#tEt|^bG+)SkZyx&mbhnZH&SW|MrUQ}bbLQS*c(7vH
zG0`R|r~3`l&et+H=-(^fEzY=0aL=uhtE>0Dd~-!{(d;*p>Wgcc3(m+%F}&NkZQYAF
z1{b!Q&duhL7w>Iz{hz*e>8HTgC-`bq4Es+Vi(US<_05?nPiyD;Hd*n>JXLXE!i83{
a^f9o6$I6K%oR|m91Pq?8elF{r5}E+LU2ypT

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-vulpkanin.png b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK-vulpkanin.png
new file mode 100644
index 0000000000000000000000000000000000000000..ad830675ce756c231e6f5add940d99cb17c5b36b
GIT binary patch
literal 819
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVEX0h;uuoF_;%L*Zed4}<MZ<l
zC^gEk=<ZQ&6bWbX3((0CY1P)<l>V}RzrzQA0q?bIT`$=EWL_t*b;AT}zrDJ81sjfM
zE@a_RX{u0sX8mEB<EHAFH+`k{GoOC*Zg!=;-RH8|-(4&`9_&{uIA;Fq)zaC*cddVX
zITqdjs$g#Ov#Uq`{rIqW``^v$+BV7^++Y92yKY~M=ovE}`PzNeT2s5;UrU*9%)ny3
z<Hoe~`nZyPZ@!)Bd7kQgU?qRM^U3003m&jIH1EHE?@f)x55?%;{%3)b4jV4Zo!cIz
z>vQr)_&g4yJTJ*jA%acEf9(6KvS-838x9_^F$)+p<9C-HulfD7=w`;f9e)#yq<YWP
z?!Q01aj~sBgU8Ni@5?WBtE{Pe?X@><`eIF%Id=Ds2me%Jf0KOX*Gnbq(07jx->LUs
zBJRiFCe_;pbVJ;8i$2$<mHSVxVR&#{=Wpiw%_WXz-|Z7hbI-E$D+uba1@Rr`lY1>@
zna0Xro%!DXbLu;uhDE=6zdd>VapT3zeaEBDI$XHo{J}kcx1W`Nalyr+{Pef>>-7J+
zvb+CPabUuSHZU-0c<XMqidnLEr?zwEod-U-Q3{Up52QTLyR>D(HoN!LHyU(r=rC33
zF-ZM+xbwB=eg{FnrH)N`Z#^5%Dk)Tix4n6=HJ+ibzkGgsl<}O<qrTjFulG8+9ys{4
zU3SghZFO;RrQ4lDmik8C+3b7Vl6ltUUp9KT6W@xzaIIFn7aksVCUyGxH(&L>Us(8S
zgMaP{->asl^{1wuy(h_Ve2dS&pHI42*w;_)<DGKW|5&o4qG|qJfwF)SUDig;qslWh
zx>EMk`I~uJFLUXCwPn3*K10Egwgr8e{S5PJ=N^iyKEO9Gbo;hr3?=g(EWEtZnML|d
zBSZ4UC&dBmg-KCv+pj<089sMIBhQ6Ek(8^`vyXW$Y*&~*spss4wKpeh>`@X@V8n?$
bR6mGEw+0643cSw*W(EdNS3j3^P6<r_vg&nf

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK.png b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/equipped-MASK.png
new file mode 100644
index 0000000000000000000000000000000000000000..7880a3189f3be8fe6cfc32463935011d67c6a355
GIT binary patch
literal 772
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU^?yT;uuoF_;%L$Y+*-{<MX#Y
zP;8WIlFRW_xFE;$RUv4PhFH~?30IP%|Fa&fcd)tD{J&A@#^$r~0RdN<+k-B?l9S?C
zv&D7`3y(_Eik#1~6{nZv9Xj_WimQ(O)a;w)pX+MM%xw3lA97^+Z`#Pc@1}q3ZsC_V
z-#s_KS9Yas^_&&=I{yC8%&-2v|HUhb-xL4*X19OxyF0USOX80kpKXJ6#A^GGJ)gs<
zaP!^OU2FbV?fdyO`LxHH^HNOrs@7khtdlP<GKV4KQ})-TXZfp-Z~F7Kb7I7NR+itl
zlz&96WfSbb{42sR&B)TtJgD`FVc#}6^L0A5Mgnem=K>qG<D>SZ@B8btFhS@1{k`&E
zf7cqnFR{8*`sFzbL-@L1pXY92%Jh*nTN<Jz$x-pULXPjt|Dpr-ZkPJ?@|M4fP4f85
z`Jl@8{2334Hnp2YJ9QNJGAGH~wBLI!wTw4n|L-M#_w8q2`M-8b{`JMpe`_bJsH{_-
zv&!Yus{h}%&AgQtWc2)-q{0j7HlL{Zw;xDKa86*riyF)sr!3l{lyiPBua(S}zc-87
zg@5L{GF){$SoHm-lgQgOM|`<|R!VGRk^jIt|AXzC()gw8c-3aQF=$NKrhm8VH|wNt
zPk;JU3q26tx7q2#x`#JUX76VZ%C(J+IcNOv^0qYjeRZwr=Fjy`pMDm`+!`4y_C4ov
z;XcM4RX;W}U#@Em`>=B1R_EyX*JZXnWd3$#`7OUL@6yLhzVkX5O!acTuwujS-@AO?
z<Z@ion4g{-Eh)O;mx<l8u++LD_X{!;k1jW7U|GqSx!p~GrSPXsKF5cpODl4FPtLL_
zDtIMukg;0fWPr*)nYJpHTerVmJ5#)smxE!ga{h&^>)wxa7p5P0UC`xRX7AMX_Kp*i
giUUqmFKEH|)6A)&`f{Z+Fm*F{y85}Sb4q9e0Jx@NWdHyG

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/icon.png b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..e2d75aa86cbf067af0fbc6c95bf2089c0ff6fb8a
GIT binary patch
literal 570
zcmV-A0>%A_P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800063Nkl<ZSPAWw
z%}N_#6oy}&K*0negyKR;il9Phi-Lj+OM4Mr)@$hAoty6U7If()xUjT~Lc6F65e<k5
z$wEtLB1u7TtUezc8I#O75nVY4GH1T;{JrOIA|;emAgRD}ufWhl3gAu7|L?Z*kAFSL
zSE}1l)Y$@$PfRG~dAF*UzOTCEKn)5cHUNSb3I(OpX;rILegFJV`{h%;nHtm5+K7t9
zqB@<9DmOp|0Wo}=MvNCSZJnPx&DV2NcR2UR2c=kjv+R#wywmdgSK9b}CGY1KU2e@N
z_3=>t!itt>hqdwbM3WcaRH;-Hw+gWV_|u<U@E?D&p-C>jY&j6#(PnG__qKrS=`R!&
zJSa!s2G$uyJVF8BAp7=1&$^kfa{aH)wpRrYBkavb7@!^irkKfO)Y{u|En>PM3sx@e
zDtoZ5TrTH0=b+s5vFC@+u$kyP1KkFkSwV&nqQ|y&tYxWG5;Fol*$`5Z?C7Wq!bhml
zXt;MCRKixU)oiNWZa>}-(nGQ(2+kpb=ks|72yS4Iqldor-WfzZ`nJIIaY8m^58<30
zryT^PA{I1wkFMF-9C6o=dWJBlgcE|nAuBWQc4s^&@3uo0Mv(xRTr%U&Cm4wAxvSS|
zj#~=|f*vyL!X`fmCb9*lXsgNDoW{K~9|=z?kW?V4Kv)H?0nnopr4R1E;Q#;t07*qo
IM6N<$g7nY?xBvhE

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/inhand-left.png b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..fe2901acd1f3fbfeb86d3b0ce614560665cdd9c5
GIT binary patch
literal 336
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU=;UsaSW-r_4d}<JSInxwukvA
z{OWx&4WeDNcdeA<S*hTgWw@7}r9A9zHG{vv2~pJ<rVW`=Op!vfazZt$%00>^eV?ej
z?~UbV_p=j$hJwI?rn2?%bCf^J?3{Gv!{3Dyx5mxB`0i`BMPZll^556Z-}@Tab@vM|
zU%&eK<H&6L%T*JzEM;eE&3x^ubz9P7(x&eVKi+IOk$xj>s^;#xU;O8d^=ED~4*2+U
z;rzo3_bG3f)917A_Nv=+UK`4<zCB0#ey;cZf0=37_LKMSxbm{%Y97nKJG-Voo>RA6
zIQY5`#6dt(!60=01L=k0@ul(yTVnR~*S2Upu|II!u8Fgj<<XJM&8JF=zXxPVtNz$t
fR>sc2@boX!G5hQ-Zx$r41R3G!>gTe~DWM4fdm53a

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/inhand-right.png b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..5615899ced3a6b6cbf8db2633243ea187bfb9bef
GIT binary patch
literal 343
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEV3hN8aSW-r_4d|6KW0af)`!Mt
zd03n|(;ONSn3J+rad3(q7Ebt8QOh8=pdu*n`mDB=HJOGjIk$2qcew`g<V<JX=={$=
zU+ww5nXA8f0Zj#g53P?+&sJKtCiL^RRbshwyBBe)U*F#9-&7-{^>l0M(cda3N~>l&
z|H)GEJep%+;G5g9bI0Y?OTO;VpWm{!GWTZUO`FhN<^O&b&NKV>bN%t!$mdV2Y*WvF
z|LUG#CNraEXTWybtC9Z}<W;W%vM1;NPY$_zZXI9vVz0{WV#NaM%#=TvRhszLGj4p!
z3ULq6$0A9$B!Bq5Hg`R~$vEKHzb!u`%Gv&{VGNpM&7A5pSMY;pfSLc+`jS=Cmv<)Z
k{TszQ;RicE!w>y?jAw(>t~$(pZ2>aL)78&qol`;+0Nr4bq5uE@

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/meta.json b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/meta.json
new file mode 100644
index 0000000000..2467db2bde
--- /dev/null
+++ b/Resources/Textures/Clothing/Mask/gascaptaincombat.rsi/meta.json
@@ -0,0 +1,38 @@
+{
+    "version": 1,
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github)  | vulpkanin version edited by Floofers. Vox state by Flareguy for SS14, Modified by Rosycup for TheDen",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "icon"
+        },
+        {
+            "name": "equipped-MASK",
+            "directions": 4
+        },
+        {
+            "name": "equipped-MASK-vox",
+            "directions": 4
+        },
+        {
+            "name": "inhand-left",
+            "directions": 4
+        },
+        {
+            "name": "inhand-right",
+            "directions": 4
+        },
+        {
+            "name": "equipped-MASK-vulpkanin",
+            "directions": 4
+        },
+        {
+            "name": "equipped-MASK-reptilian",
+            "directions": 4
+        }
+    ]
+}
diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/equipped-OUTERCLOTHING.png
new file mode 100644
index 0000000000000000000000000000000000000000..497ea69bfaaa6a8b902094bd5d5971374b17f8a6
GIT binary patch
literal 1318
zcmV+>1=;$EP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF000E-Nkl<ZcmeI2
zKWJ4+6viheg(Lw3k6<AtsH8K3B5t#VwT(@%a90qltSoF&h=o|#Y_XM<u&`<&+iYWP
zvCV=g7#k5?UY0Eu2`D7N!tlJm_xP?S^X9&HXWo5*;0#=5=FH6b&iUrgy?17u%ONw6
z8ORJ|1~LPgfy}^n%D_a5--k|}?|gdotZeJ&Q*_pC16EaCYg1JnUw*(BROKJ9E_OOE
ze(J0}IM-QNSa33gm^^aIsaK_A6ghgqXti1nJpVyXc`Sa}i^Gh=xw)(Vb%D3Gw%o?X
zhJ$ek0DNX<#;vcfyN|yeaT8}A)z&)<SLNWJx;@#&kj#%E<<*^?DEwL@04Jwb-Z&h^
z$xuK}IrTI;LiJK)=sR)qvx9g7j)J9!Jb`lR#o!Mm0A&CT3h#b7=>EE~T~?ufj1gtS
zKtlM8I3C&Z=g<E-Jv2jZ>(s>`N<hG-KGEx!Z{6D4|NG=k3N|-4cc}yK<msh8T)*C~
zMuE&g0xbKqZMWMc(^l7yzfQYbf1mA^BUew=?FFmLrhR;zL${^^#1ph8$@v)kfdt4H
z6z{x$-d)(FTxG->ex#`<L&!G~EI#_M0m3gnJlc)PE5zbYsbMJY&Fk%An0;`U?|rLr
z_lM{1`qN{jz|a4F>4RHd>T$b#t*jQE2;qxt>okgyi})D)sMpox@w1)T+1awk?Q0N&
z{GN*Tct`{Asj|4Z*jJP3Nzh2`t56}RH3j^(^tcUv-j+3;rUP&mOx^;-<dLU@fm5JL
zA@i@8iDj{$FAK($z}f3h<?yk>`E;P#Bft)SzsJcl2Qf^;G~J|dOW}u0d(ssA+5`Zh
z1&AKkf<sK6HGuN{7NQ8SD=#Z8K{07tPJTaxq&0v~->H@PVz|$Dt~_z>%O3~b+|~Wy
zZoiGSM*uy|dzrsI{tETFAtsNUayugW;nF3-M*~yMe~_o(*ZvN$pS9X}U||vwp>m9B
zDrgae=&C?R#D0s^CLjcA2?&*sLuQHg^{ZoidCq4BG6R``%s^%!Gmsg`3}gl}1DS!$
zfX6`e-(c0>*k1pMHDyQAj*#8^<5--q?si|A@Q7|Si}UtGSjtnj<f2D_E+8x~9d?`v
z5+FqP1I9fP<h;%U!Do|12eg;(wWEBB8UZ+u<DAN}`=XJM!aRnj201VM-j>`_SKZ@P
z*NGt^ihwIm=8L`m>EeRIWOwU{?WfQ&RjOlk+p#J8`sH?UINB;tq<gnVrVG2~3pMS!
zs$A_&QL9nM)2YW%R#!?|!=1LWK{mzeiy8q{${C7#ISp8QS}l&}Mh{6Nz{1LL%|}}{
zuC%a(Jqk|L2w-o%ckbW2GoS-X47q>dpIvtbMlotwTh1cw{e*9JxxTv$!*oTxGD6$n
z`XJFX*o)VouyD@D3)wh`gpsF!l=~;fl8+;9600!+?1}L>oR&_VMk_yR98Ca2OrUo7
zH`y!FUloI;Phr_WU29uaTVEc%23Q5WgEb$CxvHYGLR+uNG*0sI#li~-+)!my*brkw
z^aub5$MpeXUq$0O8Me+@3|-r`_Sm|0(n$n_6mwz8zM4XHnvj9Pr*KmtY6|FQ2ylLg
zY~Y8)e<j)SCezG&|Cn62M!7;8^D`7hfL&xX1?1RXIWIiB_#w0FK+GB-eL2nyWCk(=
c-z5WI0bv7zQ2xVC>i_@%07*qoM6N<$f&ie4<p2Nx

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..7509dcb3db6d94b1bba85ee40f853c3b6ad2a5f6
GIT binary patch
literal 535
zcmV+y0_gpTP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80005rNkl<ZSPAV_
zJxc>Y5S_#nfdmYMR6-7fbSfx8TYp5b@B{J>Y%MG;Z2Sp=AX<ox|G>gV2nxnVf<jJG
zgb+|jtd!GtGRN+6w>wE=;Z1Y<cHg|6otfPuN-fR6f6qW>ngq-)tp}#x`@{8AT3J&l
z37_wIL2$Pfw2xPVYPG7-fH9AC@U%q-5JwI1QnN?cY&;&*a5$vVXhg+gk;>&V6$%CN
zeV^V=<|wmrCe{^Y04dKkp2Cf=Nt|IGfq)lRqBtMSIRk(ggl+bGl&72BkB9=kGzez^
zk*a0zc;BIRr*B~-FIj8Fr{{V@#`C<e{upx)V2o3DyIl;UzJQ<Wc8D^7jlN!5VXzQ2
zO9G5}7<k}I%^CpedbRyZryB!J?_jNE#o)tF?F-F80oD>Iyl^-(Uk~`&aal~vnKFHo
zur&ioPOc0j`Nhpo6~O*&UDGnLw&(!j0MzuyWdMzca)9U9Q(G1X059%#oR~WuU*Ndg
zq3x6aCJKPB8npOk@E3FHI<UlY5|YWm)0=Bl!s(rh3VmMYsnj%CGAs@NCta*%X<@nc
zvsq752gYCU_embm=ApK11>$!={kd@cRb@0Fo9p>y9=_rLK$dj)qz@5vQ%f_DX5ddV
Z@C~9M#>PmSi5UO@002ovPDHLkV1hgP?g;<@

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..3079c4ca6d0b79dcd49b3aaa125469a2a1176d46
GIT binary patch
literal 759
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVA|*D;uuoF_;%Jt@7s<d$Ms(Y
zcpOmdNM51fVX#zeVfJpX=}IL6Zy!CWU$7;aTkqUE-Ca|I1g_uO=$dg+h|BeKzn`lS
zN9Szc&wpQ9pHu$(RIk$B^@p5F`S*8scbCuK{rm5O@8=}cgcKNYq8F17d^nPG`#o2r
z`Ofvvum67e_%_E%{#K3F7dh+0ZrzXLnR#pSb1^2hz_nq#Pcry7GRtl>{aA7D+evN@
z#VadyY%Ri9hOF`07-90Y>TbfPwPB}EO;#~{e*E{$<X_uzp8Gxg@p$){ee3cvB6Haj
z9DD>abAL@fE8W{Rb@`zK_BWjF@44LZjiKPz)8{w)Zay)R&k?G04!FsfKY#8F{_g#{
zr^ETbU*7a&#RA!?y_2$6-^`g+v@@rE@2_u{*HtYmsPkSL^vYnH!94B=N1r9vZ+@RE
z9=-0*mjwT-@i)S5GOnAfar%_^yY1~)Qn%k(CEIX4Jh$l1o%+A#v4v}t;u_oS|IcXs
zs*?3}$@?#7mOKru*dUsExa^F^3aOUM5~uIJyPG2UFD7%+zI|u4z1B=%;KYOO7%<kH
zE#3d(-UjQLho1{cIJ#(<smy!%v|ehrV_)lfDe;2GKOYr)c*K+>7jYia*)!j$-8%nL
zWx^+pllk_41!a0pvNjxH-YEQup`r88wk3}5lvl_$UaaoFHKXF*!<?BWMF(7^p4c@>
zF_?FBW*7uzc-Vx#`^<kp|DCeL?Bg?nm=#v{%P1Btx%FwfQ%-=%k;?CUj9*l_bS+aB
zez-c1@g1{(fZ6jpSNE2O6+VYHCtUc=krkfOXZ9}Q{{DK~*DWWGTYc>|&XO+DN_aYb
z(#8_?HE-_qO1T2#%k<8~y8=74uj`y%9q`z$X<7XBH0}$vAMU1He<r}btCi&+V}zmp
V-f3(%p8^v!gQu&X%Q~loCIBihV{ZTe

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..d74e6a4eff7b242b36a14109db4e8e5a1c12b4ae
GIT binary patch
literal 709
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVCwO7aSW+od^>BuH?yJ0@#MD(
zTOI@)*{HEYM4OK_{O(;A_Ih1Ezja-GTzdaRo0=ayc%;?Tt)!(9>$1?IvqT`ud~F@G
z{*v@}?Mv^?{lP1<vwG)~eea9)Eq917jqqq-!G-?WHr{*a#oaF6a{Ad`_1x=;vy9^o
z{?0yn?W~*IR4>)kay@_jOzT^FYcG}LX3Nc+#d-Bka<}{Qq>ULqJ7fGpSBLU0zL_Ic
zy*4cPegE{_THoYD>IJt{5Bh)J&f$=LCuaTitG`~Xl=IHI@js}MKXKM(M?PISo)^!~
ze(quuD#?$!_27%YS2W9;v-?&oZdJc5e_bP5c>1xnvW?QoU4C4xO_LU1%*aS}oHh5e
zM7E>d{BR?NYpfHFmPS3_x2O5v#*^Dj6?}@LSxzVfou0i-+2PiusMELIdzI{dyexHN
zuq%B!(b06@--Y)rl$hopyZt-ebbD~|w~y5hcfMV_x~H>Y_v`A%&GY$|8-LQ>diZYY
zXK9nn-5ITXx7(MLe*CH8z=Q_{ay-yq|982$*ZdXVS=8L#IR0_@GtHoK+mhFB*KFNV
zy10+U!R5%_bcTY7GtP?XZCUS8`+Mnr>(+-pJvW*iTYT-$*)o61S+Zl|>M14HAD>KI
zk$1a&!DkP_2F6Pp(iu3TWbUzKOlVHbZT!s~GxzZw<Ax(?l`5a7-Ve4i&UJsZ+B=4Q
z+Xaq>jwRoC6a=H=_FZ_`r>P*=uq#^iQ_P_npRDr?Vh^W2R@}^X;Ah@i=7oX}RCRxT
zv-r-FaBJ?`eJk7V+7(xnmR8AHGEKT?+`zGAZjbF-UdA{<z1g~xo~ul#W19alNpDiR
Tn8kNs@?`LI^>bP0l+XkK6NWx*

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/meta.json
new file mode 100644
index 0000000000..7941023219
--- /dev/null
+++ b/Resources/Textures/Clothing/OuterClothing/Coats/cap_trenchcoat.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Modified by Rosycup.",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "equipped-OUTERCLOTHING",
+      "directions": 4
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/equipped-INNERCLOTHING-monkey.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/equipped-INNERCLOTHING-monkey.png
new file mode 100644
index 0000000000000000000000000000000000000000..a2581dab5e38f16c496645e7608883d94ff376db
GIT binary patch
literal 1183
zcmV;Q1YrA#P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ$>+#1v`j1WN4i%h>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<`9$!jB*Z5y61OOg)ia%)oPe-NVP%yC~1{KKJM7SMnwUd?N82(+!JwgLr1s
z(mC%FhgeBch|h_~4Z0xlBiCh@-#8Z?7I<dJ$fV|pL&RdSgXIopB|{~iCJrmAM)^Y4
zWrgz=XSGset$Xqp2J+fUn(H)25yuh|NJ4~+8p^1^LX=jG6cZ`hk9qh<9DkBrGP%lN
z<XAuzDkR4b{s+IiH49UdZc-oybidg4M+E5E1)6o+{yw(t<_X|`2ClTWzuEw1KS{5*
zweS%T+y*YL+nT%wT<!qFPr77Cj^w8)6bium8GTa@7`g@e*4*A&`#607GSt=b4RCM>
zj1?(+-Q(T8oxS~grq$mMXvuP;>U)db0008kNkl<Zc%1E;O-mb56o#KjS2m&+T8K?r
zvypBF!i3~sv@pbNH!ZbLyHMz^_zw!nqS**`QMZ*q|3fwj3;`FGZel*FML~spU|n>&
zD0i4>qjSfMw)Q*_E^}|@yq9x77<dl|f*=TjAPD}*7m7~4P;@Tp`&abGbj1O3mPNi$
zbefGFCtoN!Im;Rt4~sDLBRb;AhYtX#H=5)ui&nc%BA#TURKh#9ytL>$u8w{-lLDYp
zt&z>7&a`SwNB@@2Buq2S)N~YpwGZp$EQ^g&iRaIr0&sNLrQT@jgw!GtPck(f#V`zj
zGwsn~mrAv!71LLyRQC7x4!C>o&d~p<aott$tM3;becyM0VHlWZno6}sBA&!B4EL9a
zC#h6xm}c5tjZx#(8K$rLb?|irY}>}RZ2;Cku0?=>6;T<tZ99}pFid^zZTk6j%oUlN
z9pmfvPj~Fe``wXWe&^|*CWyY)B?$2H`(q-pS;lWq&~J1Yk516<b#QjKfmPjb+6?IT
zI&K?OU+X*ICZd&q*!+TXGC2c4zt`bM|Ac<81Hj4T46*rzP(Osi(APdQ=ZWloS`GaU
zxNdzx5ClOG1VIo4K@bE%_#e4SJKPUfW{-QxW>Pd8J5IS=c5UjQv2;<^xYE|~4Nns|
z0m>FvZ5WpLFqW4VBVO%9JQ+Ba_N2Xa0)XolkJ=HwXbx)C_xBFm{vfppfp&mtrl~iY
zt{WVdBYYl8*E^RWXnBJw^R0FrfL6Oss~t%9(rj*S4m`Kob+VZh`9jeNtwIETXI@oe
zsEQ4MOeO=MB_4!)q3A5WdcpDWF~FI*=vIhmCBW;`o2EIi1ESHWmhffR+S;Pq?GE(4
zU0DefEAVRl$)}&29pllPZ=vphFYoR<-kJnO(AtDRFU95;oM9e)*aqdOwWU5l_l4`M
x5%??W1Jp!@ja|hNxGrr$5ClOG1VOk#`~tg>%2;x}(FFhi002ovPDHLkV1h)pFNXjC

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/equipped-INNERCLOTHING.png
new file mode 100644
index 0000000000000000000000000000000000000000..b4d2825f0dad12ee6ba528a6faf710415bc5ee47
GIT binary patch
literal 1338
zcmV-A1;zS_P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ$>+#1v`j1WN4i%h>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<`9$!jB*Z5y61OOg)ia%)oPe-NVP%yC~1{KKJM7SMnwUd?N82(+!JwgLr1s
z(mC%FhgeBch|h_~4Z0xlBiCh@-#8Z?7I<dJ$fV|pL&RdSgXIopB|{~iCJrmAM)^Y4
zWrgz=XSGset$Xqp2J+fUn(H)25yuh|NJ4~+8p^1^LX=jG6cZ`hk9qh<9DkBrGP%lN
z<XAuzDkR4b{s+IiH49UdZc-oybidg4M+E5E1)6o+{yw(t<_X|`2ClTWzuEw1KS{5*
zweS%T+y*YL+nT%wT<!qFPr77Cj^w8)6bium8GTa@7`g@e*4*A&`#607GSt=b4RCM>
zj1?(+-Q(T8oxS~grq$mMXvuP;>U)db000AVNkl<Zc%1E;zi-n(6vw}*PzlANw4#+-
z`a>Bz1R+N-vA~X0D_vPY>e8j<Z|I(Y6d@s%fv!Z3)P;psNS#{c6p^6|Qsg8QsjZq|
zg%UFO7{Xc3FXMB4Nn7r-oSn1%eSY`O&iOq+B9TZW5{cwLCB%C|BAKE9u(rAqa{Emb
zOe?NwNb9=Y`qdxuE1pQEXwf*NiDZh#HLayz6i$6YvMsG}edi5l^etL64qIAhzes(i
z(XI8P?<r&w$rOF~;69FzP5}S~qln1-Tt^E46O-fE+s_3$9oqFLCdUB)ilU%as{ueu
zU!eMlWQv-mNlnwVz0CF-jYiMDpdvxE{xvTL<@0$QAD!AG-D?DlQW^8JGj@Mah}3s=
zKq8r<FP=X`wNk_0ehvVjsxjOiQvd+ra2WM^9RN_R)L@j#FiK^pY7Eh66aeUXLa`tE
z|BQg`PoGgRidb7+3B7v#h7ywPIRchtVQqCKWLXwv&xG?LTHn<Hgb)xy?0w6!Tt}c_
z6uX}1mwxEGI$-ntMo0L#jey&Ee&~n3r-z^uFC!q5p!K;NFh<sq`??MQxH}2l92vsT
zGYj92{`Q;P`do<6_Z%uyOUv{|^d9ObCc<}a^=yCTzu^0aw}Gz-MCo&_1+F5V95A)C
zOdF%qsGqpUSpCFAV{{r*OUr?-2Sn;~O#uLCj85bF$S{7NH9FeiABO-SYzm0b=Qh;M
zyCQD<qUlQ{5{X12kw_#Gi9~V*@U?zsc{gWbbWwZS*R^;?-=fasEa0y`fcvvJBQie+
zRgD2?eyU~$i7t{zBvZ6q8-VXm^4uRqSwTd>D1wkIR5b=dvgpUn1I<zHrp<~rc(2E0
zFw4_-Ls1lL@9g#^0-ij6WM_oh;jIneo&vKo5j!*EBpeQ7duNyTa=uttSg<ofPMld}
zuW&oSnVZ|&&w)jRqI5b%6bA<fb_6(WaOMZS;yX9E@op1wO>4>14I%<&XCg@JI#?Y6
z@5At15zwBg?HA4nV582eNO<9PKw8h(+ZQ1Ms+Ahjdd98?P*s)dTHFqZYm4@Fsa!y*
z+}s{i1hm^Ed<w8X9_?>}LB9p6m8L_4I>4Eq@7gc8K7iTq@nvu}T$=g-Q8vi>051m(
wx;{Xp4VR`qK$H!au0G(R*dUQeB$BJZALC<)6~JI8k^lez07*qoM6N<$f{?Cpwg3PC

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..b5702f2d315a65145e95303190213ad15d400f79
GIT binary patch
literal 842
zcmV-Q1GW5#P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ$>+#1v`j1WN4i%h>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<`9$!jB*Z5y61OOg)ia%)oPe-NVP%yC~1{KKJM7SMnwUd?N82(+!JwgLr1s
z(mC%FhgeBch|h_~4Z0xlBiCh@-#8Z?7I<dJ$fV|pL&RdSgXIopB|{~iCJrmAM)^Y4
zWrgz=XSGset$Xqp2J+fUn(H)25yuh|NJ4~+8p^1^LX=jG6cZ`hk9qh<9DkBrGP%lN
z<XAuzDkR4b{s+IiH49UdZc-oybidg4M+E5E1)6o+{yw(t<_X|`2ClTWzuEw1KS{5*
zweS%T+y*YL+nT%wT<!qFPr77Cj^w8)6bium8GTa@7`g@e*4*A&`#607GSt=b4RCM>
zj1?(+-Q(T8oxS~grq$mMXvuP;>U)db0004jNkl<ZScUDC%}N4M6vux`lv(se3Y8^3
zKoO$7$6(LUrcJ$rd)>GR+SInF=g=Ak+Xmuj6Ik>ylufhnwkTtyChskzg86L@bI+ag
z|DOZ*UI+*X2>5RliX~AfmPEfbS;DH~069&gP%H_vZizy%ByyV8lOKoyuTY~|Bd2LS
z(Q8b_KuA`6ExXE9>jr>Y-DEAhO1WaZ$5e6&fLMHna>ZbKYg4MWl(=o%!nSQ;)-7Sy
zt@m%&b$xTPlNjo^LDzM<-FG{0G(X>aa#|(1m>?FPLDzMu2KyS=-`foV0wA4EvzSOR
zH9ZbMBoe`K902ZaA2>O!a(Hy?{qN@nyu~t^jA%4#z7yzlI?}>Q2D}1aO`u#cRLZFv
zfY&4FH-Yb<Y~WWXFs<h?&hr2)#9=HN=CR%3qV<-ymG$K=B7nK|4KcdBf^%&XnVs;B
zPiIvw4|b&MD!m1RK<UWLt#1f-a-NasFwbrGLma-hl)6_o&^6(gQxy*g2>27c0ME?q
Uy&tYp<p2Nx07*qoM6N<$f*UA?#{d8T

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..921ca6fbe4882156e67e0872e441d282a3954ec2
GIT binary patch
literal 893
zcmV-@1A_dCP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ$>+#1v`j1WN4i%h>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<`9$!jB*Z5y61OOg)ia%)oPe-NVP%yC~1{KKJM7SMnwUd?N82(+!JwgLr1s
z(mC%FhgeBch|h_~4Z0xlBiCh@-#8Z?7I<dJ$fV|pL&RdSgXIopB|{~iCJrmAM)^Y4
zWrgz=XSGset$Xqp2J+fUn(H)25yuh|NJ4~+8p^1^LX=jG6cZ`hk9qh<9DkBrGP%lN
z<XAuzDkR4b{s+IiH49UdZc-oybidg4M+E5E1)6o+{yw(t<_X|`2ClTWzuEw1KS{5*
zweS%T+y*YL+nT%wT<!qFPr77Cj^w8)6bium8GTa@7`g@e*4*A&`#607GSt=b4RCM>
zj1?(+-Q(T8oxS~grq$mMXvuP;>U)db0005BNkl<Zc%1FpziPrz7zOZS=};;Z6ch^n
zsSgk+k@hV*h+XZV(4|W|cJH1nS%fa_+9zr0rEg%9K|w)EK*y#-QK%-yCLijB^8*oX
z;N0+e&5{EU5fKp)5fKp)Q4*Hz1eWatVe3ir*4-nGJ&6#@c7kT3vGV$V^P;Xb8;!(6
z4I?sunZ=un8_cG%R>`CduxuwdKRd-}I0gU|ig~=geE<Mz)yki>yW5-C{TB0jt_J`J
z+hd))IH^y7QVQi#4L#R`Y1UyF20HB)I_(xrvyPtYp<Jp#DU~R1mSq@5qP#e%CkOzo
zt4?5=CTi6R3dQ_<eKZ`S=Xy{|;rZ!t?Y*S)Ho~%<z;pY7@B8zQ=k^mnwWaf->`R6z
z^}h6r?NVMCu>s`N19Ai4APZy<_b{1$BR2uQ2D_0LMQi}~(+gy#C&0)DvPZz=_dA$=
z0_bi%FN)}c<oNP>>Hj%+=_cMoI**8mh=_=Yh=_=YbSBXu5PdzqNm3mGZ3h6zbO^M3
z$spMw(DDRGb_ldQ0f43*0%;N*0?~fJHl*zkXgvUl4uRGKkmwL-|BzsZfYSK^!<=3?
Th#FN(00000NkvXXu0mjfVq%#8

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..ed69a4573879784833399193fc173927945eaf4f
GIT binary patch
literal 921
zcmV;K17`e*P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ$>+#1v`j1WN4i%h>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<`9$!jB*Z5y61OOg)ia%)oPe-NVP%yC~1{KKJM7SMnwUd?N82(+!JwgLr1s
z(mC%FhgeBch|h_~4Z0xlBiCh@-#8Z?7I<dJ$fV|pL&RdSgXIopB|{~iCJrmAM)^Y4
zWrgz=XSGset$Xqp2J+fUn(H)25yuh|NJ4~+8p^1^LX=jG6cZ`hk9qh<9DkBrGP%lN
z<XAuzDkR4b{s+IiH49UdZc-oybidg4M+E5E1)6o+{yw(t<_X|`2ClTWzuEw1KS{5*
zweS%T+y*YL+nT%wT<!qFPr77Cj^w8)6bium8GTa@7`g@e*4*A&`#607GSt=b4RCM>
zj1?(+-Q(T8oxS~grq$mMXvuP;>U)db0005dNkl<Zc%1FpPfNmZ7zgmL(IFB71%<#r
z`2q$psdv#q>}m&vE?w%_z590AMd(u3UP;l9-oe@q3JMYfJ+=;^nbY~(+;WTW2W0S*
zx$mCM?eIJR5fKp)5fKp)5dnav8?L4s?z*+42%C3j)sHnB4c~)>N*R+)@-8jFRI|~T
z?L6K39cbIa<jpKDXu9E^o*ZL17y$qZ#XO#0-T(l#YUS73&GnUM|G&0rUe6sMgh07e
zgK61N)jAYKL8sk9r`>|8)?r#U%B32F5V4+^tWEPSy@IWaj;pFFYSjt~#r$l2I2ggS
zYzQIn_;A1Vt3MS>UQIV#+v>TF<IFy`)l2kSAWYs}zb}P&^;9&;!sK09fSkBPt`F>G
zf$aVc#*<Iv#=u8Eny^s|n|EaaZYO8ROpbt|17r_?@%Pr9yaVV)8a@hP^ZGs*4$m(=
z|DXO-H!%;tMQO`RL_|bHL_|bHM3ii4n;DSd+a90icarmM>9mn90PxdmpYOpZd0s$<
zRMTLw2X9(70AN{PJ_$1eK}g*Ji#_;h|6Ng(M9vHZA$_&dHZu^5w9O32@SP7>CT%kV
v>jWx5+GYl11S&w<W(H&gerT}=PyfpoWqo5&-alFE00000NkvXXu0mjf%{!=7

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/meta.json
new file mode 100644
index 0000000000..a81e5b9477
--- /dev/null
+++ b/Resources/Textures/Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi/meta.json
@@ -0,0 +1,30 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Borrowed from QM turtleneck at https://github.com/space-wizards/space-station-14/tree/master/Resources/Textures/Clothing/Uniforms/Jumpskirt/qmturtleskirt.rsi and modified by Hanzdegloekr (github) for space station 14",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "equipped-INNERCLOTHING",
+      "directions": 4
+    },
+    {
+      "name": "equipped-INNERCLOTHING-monkey",
+      "directions": 4
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/equipped-INNERCLOTHING-monkey.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/equipped-INNERCLOTHING-monkey.png
new file mode 100644
index 0000000000000000000000000000000000000000..2cc39c88940baeb9832fac9a58e4f04b2092128c
GIT binary patch
literal 1277
zcmV<Z1OoesP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9X>4i*$~$WWauh>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<-o+;YS|^5ky#Grk+SIX5cx#?&0I>U6f~epZjz4DtVIuK9P8i>4rtTK|Hf*
z>74h8!>lAJ#OK8023?T&k?XR{Z=8z`3p_JyWK#3QVPdh^!Ey()lA#h$6Gs$PqkJLj
zvch?bvs$UK);;+PLwRi_&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs
zax9<<6_Voz|AXJ%nuV!JHz^bYx?gPjV-yJN0?oQ@e;?a+^91le16NwxUu^)hpQP8@
zTI2}m-v%zO+nT%wT<!ovPr77Cj^w8)6bium8GTa@7`O$3Yi@6?eVjf38R}~J1~@nb
z#)_1^?(y!P&ffk#)9UXBLsoK>gn$H40009tNkl<Zc%1E;%WE1@6vjV8F%YDA(SoVA
zx(VG3$cX+IT@1QyDGhbeP)MMgwgj^3s-RHZ1X4<}P4KVCMqv=LNa@CB6%v|95lLM1
zb`kC{zLGgt#}ayeAlJF0=ewT!Q27qPFbu;m48u4hoym%HCM$01yDR!rRB-@E7zWar
ztf*ERBAv;Kgkf~ucMCW4Jrwcqlg9vnQl*N7VW3toAs7f_KbM33-ul|A<G2+4cq{?{
z$QO!;$0B{LyhqW$M;U~!M=>|=0|0D)-9^GMu%F9e<<)Zl!1-AVrAn0&l0+~N#@xIQ
znx+9jUweMmLcUNW#dMS@nf;UFQ#^RMF!XiuK6MtH>N|y^@AwSRG!42QMZQo(Fc5~O
zY1Shc2qRx8Lf50#Y>XSb&M<x1Pr=a^FijJtX#xOtceXtMx@JUX+%!#B4na5d$;<TH
z3%^*nfBk$pG=(4KKLCK!-@wbA=GYIvoAm9d>XQyZ0C?Yi2G4Bh`l13Wg`!;sutg0=
z#;$+W?qGVxJCZ)>cYvL%cBiYotB{tAKbaC9e+XCY4!jo)tG_e5gy|VCM6-<M-j-|I
zpjY3nwe<FrP|+uE0RVmC{$xsECZrNdi9z~}FCUZ=ue=5R6~ngN;>xD*CsPyoKf*8!
z!!QiPFbu;m48#0)OwtZ_!o=)xJMmZq)k;Gg92{6SwQ4LX(i)fA6yLBH<pfAuT()jl
z;=@>9TlLtrgMqMeEb^f3bpik^w|Lx+@NHv|vwm`XYW1tsCMc}{U5}zvsakHZTaNHe
zNL~9_R3I56GV`^12>?*5mr$!K>5k0d;bGTxtzJSr7C}0b6|Pl?0N0t9l^C*O0{~*N
z7yyvORY+&DV)e~yTwY!RK;KxX6(Xbr*nN6k*Sl7L&*vivkHXQ>5n8QQSKr5t4W(Gh
zvo*-4Uk**->ARn<u7K~K9|>8LFb-X%H!ZGg3hB#B206BF;7_K6bfbIqe{FA)waMQC
zgAB+?eRu$9?rnLz7ma}?sfsx|vO7G<4==eX2~@}l7^nES7-bTaSAh4T0nsd5l_Hb$
n=A~Be7#N0O7=~dO#yNihi6rQ}i`JN@00000NkvXXu0mjf3Vuw^

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/equipped-INNERCLOTHING.png
new file mode 100644
index 0000000000000000000000000000000000000000..8e1557db217275f2cb2dad3dec9bb4152a28e528
GIT binary patch
literal 1449
zcmV;a1y=frP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9X>4i*$~$WWauh>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<-o+;YS|^5ky#Grk+SIX5cx#?&0I>U6f~epZjz4DtVIuK9P8i>4rtTK|Hf*
z>74h8!>lAJ#OK8023?T&k?XR{Z=8z`3p_JyWK#3QVPdh^!Ey()lA#h$6Gs$PqkJLj
zvch?bvs$UK);;+PLwRi_&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs
zax9<<6_Voz|AXJ%nuV!JHz^bYx?gPjV-yJN0?oQ@e;?a+^91le16NwxUu^)hpQP8@
zTI2}m-v%zO+nT%wT<!ovPr77Cj^w8)6bium8GTa@7`O$3Yi@6?eVjf38R}~J1~@nb
z#)_1^?(y!P&ffk#)9UXBLsoK>gn$H4000BvNkl<Zc%1E;KTH!*9LK*US`WOa5FtVN
z6XL{xF-LTA(Vc_~tS*|cuz;I8d#g!fLV|;=kZZ!?BE*CV(n~`J7L#&qEd~sQrk2v-
zo<n($*HUWV_3mo$eU@wQ_3rz--}~M5?!G@jB9TZW5{cwLB_O&%C>$XGFh4gNXtd5N
zsMeIOW7RO&(y4xjQ}IwZLQ+<igu)RrrR!DWUcu{|W~^%IxjuiuQDcpytZdbiANNw9
zYSddg(Qm3`Lg5H`_Vfu34~_r;Nh^hs;h{@Q0O;-O!Pa)%)zhI?zqhXk0HCTW3WWjy
zRE@c+9|}iEKA$J~e4b^QelM5HSB|+=30~{pXy!+WL;{BgM{K6AngJ`F!SLV!8+QvY
z^&2K26poNLuV3LfSHRYG8~~tc<G9zY0ss_6L8(*%037EEu+kY==?pY&9Ajf+06<zP
zML+caS^?`{zaeR*Fh4gNc>m!eG0oVOGho{`=I3Suwrvx7O=uOb^&2L@G)<VM$-djR
z-EanyR;uoHPVqy(VFH#vFI_61Ml;Z8J16*|-_%8rr<ob>61Vk*63}ffApU&;0PwI6
zxZTx(-$ffg4$jB(!umpZp)Ztxcf|>GK6(rQC>>s?DZO_90H;5904$0}(MEltX8}s-
zS4I4+Sg!i+7jEhcCx90Zo@9Mbg4_CzDu9abuPg@mApF8jeMbqnPRIm^Zg5q(`E?q&
ztuK5d6g<f`wazQrtuK*CBoc{4B9Tb02aaA}Q{Rm@Mkn<N&wB%SqQ)BG%~`-%e}M4Q
zAZ28D2%0typz^Ak2IO^<L?|2~wb}q2zmgYzA3z%-l2!_)8H1*c!!%>?<KThHEZ5Vf
zO&g;76AGC6^z~3x73&+DzEr@=7tfg^REubDfbc0WI55JT86HJZu)eV=x;saVj*c=%
zh=+HPn?*PQyf?SC9S5xlRlS@Puh`w)Wfj23!25&E;@BHp`m~HGU9a-#+ED?610z^9
z4A4FT(TibA6;SKc`UPJBbk=DXi73JeST&;T^S@95$GHMljVS8}&@@eGU&0BP(kI#H
zbS8;(rt-O66;K<K=cfR@@u>YLX!pOsajudOPZPlV^L594@JGAN1$=qyUJSzh0p*(y
z006hTf^5BV-=F>f8UyPQ;2dG<3<Zl>p%{ek+WMzwNcrwX64=2fcCf#)=*t69|MU#$
z9J@#YJNR?QSY%(q&jQqv=JE63X$+@{ovL+C4jyp99rn9B#BFV9kGDI3cGFS<&WdG_
z{XKUgaRAxhYq>AMaRP!TS?0_8c>$zQO+F5ZL?X-|Ar5#r8(2bL00000NkvXXu0mjf
D#(A9n

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..334ef02242d3f65f165dee34405bb3a1b6b146d8
GIT binary patch
literal 837
zcmV-L1G@Z)P)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9X>4i*$~$WWauh>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<-o+;YS|^5ky#Grk+SIX5cx#?&0I>U6f~epZjz4DtVIuK9P8i>4rtTK|Hf*
z>74h8!>lAJ#OK8023?T&k?XR{Z=8z`3p_JyWK#3QVPdh^!Ey()lA#h$6Gs$PqkJLj
zvch?bvs$UK);;+PLwRi_&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs
zax9<<6_Voz|AXJ%nuV!JHz^bYx?gPjV-yJN0?oQ@e;?a+^91le16NwxUu^)hpQP8@
zTI2}m-v%zO+nT%wT<!ovPr77Cj^w8)6bium8GTa@7`O$3Yi@6?eVjf38R}~J1~@nb
z#)_1^?(y!P&ffk#)9UXBLsoK>gn$H40004eNkl<ZScUDBO-lk%6o#LPD6@!^6e3Ne
zeTb<4qQzjpp-r1wws${n+z4%ITh#CHV-VMY_>qN1#ZYE0ye-UOjLf-)L^RLla?iQ<
zyze=1FE}_j{57<6Mri4bm=v?ioUAxNQdQB?8Bwb?g_h2Uq^geOXJWuARBu#Bs_MvU
zH6~*~u`8a4M`*Vm0H{=JB;pZr`I5PYLt6m&{9bbT5=VyzwrblFHw;4<h9PRzrl?h$
z=DyeKjm_De#QdZKx~?<qe%N`v@%7n4u}ml!z~}d(>$<H5CmJ|AJy8Gw5RFC&2Ewd)
zRse9hTy(o#0G=M7DHO|GTwYo4{oH`HSS%J3^+sjv1p58HZDA<`R)Oy(kjs~3%E=pm
z!4n)efoYI7@T(K>=qXCqDF8P8u<V}WrPJr8^^rHE_2mp4cXnCY-l2PMK--c~z_q^0
z>s=Yh&dvZZ5C`5mJu|lGUNGabNPm|bd;8`OcYB^yKJTY;;o#ul@UM9XpmX24nfP$6
P00000NkvXXu0mjf!<UC=

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..ad7541ea1d42d0ec6a5895024f4163316ae16b0b
GIT binary patch
literal 892
zcmV-?1B3jDP)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9X>4i*$~$WWauh>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<-o+;YS|^5ky#Grk+SIX5cx#?&0I>U6f~epZjz4DtVIuK9P8i>4rtTK|Hf*
z>74h8!>lAJ#OK8023?T&k?XR{Z=8z`3p_JyWK#3QVPdh^!Ey()lA#h$6Gs$PqkJLj
zvch?bvs$UK);;+PLwRi_&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs
zax9<<6_Voz|AXJ%nuV!JHz^bYx?gPjV-yJN0?oQ@e;?a+^91le16NwxUu^)hpQP8@
zTI2}m-v%zO+nT%wT<!ovPr77Cj^w8)6bium8GTa@7`O$3Yi@6?eVjf38R}~J1~@nb
z#)_1^?(y!P&ffk#)9UXBLsoK>gn$H40005ANkl<Zc%1Fpy-F)V7{>9xVj%_&L{Jd?
zIJtlYS<$<&2-?QNfX!*NJiYyHvyEV*tyiKrcn5K}FrXk3$d;~^f|{7P`w|^^evoDs
zo(XRz)9eExA|fIpA|fIpQbrUfMHDB+p!KqO<L*(#v_(i1C&f;)`Q`KP<_&wc(`=R=
z>L4Zqc=hqijT+3Pvc57^H6V(UVrz4qhx<nW78d8Zyt)CPv9|hd?db5|$o)R%b<zxg
zL3@moH%jFb;GAP+xj`q*2*VA6AfUb9qP^cD3^(Yc87s>ToO7k}UbBKAD3v!#<p~0`
z_S!`lhBVezSy-HZTYtEJq?2Yi=Quw*9eXe9yore7q{z~{qSx!aeX{hf^sQ~3H_VJ>
zm~+>kezD(_H;CB)>h73&7iMcvo13PeKU43+Q}=h|4P!Qd|M@mk`CrI^eh+GY04VZX
z;N-{ihB3WJmUa(5{Xe@GC#CnW&Jz(45fKp)5fKp)pILMWOka;rl2wPm+W~-0hrr91
z43-@NFHeAFhrr7d0G@UTtXXsjO#1;pp=yV~>j7AF2)rJEMTfxqOF|t2spbVqa$7hK
S+K!e00000<MNUMnLSTYN)0f}?

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..c0133d22a2059b63537cb966960ad724c7307921
GIT binary patch
literal 917
zcmV;G18V$<P)<h;3K|Lk000e1NJLTq002M$002M;1^@s6s%dfF0004mX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmKpe$iQ>9X>4i*$~$WWauh>AE$6^me@v=v%)FuC*#nlvOS
zE{=k0!NHHks)LKOt`4q(Aou~|?BJy6A|?JWDYS_3;J6>}?mh0_0Yam~RI_UWP&La)
z#baVNw<-o+;YS|^5ky#Grk+SIX5cx#?&0I>U6f~epZjz4DtVIuK9P8i>4rtTK|Hf*
z>74h8!>lAJ#OK8023?T&k?XR{Z=8z`3p_JyWK#3QVPdh^!Ey()lA#h$6Gs$PqkJLj
zvch?bvs$UK);;+PLwRi_&2^e1h+_!}Bq2gZ4P{hdAxf)8iis5M$2|PQjz38*nOtQs
zax9<<6_Voz|AXJ%nuV!JHz^bYx?gPjV-yJN0?oQ@e;?a+^91le16NwxUu^)hpQP8@
zTI2}m-v%zO+nT%wT<!ovPr77Cj^w8)6bium8GTa@7`O$3Yi@6?eVjf38R}~J1~@nb
z#)_1^?(y!P&ffk#)9UXBLsoK>gn$H40005ZNkl<Zc%1Fpy-Fid7{>9xVj&w4A}B2Q
zvAKW&8FBAoi=b_`FtCk{TiV+vO&Y;QTdzd%uy>H1DGVsc63CQ0TN&2*$ebAxog>c=
z(wxIgo_WvYq&P2#h=_=Yh=_=Y2tcnth_lAB#_J$2TT$NSyqo1+aM*4a-t?{Y`h)ne
z-JUt0H<wueNIz)Nm()R(%uC6EUVjjOJ=o*v@fm<&5CZW3*v95Mw|Bqzd3ut%{;ehR
zzGMSv?e4r9%gUR21B@|jZ?zZ(A-=y)_qap%xP#|;`2Ie_AY^;1g)wHK4`wTw*Ymt-
zW}Cd3E7<wojeXyzwY$T{=K6H}>G7Fi5Mqqs`s(uCSO3LA^7i_JI1C=*@pwG_guz3t
z{{^b#U70m$%zdh&byg*BZULI+oaP8t8_@W)%q03ta{_-x^9eg|RrBT+;4J#aQuGBP
zU^0fr8US(h8@QNT@Oi14cjm_M`RGUL_cOY=sLke=<XT=45fKp)5fKp)k$Q8jXTV18
z@pzJJJp;C^3jl8R3>2|CG;pnFpbV=wz_p%%GOSn2wVr{6aII&+#?1bJEUxto6e(2z
r*LntQlq!I0Jp(pMZ(2HomyhKiZ2wz0|4;#A00000NkvXXu0mjfjnuaa

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/meta.json
new file mode 100644
index 0000000000..58b759095d
--- /dev/null
+++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi/meta.json
@@ -0,0 +1,30 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Borrowed from QM turtleneck at https://github.com/space-wizards/space-station-14/tree/master/Resources/Textures/Clothing/Uniforms/Jumpsuit/qmturtle.rsi and modified by Hanzdegloker (github) for space station 14",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "equipped-INNERCLOTHING",
+      "directions": 4
+    },
+    {
+      "name": "equipped-INNERCLOTHING-monkey",
+      "directions": 4
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Nyanotrasen/Clothing/Uniforms/Jumpsuit/summer_security.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Nyanotrasen/Clothing/Uniforms/Jumpsuit/summer_security.rsi/equipped-INNERCLOTHING.png
index 29212f6ca00c4fdef46023911d41d3ea45b16589..71aaaaafebe5c60b60fc461f27b378d1b0117818 100644
GIT binary patch
delta 1116
zcmV-i1f%<=1LX*i7=H)`00020X>r~F00b;aL_t(|0qvU4N*qBD##>oXL{`Z`i0I8r
z2$BboJVEYxwmd`bc>>83h~(l?i0mOm5m8*+^sn7-=rrR_SGzMB(gnNyXL{<Z{<^AW
zm~Q8)R0b*om4V7YWuP)p8K?~WpA4*6rhVkxY<o0v#~T~&>VN90xpzDs&pzJVxZl&M
z`|e!RZ_%AI_S0xI1LI^o4#Pbzc7*z&FR|_0bZWxS9t`-~^>z2ggZ}bhUsqS14EX%;
z(DeVjy)_$=J9+RC*#K5-6W6TxtK8Hjto-|(on{yYFzF8$7onsrVI1StUPc+?3yV^d
z2Sfc<{85*ItbaU8S#{VI5T)wU!FA+lch_xCCNrx$N>5xqg&&Vmy#&A01Bmx8*Vh4q
z_=AWxp`Ysr<GF7cvIsw3fKvSI96+K|qKRFPNy<BvpyC9%3=+^0<HzAB{il;jSO5~F
z1-~-{1b|YXWt&8(e#&Mgd<a;;V;x;};WG}x8_ao|et(_<R{YKoK(RzFu69~>T~Ehb
z+vwMmAibCV5_}T@Dd<bJ<JHH8v~95~I|QUunKlMh4$zoBOW~&&PxYtc(sp(d<VF$^
zrII0a1lQBsnKcF<HRSyZf6-_wzS#qI{5!!(iv{#gd?xNwJOOUq$NJjZT7bE{ymVVz
zTcLh;cYo(@ACs`j1Tz6>-{0R4AUFQ~e`Ef<$AF>5uXaN~DYl6KRsi-j+57wZrcOWC
zF{)1ihn1J8jwj#&Rw;f80Cs+UzET2eH8LGf7$AywwbOAq?P3CQl>ZB3Od$}vx9TcO
z5|EW3VR4`8Du=+g+FQq01}X!UfyzK-pfXSysDBJp1}X!UfyzK-;FU69`YNnB=$wGs
z>3IS5_gV6Vm@^3yzD$>#O)wL{<lk*>{<Rswz5wS15dVR~tW%T7DVaFqbS6RfV8ai;
zDQhLcWNds$0^oR$uG9ccAh%2xAhm%F63e!{>6;*KrX3hfScbDxglF_EsrRw!*n(i2
zb$@@*^i5E^KgXOG@GgJoLE{w&Rt)&3iHGpRCY?zze3~~A&=TJ>c?2GydY>GC0Tz=N
zUW;AXCYT6FwXz={AC?GP*Q`X3qV4f!bJi2$d}x-6DF?KHG={WY?743l*d_wV!10{O
zwu-~Jf2caxX~s`&?6T!qA%JqlVOsA3E`PngY&??(=qV5z&s!iy@v}aHVm-NaJ&M6=
zJBik2<09Rr7a`ul*a2o!6r~3T2O%Wla{<rE$cqfsHN6Sa=1c-|c6Ju*+1uNjd3@8`
zsEGi;L_)kHt1W90!?-?$iLxE8ZF;b@H)ve|a}JmTgq7E64fg1Vnmm)8V>Kj{PE{UV
zrX0Wx5=~z1mn!kT*c+{O6cIokkl=>I-OvJN90IXT7F*0AAmzB7Tu*&Nmn7fPi4SdS
i#j6Zd1}X!ul7T<a;X(}t5|kYP0000<MNUMnLSTZqT@UO4

delta 408
zcmV;J0cZZ@2&My&7=Hu<00013M{Ml?0016POjJbx000gS4jddDAt50oBqS><D?0!H
zO9TXD3=DP}8tXyXZ2$lO0d!JMQvg8b*k%9#0X9iQK~zY`?UX%k!!Qg+DWkC0$OxQ{
zj*;G@4&npUO?GEW#(441*u}CgP?NXq%1=PkrAyIpd%^=D3V-@Y^r+vgxFypmPR^;l
zXkp;=nQw}{^RwcZ#d-eJ%%Ye^CnAf#DQ3-NCoeL6tiEHSY!L1=k0P2W@gh$1Al$>4
zUS!fd3r}~2fGHk?JK%ZNOeX6)tJzv>K`5;)6-QNl+JjKNpHO&1Av*34wdQ(T)F|Y;
z`VRjrm|~S~?|<;4{@a4+TRhnG4e(VMzPa@noWwI8T*d2!Lh(2WYr)HPX&_0NM}g0F
zg|{3QjiYOVF_N&uEfm5#pb!&<9f%qf1_z7Np<swMurMwyk)FcjPbI$O`Za<v(?gYG
znh%&wgJC9m+2cEzDin?=L{*8x`j}&f!v5v&`~{QzW)TUCF}{=l0000<MNUMnLSTZ&
CgtNf_


From 975c905d1bd33652d5d956bebcbb274e7cf23f34 Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Sun, 5 Jan 2025 20:47:03 +0000
Subject: [PATCH 19/38] Automatic Changelog Update (#1443)

---
 Resources/Changelog/Changelog.yml | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 93a9ca560a..daadc24edf 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9320,3 +9320,34 @@ Entries:
   id: 6641
   time: '2025-01-05T19:45:57.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1438
+- author: The Den Contributors
+  changes:
+    - type: Fix
+      message: >-
+        Put actual prescription lenses in the prescription medhuds and sechuds
+        (by KyuPolaris)
+    - type: Add
+      message: >-
+        Added the CMO turtleneck and head mirror to the CMO loadouts. (by
+        sleepyyapril, KyuPolaris)
+    - type: Add
+      message: >-
+        Added an armored trenchcoat for the Captain. Enjoy your swag! (by
+        Rosycup)
+    - type: Fix
+      message: Fixed uneven pants leg on summer security uniforms. (by Rosycup)
+    - type: Add
+      message: >-
+        Added the Captain's Combat Gas Mask, for those more fond of close
+        encounters. (by Rosycup)
+    - type: Tweak
+      message: >-
+        Added the Captain's Trenchcoat to the other captain locker variants. (by
+        Rosycup)
+    - type: Fix
+      message: >-
+        Fixed they/them pronouns being displayed for it/its characters in the
+        character preview. (by Azzy)
+  id: 6642
+  time: '2025-01-05T20:46:36.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1443

From 8b5eec786cd82d6f48901e04a1045e274ec0fd3c Mon Sep 17 00:00:00 2001
From: Skubman <ba.fallaria@gmail.com>
Date: Thu, 9 Jan 2025 03:37:24 +0800
Subject: [PATCH 20/38] Fix Face Markings Rendering Above Clothing (#1467)

# Description

Fixes face markings rendering above clothing, most noticeably eye-wear
by moving the Face layer below the Eyes layer on all species.

## Media

Before (red markings rendering above sunglasses):

![image](https://github.com/user-attachments/assets/cd8979e0-7d0b-4fb6-a83f-00e9a2d6a2ce)

After:

![image](https://github.com/user-attachments/assets/e3181616-fb0d-4a2c-9998-180bf6d3ad2d)


# Changelog

:cl: Skubman
- fix: Fixed face markings showing up above eye-wear.
---
 Resources/Prototypes/DeltaV/Entities/Mobs/Species/lamia.yml   | 4 ++--
 .../Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml     | 2 +-
 Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml    | 2 +-
 Resources/Prototypes/Entities/Mobs/Species/arachne.yml        | 4 ++--
 Resources/Prototypes/Entities/Mobs/Species/arachnid.yml       | 2 +-
 Resources/Prototypes/Entities/Mobs/Species/base.yml           | 4 ++--
 Resources/Prototypes/Entities/Mobs/Species/harpy.yml          | 4 ++--
 Resources/Prototypes/Entities/Mobs/Species/moth.yml           | 2 +-
 Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml      | 4 ++--
 Resources/Prototypes/Entities/Mobs/Species/vox.yml            | 4 ++--
 10 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/lamia.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/lamia.yml
index 9d7a85f97d..71bb59b04e 100644
--- a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/lamia.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/lamia.yml
@@ -74,6 +74,7 @@
         color: "#008800"
         sprite: Mobs/Customization/eyes.rsi
         state: eyes
+      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.RArm" ]
         color: "#e8b59b"
         sprite: Mobs/Species/Human/parts.rsi
@@ -106,7 +107,6 @@
       - map: [ "belt2" ]
       - map: [ "neck" ]
       - map: [ "back" ]
-      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
       - map: [ "enum.HumanoidVisualLayers.Hair" ]
       - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
@@ -252,6 +252,7 @@
         color: "#008800"
         sprite: Mobs/Customization/eyes.rsi
         state: eyes
+      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.RArm" ]
         color: "#e8b59b"
         sprite: Mobs/Species/Human/parts.rsi
@@ -283,7 +284,6 @@
       - map: [ "belt" ]
       - map: [ "neck" ]
       - map: [ "back" ]
-      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
       - map: [ "enum.HumanoidVisualLayers.Hair" ]
       - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
index 0f7b0900bf..040d4bee13 100644
--- a/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Mobs/Species/vulpkanin.yml
@@ -31,6 +31,7 @@
       - map: [ "enum.HumanoidVisualLayers.Head" ]
       - map: [ "enum.HumanoidVisualLayers.Snout" ]
       - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.RArm" ]
       - map: [ "enum.HumanoidVisualLayers.LArm" ]
       - map: [ "enum.HumanoidVisualLayers.RLeg" ]
@@ -64,7 +65,6 @@
       - map: [ "belt" ]
       - map: [ "neck" ]
       - map: [ "back" ]
-      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
       - map: [ "enum.HumanoidVisualLayers.Hair" ]
       - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml
index cd51a8053b..7c65b89a76 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml
@@ -91,6 +91,7 @@
         - map: ["enum.HumanoidVisualLayers.Head"]
         - map: ["enum.HumanoidVisualLayers.Snout"]
         - map: ["enum.HumanoidVisualLayers.Eyes"]
+        - map: ["enum.HumanoidVisualLayers.Face"]
         - map: ["enum.HumanoidVisualLayers.RArm"]
         - map: ["enum.HumanoidVisualLayers.LArm"]
         - map: ["enum.HumanoidVisualLayers.RLeg"]
@@ -125,7 +126,6 @@
         - map: ["belt"]
         - map: ["neck"]
         - map: ["back"]
-        - map: [ "enum.HumanoidVisualLayers.Face" ]
         - map: ["enum.HumanoidVisualLayers.FacialHair"]
         - map: ["enum.HumanoidVisualLayers.Hair"]
         - map: ["enum.HumanoidVisualLayers.HeadSide"]
diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachne.yml b/Resources/Prototypes/Entities/Mobs/Species/arachne.yml
index 5c203640d8..2aa1a381bf 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/arachne.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/arachne.yml
@@ -27,6 +27,7 @@
       color: "#008800"
       sprite: Mobs/Species/eyes.rsi
       state: eyes
+    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.RArm" ]
       color: "#e8b59b"
       sprite: Mobs/Species/Human/parts.rsi
@@ -66,7 +67,6 @@
     - map: [ "belt" ]
     - map: [ "neck" ]
     - map: [ "back" ]
-    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
     - map: [ "enum.HumanoidVisualLayers.Hair" ]
       state: bald
@@ -173,6 +173,7 @@
       color: "#008800"
       sprite: Mobs/Species/eyes.rsi
       state: eyes
+    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.RArm" ]
       color: "#e8b59b"
       sprite: Mobs/Species/Human/parts.rsi
@@ -212,7 +213,6 @@
     - map: [ "belt" ]
     - map: [ "neck" ]
     - map: [ "back" ]
-    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
     - map: [ "enum.HumanoidVisualLayers.Hair" ]
       state: bald
diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml
index 32e26987c8..3a4e1791fb 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml
@@ -81,6 +81,7 @@
       - map: [ "enum.HumanoidVisualLayers.Head" ]
       - map: [ "enum.HumanoidVisualLayers.Snout" ]
       - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.RArm" ]
       - map: [ "enum.HumanoidVisualLayers.LArm" ]
       - map: [ "enum.HumanoidVisualLayers.RLeg" ]
@@ -110,7 +111,6 @@
       - map: [ "enum.HumanoidVisualLayers.Tail" ] # Mentioned in moth code: This needs renaming lol.
       - map: [ "neck" ]
       - map: [ "back" ]
-      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
       - map: [ "enum.HumanoidVisualLayers.Hair" ] # Do these need to be here? (arachnid hair arachnid hair)
       - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml
index a9d96ecde5..2788ab89f3 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/base.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml
@@ -13,6 +13,7 @@
     - map: [ "enum.HumanoidVisualLayers.Head" ]
     - map: [ "enum.HumanoidVisualLayers.Snout" ]
     - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.RArm" ]
     - map: [ "enum.HumanoidVisualLayers.LArm" ]
     - map: [ "enum.HumanoidVisualLayers.RLeg" ]
@@ -41,7 +42,6 @@
     - map: [ "id" ]
     - map: [ "neck" ]
     - map: [ "back" ]
-    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
     - map: [ "enum.HumanoidVisualLayers.Hair" ]
     - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
@@ -349,6 +349,7 @@
     - map: [ "enum.HumanoidVisualLayers.Head" ]
     - map: [ "enum.HumanoidVisualLayers.Snout" ]
     - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.RArm" ]
     - map: [ "enum.HumanoidVisualLayers.LArm" ]
     - map: [ "enum.HumanoidVisualLayers.RLeg" ]
@@ -380,7 +381,6 @@
     - map: [ "id" ]
     - map: [ "neck" ]
     - map: [ "back" ]
-    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
     - map: [ "enum.HumanoidVisualLayers.Hair" ]
     - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
diff --git a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
index 34232b4e6e..f48fb560e1 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml
@@ -14,6 +14,7 @@
       - map: [ "enum.HumanoidVisualLayers.Head" ]
       - map: [ "enum.HumanoidVisualLayers.Snout" ]
       - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.LArm" ]
       - map: [ "enum.HumanoidVisualLayers.RLeg" ]
       - map: [ "enum.HumanoidVisualLayers.LLeg" ]
@@ -38,7 +39,6 @@
       - map: [ "belt" ]
       - map: [ "neck" ]
       - map: [ "back" ]
-      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
       - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
       - map: [ "enum.HumanoidVisualLayers.Tail" ]
@@ -148,6 +148,7 @@
       - map: [ "enum.HumanoidVisualLayers.Head" ]
       - map: [ "enum.HumanoidVisualLayers.Snout" ]
       - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.LArm" ]
       - map: [ "enum.HumanoidVisualLayers.RLeg" ]
       - map: [ "enum.HumanoidVisualLayers.LLeg" ]
@@ -167,7 +168,6 @@
       - map: [ "belt" ]
       - map: [ "neck" ]
       - map: [ "back" ]
-      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
       - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
       - map: [ "enum.HumanoidVisualLayers.HeadTop" ]
diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml
index f8eef07f8f..6d0c1182e9 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml
@@ -76,6 +76,7 @@
       - map: [ "enum.HumanoidVisualLayers.Head" ]
       - map: [ "enum.HumanoidVisualLayers.Snout" ]
       - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.RArm" ]
       - map: [ "enum.HumanoidVisualLayers.LArm" ]
       - map: [ "enum.HumanoidVisualLayers.RLeg" ]
@@ -110,7 +111,6 @@
       - map: [ "enum.HumanoidVisualLayers.Tail" ] #in the utopian future we should probably have a wings enum inserted here so everyhting doesn't break
       - map: [ "neck" ]
       - map: [ "back" ]
-      - map: [ "enum.HumanoidVisualLayers.Face" ]
       - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
       - map: [ "enum.HumanoidVisualLayers.Hair" ]
       - map: [ "enum.HumanoidVisualLayers.HeadSide" ]
diff --git a/Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml b/Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml
index f45adde261..2063225a8e 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/shadowkin.yml
@@ -153,6 +153,7 @@
         - map: ["enum.HumanoidVisualLayers.Snout"]
         - map: ["enum.HumanoidVisualLayers.Eyes"]
           shader: unshaded
+        - map: ["enum.HumanoidVisualLayers.Face"]
         - map: ["enum.HumanoidVisualLayers.RArm"]
         - map: ["enum.HumanoidVisualLayers.LArm"]
         - map: ["enum.HumanoidVisualLayers.RLeg"]
@@ -187,7 +188,6 @@
         - map: ["belt"]
         - map: ["neck"]
         - map: ["back"]
-        - map: [ "enum.HumanoidVisualLayers.Face" ]
         - map: ["enum.HumanoidVisualLayers.FacialHair"]
         - map: ["enum.HumanoidVisualLayers.Hair"]
         - map: ["enum.HumanoidVisualLayers.HeadSide"]
@@ -265,6 +265,7 @@
         - map: ["enum.HumanoidVisualLayers.Snout"]
         - map: ["enum.HumanoidVisualLayers.Eyes"]
           shader: unshaded
+        - map: ["enum.HumanoidVisualLayers.Face"]
         - map: ["enum.HumanoidVisualLayers.RArm"]
         - map: ["enum.HumanoidVisualLayers.LArm"]
         - map: ["enum.HumanoidVisualLayers.RLeg"]
@@ -299,7 +300,6 @@
         - map: ["belt"]
         - map: ["neck"]
         - map: ["back"]
-        - map: [ "enum.HumanoidVisualLayers.Face" ]
         - map: ["enum.HumanoidVisualLayers.FacialHair"]
         - map: ["enum.HumanoidVisualLayers.Hair"]
         - map: ["enum.HumanoidVisualLayers.HeadSide"]
diff --git a/Resources/Prototypes/Entities/Mobs/Species/vox.yml b/Resources/Prototypes/Entities/Mobs/Species/vox.yml
index 5de01dbe6a..a26cf9f061 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/vox.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/vox.yml
@@ -1,4 +1,4 @@
-- type: entity
+- type: entity
   parent: BaseMobSpeciesOrganic
   id: BaseMobVox
   abstract: true
@@ -65,6 +65,7 @@
     - map: [ "enum.HumanoidVisualLayers.Head" ]
     - map: [ "enum.HumanoidVisualLayers.Snout" ]
     - map: [ "enum.HumanoidVisualLayers.Eyes" ]
+    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.RArm" ]
     - map: [ "enum.HumanoidVisualLayers.LArm" ]
     - map: [ "enum.HumanoidVisualLayers.RLeg" ]
@@ -83,7 +84,6 @@
     - map: [ "id" ]
     - map: [ "neck" ]
     - map: [ "back" ]
-    - map: [ "enum.HumanoidVisualLayers.Face" ]
     - map: [ "enum.HumanoidVisualLayers.FacialHair" ]
     - map: [ "enum.HumanoidVisualLayers.Hair" ]
     - map: [ "enum.HumanoidVisualLayers.HeadSide" ]

From 998e0ea99369e3780aa75c536fbe8c3bd2594d32 Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Wed, 8 Jan 2025 19:37:54 +0000
Subject: [PATCH 21/38] Automatic Changelog Update (#1467)

---
 Resources/Changelog/Changelog.yml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index c0d361fc67..0c543a80f7 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9466,3 +9466,10 @@ Entries:
   id: 6652
   time: '2025-01-08T07:09:10.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1456
+- author: Skubman
+  changes:
+    - type: Fix
+      message: Fixed face markings showing up above eye-wear.
+  id: 6653
+  time: '2025-01-08T19:37:24.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1467

From b39e126d6e87d98cadd1aaa4b3ce2cae4c2bd766 Mon Sep 17 00:00:00 2001
From: Lumminal <81829924+Lumminal@users.noreply.github.com>
Date: Thu, 9 Jan 2025 23:32:06 +0200
Subject: [PATCH 22/38] Prisoner Headset Box in Warden's Locker (#1470)

# Description

Adds a prisoner headset box for warden's locker

Reason: There's too much chaos in security and making radio headsets
with pure encryption keys takes time and tools. More so cause by the
time someone gets a perma punishment, its gonna be most likely late in
the round and sec department will be dealing with a lot of things at the
same time.

---

<details><summary><h1>Media</h1></summary>
<p>

![Content
Client_LlH3OUGtCU](https://github.com/user-attachments/assets/ea20a648-9606-4104-9787-0766966bd358)


![Example Media Embed](https://example.com/thisimageisntreal.png)

</p>
</details>

---

# Changelog

<!--
You can add an author after the `:cl:` to change the name that appears
in the changelog (ex: `:cl: Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

:cl:
- add: Added prisoner headset box to warden's locker.
---
 .../Prototypes/Catalog/Fills/Boxes/security.yml   | 15 +++++++++++++++
 .../Prototypes/Catalog/Fills/Lockers/security.yml |  2 ++
 2 files changed, 17 insertions(+)

diff --git a/Resources/Prototypes/Catalog/Fills/Boxes/security.yml b/Resources/Prototypes/Catalog/Fills/Boxes/security.yml
index 82da52de3f..1aefbf7a68 100644
--- a/Resources/Prototypes/Catalog/Fills/Boxes/security.yml
+++ b/Resources/Prototypes/Catalog/Fills/Boxes/security.yml
@@ -17,6 +17,21 @@
       - state: box_security
       - state: handcuff
 
+- type: entity
+  name: prisoner headset box
+  parent: BoxCardboard
+  id: BoxPrisonerHeadset
+  description: A box of prisoner headsets.
+  components:
+  - type: StorageFill
+    contents:
+    - id: ClothingHeadsetPrison
+      amount: 4
+  - type: Sprite
+    layers:
+    - state: box_security
+    - state: headset
+
 - type: entity
   name: flashbang box
   parent: BoxCardboard
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/security.yml b/Resources/Prototypes/Catalog/Fills/Lockers/security.yml
index e2d7ad1483..fe1d9ecc72 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/security.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/security.yml
@@ -24,6 +24,7 @@
       - id: BoxPDAPrisoner # Delta-V
       - id: ClothingShoesBootsWinterWarden #Delta V: Add departmental winter boots
       - id: BoxEncryptionKeyPrisoner #Delta-V
+      - id: BoxPrisonerHeadset
       - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes!
         prob: 0.3
 
@@ -52,6 +53,7 @@
       - id: BoxPDAPrisoner # Delta-V
       - id: ClothingShoesBootsWinterWarden #Delta V: Add departmental winter boots
       - id: BoxEncryptionKeyPrisoner #Delta-V
+      - id: BoxPrisonerHeadset
       - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes!
         prob: 0.3
 

From 49076397530a63a50ad723c28c37bf00ad76201d Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Thu, 9 Jan 2025 21:32:34 +0000
Subject: [PATCH 23/38] Automatic Changelog Update (#1470)

---
 Resources/Changelog/Changelog.yml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 0c543a80f7..3015e03292 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9473,3 +9473,10 @@ Entries:
   id: 6653
   time: '2025-01-08T19:37:24.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1467
+- author: Lumminal
+  changes:
+    - type: Add
+      message: Added prisoner headset box to warden's locker.
+  id: 6654
+  time: '2025-01-09T21:32:06.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1470

From 86296da6e269e65221f68f0a2df38f3beeb9ff3e Mon Sep 17 00:00:00 2001
From: Blu <79374236+BlueHNT@users.noreply.github.com>
Date: Fri, 10 Jan 2025 03:27:28 +0100
Subject: [PATCH 24/38] Adds Missing Lathe Recipes (#1472)

<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->

# Description

<!--
Explain this PR in as much detail as applicable

Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->

N1984 exists, but you can't print more ammo reliably. You can refill
them, sure, but the moment you lose a magazine, it's gone forever.

This adds the magazines and adds the unique mags to the research.

Edit: Turns out there's like a lot missing in the lathe, so I decided to
just add the missing ones I found.

---

<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->

<details><summary><h1>Media</h1></summary>
<p>

Nothing here

</p>
</details>

---

# Changelog

<!--
You can add an author after the `:cl:` to change the name that appears
in the changelog (ex: `:cl: Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

:cl:
- add: Added missing lathe recipes
---
 .../Guns/Ammunition/Magazines/magnum.yml      |  14 ++
 .../Guns/Ammunition/Magazines/pistol.yml      |  14 ++
 .../Entities/Structures/Machines/lathe.yml    |  12 ++
 .../Prototypes/Recipes/Lathes/security.yml    | 154 +++++++++++++++---
 Resources/Prototypes/Research/arsenal.yml     |  10 ++
 5 files changed, 180 insertions(+), 24 deletions(-)

diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml
index fc506ec594..c71a58a82b 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml
@@ -102,6 +102,20 @@
     - state: mag-1
       map: ["enum.GunVisualLayers.Mag"]
 
+- type: entity
+  id: MagazineMagnumIncendiary
+  name: pistol magazine (.45 magnum incendiary)
+  parent: BaseMagazineMagnum
+  components:
+  - type: BallisticAmmoProvider
+    proto: CartridgeMagnumIncendiary
+  - type: Sprite
+    layers:
+    - state: red
+      map: ["enum.GunVisualLayers.Base"]
+    - state: mag-1
+      map: ["enum.GunVisualLayers.Mag"]
+
 - type: entity
   id: MagazineMagnumUranium
   name: pistol magazine (.45 magnum uranium)
diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml
index c57a8adaa5..a74d259ce8 100644
--- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml
+++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml
@@ -330,6 +330,20 @@
     - state: mag-1
       map: ["enum.GunVisualLayers.Mag"]
 
+- type: entity
+  id: MagazinePistolSubMachineGunIncendiary
+  name: SMG magazine (.35 auto incendiary)
+  parent: BaseMagazinePistolSubMachineGun
+  components:
+  - type: BallisticAmmoProvider
+    proto: CartridgePistolIncendiary
+  - type: Sprite
+    layers:
+    - state: red
+      map: ["enum.GunVisualLayers.Base"]
+    - state: mag-1
+      map: ["enum.GunVisualLayers.Mag"]
+
 - type: entity
   id: MagazinePistolSubMachineGunUranium
   name: SMG magazine (.35 auto uranium)
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index adf6bd94aa..850b2c0d74 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -805,6 +805,8 @@
       - MagazinePistolSubMachineGunEmpty
       - MagazinePistolSubMachineGunTopMounted
       - MagazinePistolSubMachineGunTopMountedEmpty
+      - MagazineMagnum
+      - MagazineMagnumEmpty
       - MagazineRifle
       - MagazineRifleEmpty
       - MagazineShotgun
@@ -868,10 +870,19 @@
       - MagazineBoxPistolRubber
       - MagazineBoxRifleRubber
       - MagazineGrenadeEmpty
+      - MagazineLightRifleRubber
       - MagazineLightRifleIncendiary
       - MagazineLightRifleUranium
+      - MagazinePistolRubber
       - MagazinePistolIncendiary
       - MagazinePistolUranium
+      - MagazinePistolSubMachineGunRubber
+      - MagazinePistolSubMachineGunIncendiary
+      - MagazinePistolSubMachineGunUranium
+      - MagazineMagnumRubber
+      - MagazineMagnumIncendiary
+      - MagazineMagnumUranium
+      - MagazineRifleRubber
       - MagazineRifleIncendiary
       - MagazineRifleUranium
       - MagazineShotgunBeanbag
@@ -887,6 +898,7 @@
       - ShuttleGunSvalinnMachineGunCircuitboard
       - Signaller
       - SignalTrigger
+      - SpeedLoaderMagnumRubber
       - SpeedLoaderMagnumIncendiary
       - SpeedLoaderMagnumUranium
       - TelescopicShield
diff --git a/Resources/Prototypes/Recipes/Lathes/security.yml b/Resources/Prototypes/Recipes/Lathes/security.yml
index 5b126f7697..6d00f40ce2 100644
--- a/Resources/Prototypes/Recipes/Lathes/security.yml
+++ b/Resources/Prototypes/Recipes/Lathes/security.yml
@@ -242,6 +242,15 @@
   materials:
     Steel: 145
 
+- type: latheRecipe
+  id: MagazinePistolRubber
+  result: MagazinePistolRubber
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 45
+    Plastic: 100
+
 - type: latheRecipe
   id: MagazinePistolPractice
   result: MagazinePistolPractice
@@ -285,6 +294,34 @@
   materials:
     Steel: 300
 
+- type: latheRecipe
+  id: MagazinePistolSubMachineGunRubber
+  result: MagazinePistolSubMachineGunRubber
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 100
+    Plastic: 200
+
+- type: latheRecipe
+  id: MagazinePistolSubMachineGunUranium
+  result: MagazinePistolSubMachineGunUranium
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 25
+    Plastic: 225
+    Uranium: 225
+
+- type: latheRecipe
+  id: MagazinePistolSubMachineGunIncendiary
+  result: MagazinePistolSubMachineGunIncendiary
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 25
+    Plastic: 400
+
 - type: latheRecipe
   id: MagazinePistolSubMachineGunTopMountedEmpty
   result: MagazinePistolSubMachineGunTopMountedEmpty
@@ -351,6 +388,14 @@
   materials:
     Steel: 475
 
+- type: latheRecipe
+  id: MagazineRifleRubber
+  result: MagazineRifleRubber
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 150
+    Plastic: 325
 
 - type: latheRecipe
   id: MagazineRiflePractice
@@ -395,6 +440,15 @@
   materials:
     Steel: 565
 
+- type: latheRecipe
+  id: MagazineLightRifleRubber
+  result: MagazineLightRifleRubber
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 125
+    Plastic: 350
+
 - type: latheRecipe
   id: MagazineLightRiflePractice
   result: MagazineLightRiflePractice
@@ -403,7 +457,6 @@
   materials:
     Steel: 205
 
-
 - type: latheRecipe
   id: MagazineLightRifleUranium
   result: MagazineLightRifleUranium
@@ -423,6 +476,50 @@
     Steel: 25
     Plastic: 540
 
+- type: latheRecipe
+  id: MagazineMagnumEmpty
+  result: MagazineMagnumEmpty
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 30
+
+- type: latheRecipe
+  id: MagazineMagnum
+  result: MagazineMagnum
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 150
+
+- type: latheRecipe
+  id: MagazineMagnumRubber
+  result: MagazineMagnumRubber
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 50
+    Plastic: 100
+
+- type: latheRecipe
+  id: MagazineMagnumUranium
+  result: MagazineMagnumUranium
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 30
+    Plastic: 75
+    Uranium: 150
+
+- type: latheRecipe
+  id: MagazineMagnumIncendiary
+  result: MagazineMagnumIncendiary
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 30
+    Plastic: 150
+
 - type: latheRecipe
   id: MagazineBoxRifle
   result: MagazineBoxRifle
@@ -475,21 +572,21 @@
     Plastic: 160
 
 - type: latheRecipe
-  id: SpeedLoaderMagnumEmpty
-  result: SpeedLoaderMagnumEmpty
+  id: MagazineBoxLightRifleRubber
+  result: MagazineBoxLightRifleRubber
   category: Ammo
   completetime: 5
   materials:
-    Steel: 50
+    Steel: 350
+    Plastic: 600
 
 - type: latheRecipe
-  id: MagazineBoxLightRifleRubber
-  result: MagazineBoxLightRifleRubber
+  id: SpeedLoaderMagnumEmpty
+  result: SpeedLoaderMagnumEmpty
   category: Ammo
   completetime: 5
   materials:
-    Steel: 350
-    Plastic: 600
+    Steel: 50
 
 - type: latheRecipe
   id: SpeedLoaderMagnum
@@ -499,6 +596,15 @@
   materials:
     Steel: 190
 
+- type: latheRecipe
+  id: SpeedLoaderMagnumRubber
+  result: SpeedLoaderMagnumRubber
+  category: Ammo
+  completetime: 5
+  materials:
+    Steel: 50
+    Plastic: 70
+
 - type: latheRecipe
   id: SpeedLoaderMagnumPractice
   result: SpeedLoaderMagnumPractice
@@ -758,46 +864,46 @@
   result: MagazineGrenadeEmpty
   completetime: 3
   materials:
-     Steel: 150
-     Plastic: 50
+    Steel: 150
+    Plastic: 50
 
 - type: latheRecipe
   id: GrenadeEMP
   result: GrenadeEMP
   completetime: 3
   materials:
-     Steel: 150
-     Plastic: 100
-     Glass: 20
+    Steel: 150
+    Plastic: 100
+    Glass: 20
 
 - type: latheRecipe
   id: GrenadeBlast
   result: GrenadeBlast
   completetime: 3
   materials:
-     Steel: 150
-     Plastic: 100
-     Gold: 50
+    Steel: 150
+    Plastic: 100
+    Gold: 50
 
 - type: latheRecipe
   id: GrenadeFlash
   result: GrenadeFlash
   completetime: 3
   materials:
-     Steel: 150
-     Plastic: 100
-     Glass: 20
+    Steel: 150
+    Plastic: 100
+    Glass: 20
 
 - type: latheRecipe
   id: PortableRecharger
   result: PortableRecharger
   completetime: 15
   materials:
-     Steel: 2000
-     Uranium: 2000
-     Plastic: 1000
-     Plasma: 500
-     Glass: 500
+    Steel: 2000
+    Uranium: 2000
+    Plastic: 1000
+    Plasma: 500
+    Glass: 500
 
 - type: latheRecipe
   id: ShellShotgun
diff --git a/Resources/Prototypes/Research/arsenal.yml b/Resources/Prototypes/Research/arsenal.yml
index ee2be33c83..6a1d1e3773 100644
--- a/Resources/Prototypes/Research/arsenal.yml
+++ b/Resources/Prototypes/Research/arsenal.yml
@@ -27,6 +27,8 @@
   - BoxShotgunIncendiary
   - MagazineRifleIncendiary
   - MagazinePistolIncendiary
+  - MagazinePistolSubMachineGunIncendiary
+  - MagazineMagnumIncendiary
   - MagazineLightRifleIncendiary
   - SpeedLoaderMagnumIncendiary
   - MagazineShotgunIncendiary
@@ -68,6 +70,12 @@
   - CartridgeMagnumRubber
   - CartridgeLightRifleRubber
   - CartridgeRifleRubber
+  - MagazineRifleRubber
+  - MagazinePistolRubber
+  - MagazinePistolSubMachineGunRubber
+  - MagazineMagnumRubber
+  - MagazineLightRifleRubber
+  - SpeedLoaderMagnumRubber
   - MagazineBoxPistolRubber
   - MagazineBoxMagnumRubber
   - MagazineBoxLightRifleRubber
@@ -88,6 +96,8 @@
   recipeUnlocks:
   - MagazineRifleUranium
   - MagazinePistolUranium
+  - MagazinePistolSubMachineGunUranium
+  - MagazineMagnumUranium
   - MagazineLightRifleUranium
   - SpeedLoaderMagnumUranium
   - MagazineBoxPistolUranium

From b89412ad039706bdfc528843a406813277778564 Mon Sep 17 00:00:00 2001
From: Spatison <137375981+Spatison@users.noreply.github.com>
Date: Fri, 10 Jan 2025 12:27:50 +1000
Subject: [PATCH 25/38] Some Surgery Fixs (#1471)

<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->

# Description

<!--
Explain this PR in as much detail as applicable

Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->

When attempting to insert an organ, a check is now performed to ensure a
container exists for it. Skeletons can now lie down, and nymphs can now
be subject to surgery.
---

# Changelog

<!--
You can add an author after the `:cl:` to change the name that appears
in the changelog (ex: `:cl: Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

:cl: Spatison
- tweak: Nymphs are now operable.
- fix: Skeletons can now lie down.
- fix: It is no longer possible to insert an organ into a body if the
required space is unavailable.
---
 .../SurgeryOrganConditionComponent.cs         |  5 ++-
 .../_Shitmed/Surgery/SharedSurgerySystem.cs   |  4 ++-
 Resources/Prototypes/Body/Organs/diona.yml    | 15 +++++++++
 .../Entities/Mobs/Species/skeleton.yml        |  1 +
 .../_Shitmed/Entities/Surgery/surgeries.yml   | 32 +++++++++++++++++++
 5 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryOrganConditionComponent.cs b/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryOrganConditionComponent.cs
index 53db0430e5..7ddd99f9af 100644
--- a/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryOrganConditionComponent.cs
+++ b/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryOrganConditionComponent.cs
@@ -15,4 +15,7 @@ public sealed partial class SurgeryOrganConditionComponent : Component
 
     [DataField]
     public bool Reattaching;
-}
\ No newline at end of file
+
+    [DataField(required: true)]
+    public string SlotId = string.Empty;
+}
diff --git a/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.cs b/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.cs
index fe12eed8fe..aa47087532 100644
--- a/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.cs
+++ b/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.cs
@@ -22,6 +22,7 @@
 using Content.Shared.Prototypes;
 using Content.Shared.Standing;
 using Robust.Shared.Audio.Systems;
+using Robust.Shared.Containers;
 using Robust.Shared.Map;
 using Robust.Shared.Network;
 using Robust.Shared.Prototypes;
@@ -47,6 +48,7 @@ public abstract partial class SharedSurgerySystem : EntitySystem
     [Dependency] private readonly RotateToFaceSystem _rotateToFace = default!;
     [Dependency] private readonly StandingStateSystem _standing = default!;
     [Dependency] private readonly SharedTransformSystem _transform = default!;
+    [Dependency] private readonly SharedContainerSystem _container = default!;
 
     /// <summary>
     /// Cache of all surgery prototypes' singleton entities.
@@ -265,7 +267,7 @@ private void OnOrganConditionValid(Entity<SurgeryOrganConditionComponent> ent, r
                     && !organs.Any(organ => HasComp<OrganReattachedComponent>(organ.Id))))
                     args.Cancelled = true;
             }
-            else if (!ent.Comp.Inverse)
+            else if (!ent.Comp.Inverse || !_container.TryGetContainer(args.Part, SharedBodySystem.GetOrganContainerId(ent.Comp.SlotId), out _))
                 args.Cancelled = true;
         }
     }
diff --git a/Resources/Prototypes/Body/Organs/diona.yml b/Resources/Prototypes/Body/Organs/diona.yml
index 72564b1abb..fb6c819493 100644
--- a/Resources/Prototypes/Body/Organs/diona.yml
+++ b/Resources/Prototypes/Body/Organs/diona.yml
@@ -184,6 +184,11 @@
   - type: IsDeadIC
   - type: Body
     prototype: AnimalNymphBrain
+  - type: SurgeryTarget
+  - type: UserInterface
+    interfaces:
+      enum.SurgeryUIKey.Key:
+        type: SurgeryBui
 
 - type: entity
   id: OrganDionaNymphStomach
@@ -196,6 +201,11 @@
   - type: IsDeadIC
   - type: Body
     prototype: AnimalNymphStomach
+  - type: SurgeryTarget
+  - type: UserInterface
+    interfaces:
+      enum.SurgeryUIKey.Key:
+        type: SurgeryBui
 
 - type: entity
   id: OrganDionaNymphLungs
@@ -208,3 +218,8 @@
   - type: IsDeadIC
   - type: Body
     prototype: AnimalNymphLungs
+  - type: SurgeryTarget
+  - type: UserInterface
+    interfaces:
+      enum.SurgeryUIKey.Key:
+        type: SurgeryBui
diff --git a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml
index 96c6185693..5f9812f490 100644
--- a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml
+++ b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml
@@ -104,6 +104,7 @@
   - type: FireVisuals
     alternateState: Standing
   - type: FootPrints
+  - type: LayingDown
 
 - type: entity
   parent: BaseSpeciesDummy
diff --git a/Resources/Prototypes/_Shitmed/Entities/Surgery/surgeries.yml b/Resources/Prototypes/_Shitmed/Entities/Surgery/surgeries.yml
index 775716ecff..44d1f3c1c8 100644
--- a/Resources/Prototypes/_Shitmed/Entities/Surgery/surgeries.yml
+++ b/Resources/Prototypes/_Shitmed/Entities/Surgery/surgeries.yml
@@ -377,6 +377,16 @@
   - type: SurgeryOrganCondition
     organ:
     - type: Brain
+    slotId: brain
+
+- type: entity
+  parent: SurgeryRemoveBrain
+  id: SurgeryRemoveBrainTorso
+  name: Remove Brain
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: SurgeryPartCondition
+    part: Torso
 
 - type: entity
   parent: SurgeryBase
@@ -397,6 +407,16 @@
     - type: Brain
     inverse: true
     reattaching: true
+    slotId: brain
+
+- type: entity
+  parent: SurgeryInsertBrain
+  id: SurgeryInsertBrainTorso
+  name: Insert Brain
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: SurgeryPartCondition
+    part: Torso
 
 - type: entity
   parent: SurgeryBase
@@ -415,6 +435,7 @@
   - type: SurgeryOrganCondition
     organ:
     - type: Heart
+    slotId: heart
 
 - type: entity
   parent: SurgeryBase
@@ -435,6 +456,7 @@
     - type: Heart
     inverse: true
     reattaching: true
+    slotId: heart
 
 - type: entity
   parent: SurgeryBase
@@ -453,6 +475,7 @@
   - type: SurgeryOrganCondition
     organ:
     - type: Liver
+    slotId: liver
 
 - type: entity
   parent: SurgeryBase
@@ -473,6 +496,7 @@
     - type: Liver
     inverse: true
     reattaching: true
+    slotId: liver
 
 - type: entity
   parent: SurgeryBase
@@ -491,6 +515,7 @@
   - type: SurgeryOrganCondition
     organ:
     - type: Lung
+    slotId: lungs
 
 - type: entity
   parent: SurgeryBase
@@ -511,6 +536,7 @@
     - type: Lung
     inverse: true
     reattaching: true
+    slotId: lungs
 
 - type: entity
   parent: SurgeryBase
@@ -529,6 +555,7 @@
   - type: SurgeryOrganCondition
     organ:
     - type: Stomach
+    slotId: stomach
 
 - type: entity
   parent: SurgeryBase
@@ -549,6 +576,7 @@
     - type: Stomach
     inverse: true
     reattaching: true
+    slotId: stomach
 
 - type: entity
   parent: SurgeryBase
@@ -567,6 +595,7 @@
   - type: SurgeryOrganCondition
     organ:
     - type: Eyes
+    slotId: eyes
 
 - type: entity
   parent: SurgeryBase
@@ -587,6 +616,7 @@
     - type: Eyes
     inverse: true
     reattaching: true
+    slotId: eyes
 
 - type: entity
   parent: SurgeryBase
@@ -602,6 +632,7 @@
   - type: SurgeryOrganCondition
     organ:
     - type: Brain
+    slotId: brain
   - type: SurgeryOrganOnAddCondition
     components:
       brain:
@@ -629,6 +660,7 @@
   - type: SurgeryOrganCondition
     organ:
     - type: Brain
+    slotId: brain
   - type: SurgeryOrganOnAddCondition
     components:
       brain:

From 77a72958d47ad3cc0752da2762576f4f107d75f7 Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Fri, 10 Jan 2025 02:27:54 +0000
Subject: [PATCH 26/38] Automatic Changelog Update (#1472)

---
 Resources/Changelog/Changelog.yml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 3015e03292..b1aee0b265 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9480,3 +9480,10 @@ Entries:
   id: 6654
   time: '2025-01-09T21:32:06.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1470
+- author: BlueHNT
+  changes:
+    - type: Add
+      message: Added missing lathe recipes
+  id: 6655
+  time: '2025-01-10T02:27:28.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1472

From ba616f0ce8375e47afee0342b8a580b8c5f88c5a Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Fri, 10 Jan 2025 02:28:23 +0000
Subject: [PATCH 27/38] Automatic Changelog Update (#1471)

---
 Resources/Changelog/Changelog.yml | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index b1aee0b265..40eee58c48 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9487,3 +9487,16 @@ Entries:
   id: 6655
   time: '2025-01-10T02:27:28.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1472
+- author: Spatison
+  changes:
+    - type: Tweak
+      message: Nymphs are now operable.
+    - type: Fix
+      message: Skeletons can now lie down.
+    - type: Fix
+      message: >-
+        It is no longer possible to insert an organ into a body if the required
+        space is unavailable.
+  id: 6656
+  time: '2025-01-10T02:27:50.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1471

From 0f481422a54a197923f4bf03db1b5733e481965f Mon Sep 17 00:00:00 2001
From: Spatison <137375981+Spatison@users.noreply.github.com>
Date: Fri, 10 Jan 2025 14:41:32 +1000
Subject: [PATCH 28/38] Night And Thermal Vision (#1462)

<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->

# Description

<!--
Explain this PR in as much detail as applicable

Some example prompts to consider:
How might this affect the game? The codebase?
What might be some alternatives to this?
How/Who does this benefit/hurt [the game/codebase]?
-->

Port from WWDP. Refactor from
[Goob](https://github.com/Goob-Station/Goob-Station/pull/1251)

---

<!--
This is default collapsed, readers click to expand it and see all your
media
The PR media section can get very large at times, so this is a good way
to keep it clean
The title is written using HTML tags
The title must be within the <summary> tags or you won't see it
-->

<details><summary><h1>Media</h1></summary>
<p>


![image](https://github.com/user-attachments/assets/ee60eb59-0432-477e-8aee-25a56032e58e)

Night vision goggles:

![image](https://github.com/user-attachments/assets/f9269e1a-97ed-456f-bd45-7015b723fb3e)

Zealot's blindfold:

![image](https://github.com/user-attachments/assets/7c60011e-1d0a-4fb2-92cb-fded8c747555)

Animal vision:

![image](https://github.com/user-attachments/assets/14f1153d-b771-4316-9faa-fee951d884ce)

Thermal vision goggles:

![image](https://github.com/user-attachments/assets/b167ef8b-e1b7-477e-a08d-b217fd2e38c5)

Deathsquad helmet:

![image](https://github.com/user-attachments/assets/2e15ab15-6d23-45c2-b51e-3c16dc3a135d)

Xeno vision:

![image](https://github.com/user-attachments/assets/1677b69e-013f-464a-baaf-af3b5f1b6488)


</p>
</details>

---

# Changelog

<!--
You can add an author after the `:cl:` to change the name that appears
in the changelog (ex: `:cl: Death`)
Leaving it blank will default to your GitHub display name
This includes all available types for the changelog
-->

:cl: @Aviu00, Spatison, @PuroSlavKing
- add: Added night vision goggle
- add: Added thermal vision goggle
- add: Deathsquad helmet now grants night and thermal vision.
- add: Ninja visor now grants night vision.
- tweak: Some animals have gained night vision.
- tweak: Xenos have gained night vision.

---------

Signed-off-by: Spatison <137375981+Spatison@users.noreply.github.com>
Co-authored-by: PuroSlavKing <103608145+puroslavking@users.noreply.github.com>
---
 Content.Client/Overlays/EquipmentHudSystem.cs |    2 +-
 .../Switchable/BaseSwitchableOverlay.cs       |   48 +
 .../Overlays/Switchable/NightVisionSystem.cs  |   87 +
 .../Switchable/ThermalVisionOverlay.cs        |  159 ++
 .../Switchable/ThermalVisionSystem.cs         |   95 +
 Content.Shared/Actions/SharedActionsSystem.cs |    5 +-
 .../Body/Components/BodyComponent.cs          |    3 +
 .../Inventory/InventorySystem.Relay.cs        |    4 +
 .../Overlays/BaseOverlayComponent.cs          |   16 +
 .../Switchable/NightVisionComponent.cs        |   14 +
 .../Overlays/Switchable/NightVisionSystem.cs  |    3 +
 .../Switchable/SwitchableOverlayComponent.cs  |   48 +
 .../Switchable/SwitchableOverlaySystem.cs     |  166 ++
 .../Switchable/ThermalVisionComponent.cs      |   17 +
 .../Switchable/ThermalVisionSystem.cs         |    3 +
 Resources/Audio/Items/Goggles/activate.ogg    |  Bin 0 -> 12048 bytes
 .../Audio/Items/Goggles/attributions.yml      |    9 +
 Resources/Audio/Items/Goggles/deactivate.ogg  |  Bin 0 -> 12424 bytes
 .../Locale/en-US/research/technologies.ftl    |    2 +
 .../Locale/en-US/store/uplink-catalog.ftl     |    6 +
 .../Locale/ru-RU/prototypes/actions/types.ftl |    8 +
 .../entities/clothing/eyes/goggles.ftl        |   23 +
 .../objects/tools/empflashlight.ftl           |    0
 .../Locale/ru-RU/research/techologies.ftl     |    2 +
 .../Locale/ru-RU/store/uplink-catalog.ftl     |    7 +
 Resources/Prototypes/Actions/types.yml        |   41 +-
 .../Prototypes/Catalog/Fills/Lockers/misc.yml |    8 +-
 .../Prototypes/Catalog/uplink_catalog.yml     |   72 +
 .../Entities/Clothing/Eyes/glasses.yml        |    1 +
 .../Entities/Clothing/Eyes/goggles.yml        |  114 ++
 .../Clothing/Head/hardsuit-helmets.yml        |    3 +
 .../Mobs/Cyborgs/base_borg_chassis.yml        |    1 +
 .../Prototypes/Entities/Mobs/NPCs/animals.yml |   12 +
 .../Prototypes/Entities/Mobs/NPCs/carp.yml    |    6 +
 .../Entities/Mobs/NPCs/regalrat.yml           |   12 +
 .../Prototypes/Entities/Mobs/NPCs/xeno.yml    |    6 +
 .../Entities/Mobs/Player/admin_ghost.yml      |    1 +
 .../Entities/Mobs/Player/dragon.yml           |    5 +
 .../Entities/Mobs/Player/silicon_base.yml     |    1 +
 .../Entities/Structures/Machines/lathe.yml    | 1621 +++++++++--------
 .../Prototypes/Procedural/salvage_loot.yml    |    4 +
 .../Prototypes/Recipes/Lathes/devices.yml     |   30 +
 .../Prototypes/Recipes/Lathes/medical.yml     |   13 +-
 .../Prototypes/Recipes/Lathes/security.yml    |   12 +-
 .../Prototypes/Research/experimental.yml      |   27 +
 Resources/Prototypes/Shaders/shaders.yml      |    7 +-
 .../Entities/Clothing/Cult/armor.yml          |    8 +-
 .../equipped-EYES-off.png                     |  Bin 0 -> 452 bytes
 .../equipped-EYES.png                         |  Bin 0 -> 739 bytes
 .../diagnostic_nightvision.rsi/icon.png       |  Bin 0 -> 306 bytes
 .../inhand-left.png                           |  Bin 0 -> 233 bytes
 .../inhand-right.png                          |  Bin 0 -> 230 bytes
 .../diagnostic_nightvision.rsi/meta.json      |   48 +
 .../equipped-EYES-off.png                     |  Bin 0 -> 452 bytes
 .../medical_nightvision.rsi/equipped-EYES.png |  Bin 0 -> 733 bytes
 .../Goggles/medical_nightvision.rsi/icon.png  |  Bin 0 -> 306 bytes
 .../medical_nightvision.rsi/inhand-left.png   |  Bin 0 -> 233 bytes
 .../medical_nightvision.rsi/inhand-right.png  |  Bin 0 -> 230 bytes
 .../Goggles/medical_nightvision.rsi/meta.json |   48 +
 .../monocle_thermal.rsi/equipped-EYES-off.png |  Bin 0 -> 477 bytes
 .../monocle_thermal.rsi/equipped-EYES.png     |  Bin 0 -> 410 bytes
 .../Eyes/Goggles/monocle_thermal.rsi/icon.png |  Bin 0 -> 298 bytes
 .../Goggles/monocle_thermal.rsi/meta.json     |   22 +
 .../nightvision.rsi/equipped-EYES-off.png     |  Bin 0 -> 452 bytes
 .../Goggles/nightvision.rsi/equipped-EYES.png |  Bin 0 -> 719 bytes
 .../Eyes/Goggles/nightvision.rsi/icon.png     |  Bin 0 -> 218 bytes
 .../Goggles/nightvision.rsi/inhand-left.png   |  Bin 0 -> 385 bytes
 .../Goggles/nightvision.rsi/inhand-right.png  |  Bin 0 -> 410 bytes
 .../Eyes/Goggles/nightvision.rsi/meta.json    |   48 +
 .../equipped-EYES-off.png                     |  Bin 0 -> 452 bytes
 .../equipped-EYES.png                         |  Bin 0 -> 704 bytes
 .../Goggles/security_nightvision.rsi/icon.png |  Bin 0 -> 505 bytes
 .../security_nightvision.rsi/inhand-left.png  |  Bin 0 -> 233 bytes
 .../security_nightvision.rsi/inhand-right.png |  Bin 0 -> 309 bytes
 .../security_nightvision.rsi/meta.json        |   48 +
 .../Goggles/thermal.rsi/equipped-EYES.png     |  Bin 0 -> 524 bytes
 .../Eyes/Goggles/thermal.rsi/icon.png         |  Bin 0 -> 510 bytes
 .../Eyes/Goggles/thermal.rsi/inhand-left.png  |  Bin 0 -> 327 bytes
 .../Eyes/Goggles/thermal.rsi/inhand-right.png |  Bin 0 -> 325 bytes
 .../Eyes/Goggles/thermal.rsi/meta.json        |   26 +
 Resources/Textures/Shaders/nightvision.swsl   |   38 +
 81 files changed, 2192 insertions(+), 818 deletions(-)
 create mode 100644 Content.Client/Overlays/Switchable/BaseSwitchableOverlay.cs
 create mode 100644 Content.Client/Overlays/Switchable/NightVisionSystem.cs
 create mode 100644 Content.Client/Overlays/Switchable/ThermalVisionOverlay.cs
 create mode 100644 Content.Client/Overlays/Switchable/ThermalVisionSystem.cs
 create mode 100644 Content.Shared/Overlays/BaseOverlayComponent.cs
 create mode 100644 Content.Shared/Overlays/Switchable/NightVisionComponent.cs
 create mode 100644 Content.Shared/Overlays/Switchable/NightVisionSystem.cs
 create mode 100644 Content.Shared/Overlays/Switchable/SwitchableOverlayComponent.cs
 create mode 100644 Content.Shared/Overlays/Switchable/SwitchableOverlaySystem.cs
 create mode 100644 Content.Shared/Overlays/Switchable/ThermalVisionComponent.cs
 create mode 100644 Content.Shared/Overlays/Switchable/ThermalVisionSystem.cs
 create mode 100644 Resources/Audio/Items/Goggles/activate.ogg
 create mode 100644 Resources/Audio/Items/Goggles/attributions.yml
 create mode 100644 Resources/Audio/Items/Goggles/deactivate.ogg
 create mode 100644 Resources/Locale/ru-RU/prototypes/actions/types.ftl
 create mode 100644 Resources/Locale/ru-RU/prototypes/entities/clothing/eyes/goggles.ftl
 rename Resources/Locale/ru-RU/{entities => prototypes}/objects/tools/empflashlight.ftl (100%)
 create mode 100644 Resources/Locale/ru-RU/research/techologies.ftl
 create mode 100644 Resources/Prototypes/Entities/Clothing/Eyes/goggles.yml
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/equipped-EYES-off.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/equipped-EYES.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/equipped-EYES-off.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/equipped-EYES.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/equipped-EYES-off.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/equipped-EYES.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/equipped-EYES-off.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/equipped-EYES.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/equipped-EYES-off.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/equipped-EYES.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/meta.json
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/equipped-EYES.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/icon.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/inhand-left.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/inhand-right.png
 create mode 100644 Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/meta.json
 create mode 100644 Resources/Textures/Shaders/nightvision.swsl

diff --git a/Content.Client/Overlays/EquipmentHudSystem.cs b/Content.Client/Overlays/EquipmentHudSystem.cs
index c7578b6793..3672892ae3 100644
--- a/Content.Client/Overlays/EquipmentHudSystem.cs
+++ b/Content.Client/Overlays/EquipmentHudSystem.cs
@@ -102,7 +102,7 @@ protected virtual void OnRefreshComponentHud(EntityUid uid, T component, Refresh
         args.Components.Add(component);
     }
 
-    private void RefreshOverlay(EntityUid uid)
+    protected void RefreshOverlay(EntityUid uid)
     {
         if (uid != _player.LocalSession?.AttachedEntity)
             return;
diff --git a/Content.Client/Overlays/Switchable/BaseSwitchableOverlay.cs b/Content.Client/Overlays/Switchable/BaseSwitchableOverlay.cs
new file mode 100644
index 0000000000..5977355968
--- /dev/null
+++ b/Content.Client/Overlays/Switchable/BaseSwitchableOverlay.cs
@@ -0,0 +1,48 @@
+using System.Numerics;
+using Content.Shared.Overlays.Switchable;
+using Robust.Client.Graphics;
+using Robust.Shared.Enums;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Overlays.Switchable;
+
+public sealed class BaseSwitchableOverlay<TComp> : Overlay where TComp : SwitchableOverlayComponent
+{
+    [Dependency] private readonly IPrototypeManager _prototype = default!;
+
+    public override bool RequestScreenTexture => true;
+    public override OverlaySpace Space => OverlaySpace.WorldSpace;
+
+    private readonly ShaderInstance _shader;
+
+    public TComp? Comp = null;
+
+    public bool IsActive = true;
+
+    public BaseSwitchableOverlay()
+    {
+        IoCManager.InjectDependencies(this);
+        _shader = _prototype.Index<ShaderPrototype>("NightVision").InstanceUnique();
+    }
+
+    protected override void Draw(in OverlayDrawArgs args)
+    {
+        if (ScreenTexture is null || Comp is null || !IsActive)
+            return;
+
+        _shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
+        _shader.SetParameter("tint", Comp.Tint);
+        _shader.SetParameter("luminance_threshold", Comp.Strength);
+        _shader.SetParameter("noise_amount", Comp.Noise);
+
+        var worldHandle = args.WorldHandle;
+
+        var accumulator = Math.Clamp(Comp.PulseAccumulator, 0f, Comp.PulseTime);
+        var alpha = Comp.PulseTime <= 0f ? 1f : float.Lerp(1f, 0f, accumulator / Comp.PulseTime);
+
+        worldHandle.SetTransform(Matrix3x2.Identity);
+        worldHandle.UseShader(_shader);
+        worldHandle.DrawRect(args.WorldBounds, Comp.Color.WithAlpha(alpha));
+        worldHandle.UseShader(null);
+    }
+}
diff --git a/Content.Client/Overlays/Switchable/NightVisionSystem.cs b/Content.Client/Overlays/Switchable/NightVisionSystem.cs
new file mode 100644
index 0000000000..c85b3758d8
--- /dev/null
+++ b/Content.Client/Overlays/Switchable/NightVisionSystem.cs
@@ -0,0 +1,87 @@
+using Content.Shared.Inventory.Events;
+using Content.Shared.Overlays.Switchable;
+using Robust.Client.Graphics;
+
+namespace Content.Client.Overlays.Switchable;
+
+public sealed class NightVisionSystem : EquipmentHudSystem<NightVisionComponent>
+{
+    [Dependency] private readonly IOverlayManager _overlayMan = default!;
+    [Dependency] private readonly ILightManager _lightManager = default!;
+
+    private BaseSwitchableOverlay<NightVisionComponent> _overlay = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<NightVisionComponent, SwitchableOverlayToggledEvent>(OnToggle);
+
+        _overlay = new BaseSwitchableOverlay<NightVisionComponent>();
+    }
+
+    private void OnToggle(Entity<NightVisionComponent> ent, ref SwitchableOverlayToggledEvent args)
+    {
+        RefreshOverlay(args.User);
+    }
+
+    protected override void UpdateInternal(RefreshEquipmentHudEvent<NightVisionComponent> args)
+    {
+        base.UpdateInternal(args);
+
+        var active = false;
+        NightVisionComponent? nvComp = null;
+        foreach (var comp in args.Components)
+        {
+            if (comp.IsActive || comp.PulseTime > 0f && comp.PulseAccumulator < comp.PulseTime)
+                active = true;
+            else
+                continue;
+
+            if (comp.DrawOverlay)
+            {
+                if (nvComp == null)
+                    nvComp = comp;
+                else if (nvComp.PulseTime > 0f && comp.PulseTime <= 0f)
+                    nvComp = comp;
+            }
+
+            if (active && nvComp is { PulseTime: <= 0 })
+                break;
+        }
+
+        UpdateNightVision(active);
+        UpdateOverlay(nvComp);
+    }
+
+    protected override void DeactivateInternal()
+    {
+        base.DeactivateInternal();
+
+        UpdateNightVision(false);
+        UpdateOverlay(null);
+    }
+
+    private void UpdateNightVision(bool active)
+    {
+        _lightManager.DrawLighting = !active;
+    }
+
+    private void UpdateOverlay(NightVisionComponent? nvComp)
+    {
+        _overlay.Comp = nvComp;
+
+        switch (nvComp)
+        {
+            case not null when !_overlayMan.HasOverlay<BaseSwitchableOverlay<NightVisionComponent>>():
+                _overlayMan.AddOverlay(_overlay);
+                break;
+            case null:
+                _overlayMan.RemoveOverlay(_overlay);
+                break;
+        }
+
+        if (_overlayMan.TryGetOverlay<BaseSwitchableOverlay<ThermalVisionComponent>>(out var overlay))
+            overlay.IsActive = nvComp == null;
+    }
+}
diff --git a/Content.Client/Overlays/Switchable/ThermalVisionOverlay.cs b/Content.Client/Overlays/Switchable/ThermalVisionOverlay.cs
new file mode 100644
index 0000000000..eb12b33e3a
--- /dev/null
+++ b/Content.Client/Overlays/Switchable/ThermalVisionOverlay.cs
@@ -0,0 +1,159 @@
+using System.Linq;
+using System.Numerics;
+using Content.Client.Stealth;
+using Content.Shared.Body.Components;
+using Content.Shared.Overlays.Switchable;
+using Content.Shared.Stealth.Components;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
+using Robust.Client.Player;
+using Robust.Shared.Enums;
+using Robust.Shared.Map;
+using Robust.Shared.Timing;
+
+namespace Content.Client.Overlays.Switchable;
+
+public sealed class ThermalVisionOverlay : Overlay
+{
+    [Dependency] private readonly IEntityManager _entity = default!;
+    [Dependency] private readonly IPlayerManager _player = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
+
+    private readonly TransformSystem _transform;
+    private readonly StealthSystem _stealth;
+    private readonly ContainerSystem _container;
+    private readonly SharedPointLightSystem _light;
+
+    public override bool RequestScreenTexture => true;
+    public override OverlaySpace Space => OverlaySpace.WorldSpace;
+
+    private readonly List<ThermalVisionRenderEntry> _entries = [];
+
+    private EntityUid? _lightEntity;
+
+    public float LightRadius;
+
+    public ThermalVisionComponent? Comp;
+
+    public ThermalVisionOverlay()
+    {
+        IoCManager.InjectDependencies(this);
+
+        _container = _entity.System<ContainerSystem>();
+        _transform = _entity.System<TransformSystem>();
+        _stealth = _entity.System<StealthSystem>();
+        _light = _entity.System<SharedPointLightSystem>();
+
+        ZIndex = -1;
+    }
+
+    protected override void Draw(in OverlayDrawArgs args)
+    {
+        if (ScreenTexture is null || Comp is null)
+            return;
+
+        var worldHandle = args.WorldHandle;
+        var eye = args.Viewport.Eye;
+
+        if (eye == null)
+            return;
+
+        var player = _player.LocalEntity;
+
+        if (!_entity.TryGetComponent(player, out TransformComponent? playerXform))
+            return;
+
+        var accumulator = Math.Clamp(Comp.PulseAccumulator, 0f, Comp.PulseTime);
+        var alpha = Comp.PulseTime <= 0f ? 1f : float.Lerp(1f, 0f, accumulator / Comp.PulseTime);
+
+        // Thermal vision grants some night vision (clientside light)
+        if (LightRadius > 0)
+        {
+            _lightEntity ??= _entity.SpawnAttachedTo(null, playerXform.Coordinates);
+            _transform.SetParent(_lightEntity.Value, player.Value);
+            var light = _entity.EnsureComponent<PointLightComponent>(_lightEntity.Value);
+            _light.SetRadius(_lightEntity.Value, LightRadius, light);
+            _light.SetEnergy(_lightEntity.Value, alpha, light);
+            _light.SetColor(_lightEntity.Value, Comp.Color, light);
+        }
+        else
+            ResetLight();
+
+        var mapId = eye.Position.MapId;
+        var eyeRot = eye.Rotation;
+
+        _entries.Clear();
+        var entities = _entity.EntityQueryEnumerator<BodyComponent, SpriteComponent, TransformComponent>();
+        while (entities.MoveNext(out var uid, out var body, out var sprite, out var xform))
+        {
+            if (!CanSee(uid, sprite) || !body.ThermalVisibility)
+                continue;
+
+            var entity = uid;
+
+            if (_container.TryGetOuterContainer(uid, xform, out var container))
+            {
+                var owner = container.Owner;
+                if (_entity.TryGetComponent<SpriteComponent>(owner, out var ownerSprite)
+                    && _entity.TryGetComponent<TransformComponent>(owner, out var ownerXform))
+                {
+                    entity = owner;
+                    sprite = ownerSprite;
+                    xform = ownerXform;
+                }
+            }
+
+            if (_entries.Any(e => e.Ent.Owner == entity))
+                continue;
+
+            _entries.Add(new ThermalVisionRenderEntry((entity, sprite, xform), mapId, eyeRot));
+        }
+
+        foreach (var entry in _entries)
+        {
+            Render(entry.Ent, entry.Map, worldHandle, entry.EyeRot, Comp.Color, alpha);
+        }
+
+        worldHandle.SetTransform(Matrix3x2.Identity);
+    }
+
+    private void Render(Entity<SpriteComponent, TransformComponent> ent,
+        MapId? map,
+        DrawingHandleWorld handle,
+        Angle eyeRot,
+        Color color,
+        float alpha)
+    {
+        var (uid, sprite, xform) = ent;
+        if (xform.MapID != map || !CanSee(uid, sprite))
+            return;
+
+        var position = _transform.GetWorldPosition(xform);
+        var rotation = _transform.GetWorldRotation(xform);
+
+        var originalColor = sprite.Color;
+        sprite.Color = color.WithAlpha(alpha);
+        sprite.Render(handle, eyeRot, rotation, position: position);
+        sprite.Color = originalColor;
+    }
+
+    private bool CanSee(EntityUid uid, SpriteComponent sprite)
+    {
+        return sprite.Visible && (!_entity.TryGetComponent(uid, out StealthComponent? stealth) ||
+                                  _stealth.GetVisibility(uid, stealth) > 0.5f);
+    }
+
+    public void ResetLight()
+    {
+        if (_lightEntity == null || !_timing.IsFirstTimePredicted)
+            return;
+
+        _entity.DeleteEntity(_lightEntity);
+        _lightEntity = null;
+    }
+}
+
+public record struct ThermalVisionRenderEntry(
+    Entity<SpriteComponent, TransformComponent> Ent,
+    MapId? Map,
+    Angle EyeRot);
diff --git a/Content.Client/Overlays/Switchable/ThermalVisionSystem.cs b/Content.Client/Overlays/Switchable/ThermalVisionSystem.cs
new file mode 100644
index 0000000000..9b6e5eed0f
--- /dev/null
+++ b/Content.Client/Overlays/Switchable/ThermalVisionSystem.cs
@@ -0,0 +1,95 @@
+using Content.Shared.Inventory.Events;
+using Content.Shared.Overlays.Switchable;
+using Robust.Client.Graphics;
+
+namespace Content.Client.Overlays.Switchable;
+
+public sealed class ThermalVisionSystem : EquipmentHudSystem<ThermalVisionComponent>
+{
+    [Dependency] private readonly IOverlayManager _overlayMan = default!;
+
+    private ThermalVisionOverlay _thermalOverlay = default!;
+    private BaseSwitchableOverlay<ThermalVisionComponent> _overlay = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<ThermalVisionComponent, SwitchableOverlayToggledEvent>(OnToggle);
+
+        _thermalOverlay = new ThermalVisionOverlay();
+        _overlay = new BaseSwitchableOverlay<ThermalVisionComponent>();
+    }
+
+    private void OnToggle(Entity<ThermalVisionComponent> ent, ref SwitchableOverlayToggledEvent args)
+    {
+        RefreshOverlay(args.User);
+    }
+
+    protected override void UpdateInternal(RefreshEquipmentHudEvent<ThermalVisionComponent> args)
+    {
+        base.UpdateInternal(args);
+        ThermalVisionComponent? tvComp = null;
+        var lightRadius = 0f;
+        foreach (var comp in args.Components)
+        {
+            if (!comp.IsActive && (comp.PulseTime <= 0f || comp.PulseAccumulator >= comp.PulseTime))
+                continue;
+
+            if (tvComp == null)
+                tvComp = comp;
+            else if (!tvComp.DrawOverlay && comp.DrawOverlay)
+                tvComp = comp;
+            else if (tvComp.DrawOverlay == comp.DrawOverlay && tvComp.PulseTime > 0f && comp.PulseTime <= 0f)
+                tvComp = comp;
+
+            lightRadius = MathF.Max(lightRadius, comp.LightRadius);
+        }
+
+        UpdateThermalOverlay(tvComp, lightRadius);
+        UpdateOverlay(tvComp);
+    }
+
+    protected override void DeactivateInternal()
+    {
+        base.DeactivateInternal();
+
+        UpdateOverlay(null);
+        UpdateThermalOverlay(null, 0f);
+    }
+
+    private void UpdateThermalOverlay(ThermalVisionComponent? comp, float lightRadius)
+    {
+        _thermalOverlay.LightRadius = lightRadius;
+        _thermalOverlay.Comp = comp;
+
+        switch (comp)
+        {
+            case not null when !_overlayMan.HasOverlay<ThermalVisionOverlay>():
+                _overlayMan.AddOverlay(_thermalOverlay);
+                break;
+            case null:
+                _overlayMan.RemoveOverlay(_thermalOverlay);
+                _thermalOverlay.ResetLight();
+                break;
+        }
+    }
+
+    private void UpdateOverlay(ThermalVisionComponent? tvComp)
+    {
+        _overlay.Comp = tvComp;
+
+        switch (tvComp)
+        {
+            case { DrawOverlay: true } when !_overlayMan.HasOverlay<BaseSwitchableOverlay<ThermalVisionComponent>>():
+                _overlayMan.AddOverlay(_overlay);
+                break;
+            case null or { DrawOverlay: false }:
+                _overlayMan.RemoveOverlay(_overlay);
+                break;
+        }
+
+        // Night vision overlay is prioritized
+        _overlay.IsActive = !_overlayMan.HasOverlay<BaseSwitchableOverlay<NightVisionComponent>>();
+    }
+}
diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs
index 91acf47478..8cede391a8 100644
--- a/Content.Shared/Actions/SharedActionsSystem.cs
+++ b/Content.Shared/Actions/SharedActionsSystem.cs
@@ -14,6 +14,7 @@
 using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
 using Robust.Shared.Map;
+using Robust.Shared.Network;
 using Robust.Shared.Timing;
 using Robust.Shared.Utility;
 
@@ -23,6 +24,8 @@ public abstract class SharedActionsSystem : EntitySystem
 {
     [Dependency] protected readonly IGameTiming GameTiming = default!;
     [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
+    [Dependency] private readonly INetManager _net = default!;
+
     [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
     [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
     [Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!;
@@ -774,7 +777,7 @@ public bool AddActionDirect(EntityUid performer,
         if (!ResolveActionData(actionId, ref action))
             return false;
 
-        DebugTools.Assert(action.Container == null ||
+        DebugTools.Assert(_net.IsClient || action.Container == null ||
                           (TryComp(action.Container, out ActionsContainerComponent? containerComp)
                            && containerComp.Container.Contains(actionId)));
 
diff --git a/Content.Shared/Body/Components/BodyComponent.cs b/Content.Shared/Body/Components/BodyComponent.cs
index 481e22150b..4ddfbdf979 100644
--- a/Content.Shared/Body/Components/BodyComponent.cs
+++ b/Content.Shared/Body/Components/BodyComponent.cs
@@ -41,4 +41,7 @@ public sealed partial class BodyComponent : Component
     [ViewVariables]
     [DataField, AutoNetworkedField]
     public HashSet<EntityUid> LegEntities = new();
+
+    [DataField, AutoNetworkedField]
+    public bool ThermalVisibility = true;
 }
diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs
index 9d263a6098..4375f1ab19 100644
--- a/Content.Shared/Inventory/InventorySystem.Relay.cs
+++ b/Content.Shared/Inventory/InventorySystem.Relay.cs
@@ -20,6 +20,8 @@
 using Content.Shared.Verbs;
 using Content.Shared.Weapons.Ranged.Events;
 using Content.Shared.Chat;
+using Content.Shared.Overlays.Switchable;
+
 
 namespace Content.Shared.Inventory;
 
@@ -63,6 +65,8 @@ public void InitializeRelay()
         SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowMindShieldIconsComponent>>(RelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSyndicateIconsComponent>>(RelayInventoryEvent);
         SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowCriminalRecordIconsComponent>>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<NightVisionComponent>>(RelayInventoryEvent);
+        SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ThermalVisionComponent>>(RelayInventoryEvent);
 
         SubscribeLocalEvent<InventoryComponent, GetVerbsEvent<EquipmentVerb>>(OnGetEquipmentVerbs);
     }
diff --git a/Content.Shared/Overlays/BaseOverlayComponent.cs b/Content.Shared/Overlays/BaseOverlayComponent.cs
new file mode 100644
index 0000000000..fe6a5c763e
--- /dev/null
+++ b/Content.Shared/Overlays/BaseOverlayComponent.cs
@@ -0,0 +1,16 @@
+namespace Content.Shared.Overlays;
+
+public abstract partial class BaseOverlayComponent : Component
+{
+    [DataField, ViewVariables(VVAccess.ReadOnly)]
+    public virtual Vector3 Tint { get; set; } = new(0.3f, 0.3f, 0.3f);
+
+    [DataField, ViewVariables(VVAccess.ReadOnly)]
+    public virtual float Strength { get; set; } = 2f;
+
+    [DataField, ViewVariables(VVAccess.ReadOnly)]
+    public virtual float Noise { get; set; } = 0.5f;
+
+    [DataField, ViewVariables(VVAccess.ReadOnly)]
+    public virtual Color Color { get; set; } = Color.White;
+}
diff --git a/Content.Shared/Overlays/Switchable/NightVisionComponent.cs b/Content.Shared/Overlays/Switchable/NightVisionComponent.cs
new file mode 100644
index 0000000000..cb8866dc85
--- /dev/null
+++ b/Content.Shared/Overlays/Switchable/NightVisionComponent.cs
@@ -0,0 +1,14 @@
+using Content.Shared.Actions;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Overlays.Switchable;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class NightVisionComponent : SwitchableOverlayComponent
+{
+    public override string? ToggleAction { get; set; } = "ToggleNightVision";
+
+    public override Color Color { get; set; } = Color.FromHex("#98FB98");
+}
+
+public sealed partial class ToggleNightVisionEvent : InstantActionEvent;
diff --git a/Content.Shared/Overlays/Switchable/NightVisionSystem.cs b/Content.Shared/Overlays/Switchable/NightVisionSystem.cs
new file mode 100644
index 0000000000..f547b9dc76
--- /dev/null
+++ b/Content.Shared/Overlays/Switchable/NightVisionSystem.cs
@@ -0,0 +1,3 @@
+namespace Content.Shared.Overlays.Switchable;
+
+public sealed class NightVisionSystem : SwitchableOverlaySystem<NightVisionComponent, ToggleNightVisionEvent>;
diff --git a/Content.Shared/Overlays/Switchable/SwitchableOverlayComponent.cs b/Content.Shared/Overlays/Switchable/SwitchableOverlayComponent.cs
new file mode 100644
index 0000000000..8565defe04
--- /dev/null
+++ b/Content.Shared/Overlays/Switchable/SwitchableOverlayComponent.cs
@@ -0,0 +1,48 @@
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Overlays.Switchable;
+
+public abstract partial class SwitchableOverlayComponent : BaseOverlayComponent
+{
+    [DataField, AutoNetworkedField]
+    public bool IsActive;
+
+    [DataField]
+    public bool DrawOverlay = true;
+
+    /// <summary>
+    /// If it is greater than 0, overlay isn't toggled but pulsed instead
+    /// </summary>
+    [DataField]
+    public float PulseTime;
+
+    [ViewVariables(VVAccess.ReadOnly)]
+    public float PulseAccumulator;
+
+    [DataField]
+    public virtual SoundSpecifier? ActivateSound { get; set; } =
+        new SoundPathSpecifier("/Audio/Items/Goggles/activate.ogg");
+
+    [DataField]
+    public virtual SoundSpecifier? DeactivateSound { get; set; } =
+        new SoundPathSpecifier("/Audio/Items/Goggles/deactivate.ogg");
+
+    [DataField]
+    public virtual string? ToggleAction { get; set; }
+
+    [ViewVariables]
+    public EntityUid? ToggleActionEntity;
+}
+
+[Serializable, NetSerializable]
+public sealed class SwitchableVisionOverlayComponentState : IComponentState
+{
+    public Color Color;
+    public bool IsActive;
+    public SoundSpecifier? ActivateSound;
+    public SoundSpecifier? DeactivateSound;
+    public EntProtoId? ToggleAction;
+    public float LightRadius;
+}
diff --git a/Content.Shared/Overlays/Switchable/SwitchableOverlaySystem.cs b/Content.Shared/Overlays/Switchable/SwitchableOverlaySystem.cs
new file mode 100644
index 0000000000..eb7b230cbc
--- /dev/null
+++ b/Content.Shared/Overlays/Switchable/SwitchableOverlaySystem.cs
@@ -0,0 +1,166 @@
+using Content.Shared.Actions;
+using Content.Shared.Inventory;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.GameStates;
+using Robust.Shared.Network;
+using Robust.Shared.Player;
+using Robust.Shared.Timing;
+
+namespace Content.Shared.Overlays.Switchable;
+
+public abstract class SwitchableOverlaySystem<TComp, TEvent> : EntitySystem
+    where TComp : SwitchableOverlayComponent
+    where TEvent : InstantActionEvent
+{
+    [Dependency] private readonly SharedAudioSystem _audio = default!;
+    [Dependency] private readonly SharedActionsSystem _actions = default!;
+    [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly INetManager _net = default!;
+
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<TComp, TEvent>(OnToggle);
+        SubscribeLocalEvent<TComp, ComponentInit>(OnInit);
+        SubscribeLocalEvent<TComp, MapInitEvent>(OnMapInit);
+        SubscribeLocalEvent<TComp, ComponentShutdown>(OnShutdown);
+        SubscribeLocalEvent<TComp, GetItemActionsEvent>(OnGetItemActions);
+        SubscribeLocalEvent<TComp, ComponentGetState>(OnGetState);
+        SubscribeLocalEvent<TComp, ComponentHandleState>(OnHandleState);
+    }
+
+    public override void FrameUpdate(float frameTime)
+    {
+        base.FrameUpdate(frameTime);
+
+        if (_net.IsClient)
+            ActiveTick(frameTime);
+    }
+
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
+
+        if (_net.IsServer)
+            ActiveTick(frameTime);
+    }
+
+    private void ActiveTick(float frameTime)
+    {
+        var query = EntityQueryEnumerator<TComp>();
+
+        while (query.MoveNext(out var uid, out var comp))
+        {
+            if (comp.PulseTime <= 0f || comp.PulseAccumulator >= comp.PulseTime)
+                continue;
+
+            comp.PulseAccumulator += frameTime;
+
+            if (comp.PulseAccumulator < comp.PulseTime)
+                continue;
+
+            Toggle(uid, comp, false, false);
+            RaiseSwitchableOverlayToggledEvent(uid, uid, comp.IsActive);
+            RaiseSwitchableOverlayToggledEvent(uid, Transform(uid).ParentUid, comp.IsActive);
+        }
+    }
+
+    private void OnGetState(EntityUid uid, TComp component, ref ComponentGetState args)
+    {
+        args.State = new SwitchableVisionOverlayComponentState
+        {
+            Color = component.Color,
+            IsActive = component.IsActive,
+            ActivateSound = component.ActivateSound,
+            DeactivateSound = component.DeactivateSound,
+            ToggleAction = component.ToggleAction,
+            LightRadius = component is ThermalVisionComponent thermal ? thermal.LightRadius : 0f,
+        };
+    }
+
+    private void OnHandleState(EntityUid uid, TComp component, ref ComponentHandleState args)
+    {
+        if (args.Current is not SwitchableVisionOverlayComponentState state)
+            return;
+
+        component.Color = state.Color;
+        component.ActivateSound = state.ActivateSound;
+        component.DeactivateSound = state.DeactivateSound;
+
+        if (component.ToggleAction != state.ToggleAction)
+        {
+            _actions.RemoveAction(uid, component.ToggleActionEntity);
+            component.ToggleAction = state.ToggleAction;
+            if (component.ToggleAction != null)
+                _actions.AddAction(uid, ref component.ToggleActionEntity, component.ToggleAction);
+        }
+
+        if (component is ThermalVisionComponent thermal)
+            thermal.LightRadius = state.LightRadius;
+
+        if (component.IsActive == state.IsActive)
+            return;
+
+        component.IsActive = state.IsActive;
+
+        RaiseSwitchableOverlayToggledEvent(uid, uid, component.IsActive);
+        RaiseSwitchableOverlayToggledEvent(uid, Transform(uid).ParentUid, component.IsActive);
+    }
+
+    private void OnGetItemActions(Entity<TComp> ent, ref GetItemActionsEvent args)
+    {
+        if (ent.Comp.ToggleAction != null && args.SlotFlags is not SlotFlags.POCKET and not null)
+            args.AddAction(ref ent.Comp.ToggleActionEntity, ent.Comp.ToggleAction);
+    }
+
+    private void OnShutdown(EntityUid uid, TComp component, ComponentShutdown args)
+    {
+        _actions.RemoveAction(uid, component.ToggleActionEntity);
+    }
+
+    private void OnInit(EntityUid uid, TComp component, ComponentInit args)
+    {
+        component.PulseAccumulator = component.PulseTime;
+    }
+
+    private void OnMapInit(EntityUid uid, TComp component, MapInitEvent args)
+    {
+        if (component.ToggleActionEntity == null && component.ToggleAction != null)
+            _actions.AddAction(uid, ref component.ToggleActionEntity, component.ToggleAction);
+    }
+
+    private void OnToggle(EntityUid uid, TComp component, TEvent args)
+    {
+        Toggle(uid, component, !component.IsActive);
+        RaiseSwitchableOverlayToggledEvent(uid, args.Performer, component.IsActive);
+        args.Handled = true;
+    }
+
+    private void Toggle(EntityUid uid, TComp component, bool activate, bool playSound = true)
+    {
+        if (playSound && _net.IsClient && _timing.IsFirstTimePredicted)
+        {
+            _audio.PlayEntity(activate ? component.ActivateSound : component.DeactivateSound,
+                Filter.Local(),
+                uid,
+                false);
+        }
+
+        if (component.PulseTime > 0f)
+        {
+            component.PulseAccumulator = activate ? 0f : component.PulseTime;
+            return;
+        }
+
+        component.IsActive = activate;
+        Dirty(uid, component);
+    }
+
+    private void RaiseSwitchableOverlayToggledEvent(EntityUid uid, EntityUid user, bool activated)
+    {
+        var ev = new SwitchableOverlayToggledEvent(user, activated);
+        RaiseLocalEvent(uid, ref ev);
+    }
+}
+
+[ByRefEvent]
+public record struct SwitchableOverlayToggledEvent(EntityUid User, bool Activated);
diff --git a/Content.Shared/Overlays/Switchable/ThermalVisionComponent.cs b/Content.Shared/Overlays/Switchable/ThermalVisionComponent.cs
new file mode 100644
index 0000000000..6e3d39f289
--- /dev/null
+++ b/Content.Shared/Overlays/Switchable/ThermalVisionComponent.cs
@@ -0,0 +1,17 @@
+using Content.Shared.Actions;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Overlays.Switchable;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class ThermalVisionComponent : SwitchableOverlayComponent
+{
+    public override string? ToggleAction { get; set; } = "ToggleThermalVision";
+
+    public override Color Color { get; set; } = Color.FromHex("#F84742");
+
+    [DataField]
+    public float LightRadius = 5f;
+}
+
+public sealed partial class ToggleThermalVisionEvent : InstantActionEvent;
diff --git a/Content.Shared/Overlays/Switchable/ThermalVisionSystem.cs b/Content.Shared/Overlays/Switchable/ThermalVisionSystem.cs
new file mode 100644
index 0000000000..c19d0d1690
--- /dev/null
+++ b/Content.Shared/Overlays/Switchable/ThermalVisionSystem.cs
@@ -0,0 +1,3 @@
+namespace Content.Shared.Overlays.Switchable;
+
+public sealed class SharedThermalVisionSystem : SwitchableOverlaySystem<ThermalVisionComponent, ToggleThermalVisionEvent>;
diff --git a/Resources/Audio/Items/Goggles/activate.ogg b/Resources/Audio/Items/Goggles/activate.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..96cdb288fe07d0e1d3c0f38774cb7ffe01624724
GIT binary patch
literal 12048
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

literal 0
HcmV?d00001

diff --git a/Resources/Audio/Items/Goggles/attributions.yml b/Resources/Audio/Items/Goggles/attributions.yml
new file mode 100644
index 0000000000..7b1121f542
--- /dev/null
+++ b/Resources/Audio/Items/Goggles/attributions.yml
@@ -0,0 +1,9 @@
+- files: ["activate.ogg"]
+  license: "CC-BY-NC-SA-3.0"
+  copyright: "Taken from TGstation"
+  source: "https://github.com/tgstation/tgstation"
+
+- files: ["deactivate.ogg"]
+  license: "CC-BY-NC-SA-3.0"
+  copyright: "Taken from TGstation"
+  source: "https://github.com/tgstation/tgstation"
\ No newline at end of file
diff --git a/Resources/Audio/Items/Goggles/deactivate.ogg b/Resources/Audio/Items/Goggles/deactivate.ogg
new file mode 100644
index 0000000000000000000000000000000000000000..e1e8f4fd82fcfa0b0c01c28b4ec93f53bbb2c2de
GIT binary patch
literal 12424
zcmaiabzD@<*Z5t!MM_#?X;d1P?pQ!%VQHkh6j-D|X{5VD>5@i35R~plq?DFMQW5xF
ze7@i3ec!)+^O<}1%*mNEXJ*d5cQtHmv;Z{VKjphKuF@@-aPJ}(LJ#q9aW%JdyG20c
zD{g-PAW#JI_xC+S<5u$Daw~aDX`0m}zH_5_^S{bV^ndgaf@C!_4{Je@hr&V+d3ktn
zKm-AJIhr}!pv-KnBv8(lRAAfI%-Pb>%GJc#%*jeZ%LT+L|AV0bi5^zYmM*R)c9s%`
zJjVZ429RRqY~f;Q<thQ%umElF@(bJ=VQ{oF|HnQt$m3*Y4+@*Rg8C%X1!NfR-s0?>
zL7az`tDBvRvxFcoA2o=yaB+HO=5A;1X!Q@bn}nU4ixYV9`GHh<1uZ#*$`frBjmHv5
zcRNQrcQ0-R8!Izc1}7H}D<>;wcQ<YZEnOLHZU%QV3wJvUGe>R)tLG@YXSXzN25T2b
zD^SAinU#f|nIqVAwXgyup1C;MSy+LZTx@I{ZxQacR<2IBvd(rkw(blbcDG%GVE!{6
zCRsTh2p|mrP&Z0W#X>iVU}9?7CseDnvLg<=RI+M!U(xcZ84j|z#W5D-$%Y%UzZ{E0
z0=EKTGM;3?kuo@p!7LJb2|;WUAQTP*adx*jV%h)R6kxU>RR)JHc$G(lAZT6Wf;LzI
zrbi6owitr%$iB}As(^vaP(kG<L0GUY+Tc&z?2)g!c-~V4V+gWGy;|exn+n304bKQt
z5xk%dwvq9q_{RoRMma7BOQw%9SWyP-0T%2%S@57t33V_h4Cj6@gMcMD5C;HxZ`dQ>
zu;UR^*Wv+v06;9QN!I(Ewm+V>zlIhchfp6A3`_uwqCDlu0_B)B<pijH0?XgJ5mClH
zSo^o~{S{XRfG3&+3eU-~|H@ec08XArWT9SUp>5=5cnnT(XayP&2mlzM838#hait{r
zQElXGqtpEVs)i|6RDZ=m9}-X4S(jpk^Pp2<{hbG}8-aHtdAb7s>*PR6IMEy2O4xGN
zYMwq(2D}DFm!;g`m5>?P4BO0d8|mN3;vE5@H(B}w86e+gR#%=r-aimqjn`NP=PmB}
z$Pd%3yFDPpTIm&+5#0bnn3Z-h8LBlPq}=R<$W*<>x!tPzd)w~*L7PQ-+bn5oPRShW
z1|f}}A4^%p|FZn$`|D(Iywb#>(Pj%AI1`(;42pNnsri1$oNw{qQU_(pZjW!-79@${
zup~c6z}fzBI2s_0!x%z_Q2y`DJe)C<(sh8NIPVplv$W(*6yG3s-O%5g=x#+Fkr)AQ
z7qJ{yWfwxrNpMEbVIQ`c5mc{Z;859sfO8ZkA@KhCj{)?(EEbhzoaU`&^Kg#hELS|v
zl7HOEa62^spz)J-{4U-9)Fax_yDXX{V0|#jCpf94fJ9l%rl9nj{0zT@7@zwsg7pGr
zrk7%+|9|Q~LkD*~1~AzF83;!YrP~l}3z|gy-(i9i3OplI`WtU5wNTXw=<o!$#<73~
zse~q(!lVFloZMJb*hy2!YEsZxOUM|h<D{G7WY~zBPqmsq_gns7)foHl5J><)G=Z5T
zfr%qwRU`(gB5m8p2}onzuE@w0_Lx<X1gJ^^i(P_^S4v5G#*g$I&a%HO0P!u$ZHX-M
zj4btxEb)xl3Qw?2Pbn$Q;2J2}ZK>M%|5g0I0S*NKcc_vpR0#o9K!Cts?*<awdYASy
zFI2&mdvHSFpD~V;N`Ma4b^mA6_|F7@`*nXc+2A;>Itj}(;sH|Y!8Af)S_}FAE9#R1
z>ZG7!ac>vwn1S0+WonGfRz+$bdqLjpW7tN)>=65_tW9EGi?m(@uN*;7icD}4Cg?N_
zKoeY7ynVb~w5}s6+faoO7$;p}4@{}_?UW|GrpQ1HUf8JZu$l!n2iOY@RLkiKwH?Z8
zKp_AdyzukK;>aP=WB~Az0D;F5l4L%@u^ERLfNjv4N5YD;EJk4L*+~O1w(LX_jzX}>
zv6+=LqOy^dIHAH0#zzMPykyx0EEND^HsIScTJ=N$but!pQUwh%<5^OL>12Un0YOb|
zq&k`Uv^G+oLLHgHqRy|bPKMMXRX~y>wNliP4OXK9PIKDGMGE9}qm|*ApKc0jkzal8
zwh2;EVAHtKX)*O*RmfRw<h&3_71VS$)<jzAgPJ{z^=FZ~Gk&1vX)X0RawIYZIX7*E
zOhK8rBNugy=Vp=mGk)_kAtp0^pGwMFoCm6^%4;hwYad>=?Cm6}Osd^>Xj)zqsjl1L
zq=j-aBvqItM^2|GXrVwYekLfZxmo#flmar@>eghkmGKKJ-6l}P3F+at>~3tFiZa%-
zHariRM4^n6t(JAI^v|t~duLF~=W3IU>a)|RNhE4{2DP5<G=Bk#p^zydCLrHz$agR2
z#d|rLNYrAIu?Z-4&)G!yYrC`fJ12{I$=Y|!1WN7I+{W`lE$!-QsKqTBx$nZE0+aPl
zpuR<SW0O?WqU}!06K$liuGQQ*QuoXc?8Nsozhz3~>^bQ2(CL(Hvva?~ef(r(V+h!T
z%`_)tJ^$6MKka<(C__-TW~jYNy!E+zs3f@Nv1kDRO^qErB(wqtSit}&gR|t+WWvdU
zz^#BII1bT889W5zpmIaVa+HQ35U(kN;$W;SZja&Y`Grs5s`<e)vK%!b2m{B;=?sI{
zg2598?1c?a;IB&ysSO<j6{BSOvJw+uY=udG2}3Z>>>zLp1vfeaZjNp}7#mAa3>=%W
zFafT{Qb;MsS(BV(4idf?I5u~uxv>{^C%_$93iS-tV2zY+F}KFq{u(cAKp-5F-4LKE
zD<U{2s0t3}1$zamB9euJs<hx>ugtkPruE?VHJ~b0-kB$e*C0U^&I_t?u34Xvv3*cL
zV!_VRLt#->*+4DF@sIIo3X96NTjMM}3GnD!<I&CFcKEnvJ;R`)x%-QQQ}bzt+gNFX
zftFhHZLgX!_1*T{g2up+cRztgRW=wHM!~}VV?43}ROL`}1`<G3s&K(ZN{1N1vkZfB
zkl<invytI;z`OB9%R#V-(gCz#0IJ%Uu>g}tbRuwjU`=`nu6wlGb&tUa=f%pG3FqA`
z5WwNx$V!Uj-DD_0@NUosBltEMk`fTN5CX5TAOYc!pM*fzSAy#v?RMSM2(VCKgUgl$
zh{FR+pV1Ef6xS3$&UtY6AIpymfGdmcF9uwFPJ{noP^iVfJV=zW@wvRFAQ-@4fJ=Z<
zAV&YpZ&Ld&rZL1s0I3UNQmmHsjBj}wQHGQ{)3+EWL*Y=vS=8crh#5?@$$6*c;PTUv
zST6t^VqgP#Xf!%XA{^BC+<$uoCT`%|$|y4i5rao*Au$3D?v0esz_f%XpMZ?ImIMd~
zV-+VJJR+l$ZqLbEs4$7--`wnfvb6sLVFDK#BEW^zmpqOd5$SwJE=VA#w1cuR&6PkD
zmqRcLhLxX`1bWIWiWjG_V9G!>*^L;kQrhsvydo>;2?Ac(O>F_j)Qmwz%}j<E7`GG-
z6|gU~aJvURdTt|a=Wz%J-Wdb8gSONe^9sSug&^Wj^<)-R&1c_y4mcVO9EK$>7=oYF
zOdGfz-X@c;dCwPu4#5P|C<?YoAAHz}Z3X}@g3tl^SJC_x&}{M;tb4bk#lZy_h|R$X
z&H~pVIBbxc7CfBUSrC75M6x(6mjA^SCPn?jhg+DG@E<-fkKo(P17$%R0{&MP=N9_$
zFOK6jv;9luVEGp+3?_!N-|~UJC6)zm|MBvFaS8w85QzWcz^VEVUlKwEOhIWyz)+=>
zVWUD)n7zflM<4h%ex(6`tV>5LB3ovN*QS&ahqt6u7S0jMD>uMU#G!@97{cfl$%vNU
zt)tov9_+*z01oH^9_c4M=l}r`u_U$(oAk4KFuRqt3{@83#t6es2JZ5b15j4>H8kmv
zZiTPinC?{HUOn6wC6*<AMclOl;3;=>;tGo&g|aPt!^nPv!2bKB2G0H+0O-XezB^8<
z7}|rS6xNHa3}(Y%=>s~jfeuDAd3k}b`23pA@$W|v5->^mPr<;z_zQt?2w-6RecZzU
zvi>37KJMM(JrP-0I#6b21}GQj!$(k77G`GV2OOQ<9V`zXJYwbMnHib<+S@VO(bGTB
zGsn)x!N$VM{@~I4`@va$-ie`4pZkVbpsdU++z%hIu|T0*4+fxI++3X{4Yf7Z!LpLY
z(1TOESMor|N1y9}fdzltcUC{;$6p28-2JS4cyqM_$&$pu*I3q?6Tl?`w8b@kegA#z
zgC76=-Y#hY8-$OJA|e_qOHv=`*}L>9CX`19SWPsdCf|HwxM-K2HDV!^PG*kSYecJ%
z)W74C`VJEZ188SCHP<!SX$|u)3SH<&!g?<1eye4PH{fk~&{O5z1$eFo)iXa@5>^<!
zIMv!Zja{r_*?ckB@EPrc<XoouGZ%?;NT8?+VCp+r#pu2ToMJ28N$uMfe)UOaWPaKP
z)qmPY2rNj_{%qqHPWgrgT#u&`2kgb??1^-bOEXuIWZFaqO<7z_pSPWTXyXQ^#1(?x
z2VXT}pU~S<2Lr%vO_hZ3+b~5~?l~T}QdZ~aIl4s5LHXO<F&(cW_b$nX5_XSkzQlz}
zHR(V!VE+Y%`u-o+Exo(5<w>V@c$m*o$R>k#UmwjjOT;TdrbP7#$FDgooS~Qi!r@pU
z$)22C;v&0N?t!d|%rKO%*@zPCfIj(Yd<8X08##apeA2aHT4{<3Dr?nVMt;4DIqrE;
z=-x7pwf14=RsCi}3FA);X-J@Lj6hPK>u_|S2`T@|og&8<vu1*iX3>X48&dNdb`7<X
z7|;OQ!RRKH+AS%Bg!Zl*zWD?*EoZYU+L|cGy-p!22m}Mz$QRQoyQ$u)+LB;bVJ+W0
z+lZd$jt#&BI~}5&_wh<72%L+EUA-mjGqj$LMsYDMO8CYBy+Zf_a3X#f(t6@oUK>}3
zQw{|BT#OSgfBX}W_52ralmB4*8?R|bA1$UFu_IDpXZjQI@a%|(<=845fOM|P7u{_)
z()-rg!h+FmCK;DFg?rJSFlyLPzY#@?H7y!_UeFZfm<tyW$lMw}Gdz(!LxqUIe0kgz
zr68?n_}1_GYU=u@*PqYc$7e+ws<{g{gAdzm((*4nkhPA9Lcyja*V;T+heuikQhrRQ
zL54p@v?9iICDs>ci~@fv`P(edh<a<fVm%dwS?deaNwk=eRHQz$E?W}3Pnnux)7Fv0
zx4c{5+Y{D!Y&a6xhFUl7;@?;DExD<@_Tp{A(KcI=(d8*<rAj}8Ms*D^$=4_7n#EXt
zx;p<etrgwrBB?usjvkJN#q5%sOaCl<Xfh^sX-{2<NPdS(Ng$FNQqGa7E>#Ij{2-i}
zBY^we$lmK0iBaxoV{Lz~Zl~#DTiuZ{Q<inIQ^0okjULQ7NB0H(F46J4te#Flu<q9j
z#(p6x_||8EVqe(YN6-4*?22EKr7N(vgnTvn%~gxR0hLV_hjvi?F%9h(r+o$$PSuC{
zjC7YYmvi<{<D~|<S-u+qt$8<3AMwvQ8)St|l(6n4>NC}8F+AaLc||Y+g%vHF;6NH#
zX?q;<@QG{2+QsL8Jg4<4&w1~q7-e{GYlhmjKt*L2SA=bKms!O(*{Vk}=h-QtR5SI)
z;o^>4?{vg7_H88k8@AuJs07*}S(vGu3cH5ANJ#+qLjuoF-xF;B-i#B9PS2a{IOaE%
zcDWL<tEFoW+;_F=_`-foz5jg__LN3jsYpXO)JSY3<Im%@m56MDkquRw@J}vk9%z|g
z?;@LN)CbmPu-Y8o+VHe>)co0ZwfSZ)q^s<qAnGH7h%Si&Fr>79KK{KKf#v%a0(kzK
zHb<7pu4D_Pjwxw#Q~USnd}R5Y4B1tjGk*S!v+R*=46_Oe(6Qu0l2Y(G>e)xcwOcmF
z=$tX$dSrp^BG%shukPr7dQwQA)Mq=sv4Q}KxlT9yUPN1?UJ+h&zjwoWipZw#WU>qT
zF3;HRsXyu!Ta*5f9)}%=tv(1I4J_Y2^vyXx9-%}Q*lm*(ZsxNu*Pm8Jn63`H8l6=s
z$SZIy$ReDBf41)&1I9oHZ;)_ynT0mX=F<MSL~rqH6NZn92I6@YDpT-=bh}!O?eOp<
zOdv~s(O^lZ`KrX8;=)JFNX%<|OQ)?JZ=~sPOE;vP>;#@>wXi1Xv}wJDhQg#m2LQd1
z>5rDp%KRkDm&40&dg7$KROg}-(krLm&Ii1N8MCw<P(ntT<5xd~@7LvMY#ejEczh<}
zDr_Tq2mj<t0wkd)e5k4j_oU#*i*hx!8_7gD-|6!izjK|M%%2qDKL(5XGpQv_1mBss
z1F3>3R!6IzyM4Ov$hDd=cI34)X==|%2ZJrMwAhjBo=iWgQBT9XXMzZp*@n#8p5npz
zf{a}gTZbM=CC|$1KUO&SrSM1Z*x%ny(^f<&{w?{;Mp_BIZ65}1P_iB1wOf!t?_bb^
zF`aEUV;^go$s}2~t{nbrm}`=WU&qRRn36`4El-)>pv=Ty@`B(c8X1H8T&?oi4qALd
z&`^dzoV0aF3xq+)9g9Rd5Cfp8#tp=xY@_lwQB+14E(m0-@oOa_!zZ@>^uA#Vu}~OM
z{$9w|IXJF|oTjG7B`ZN=dS{Hyj^}W=yt#YPQ?CEQ{3(|RUcLBNz46mkw|FHLjGQf|
zpP~V1N)ieAEwvnaqZV9`O@%7^`cHHYM6-;FRp0Vu$I`h*_BnCDD4c#lfTdN1tM}i|
z=xPHbTGEHs;DN#WHp$h$I9U|}D@pN-B&@4V>lDdc8_{yu*C9X!V05^o@?zPu|M?Sa
z{IC)hvqx<g!)WZlP~bTRF^4I}-uWL#{6`l)t1S-a&TGnpQLkQE$CrE)fWL+tFrb-M
zN-=#%Dcm}{V=blaQFq?=?41)2zH+FIQ^dSp{C%?tLJZw>UevPhn3^Hfuziv5u|fs+
zhxGJZpLH?T0_8vOWDZZ!ZdQp9Q~IX1J+;u?>P(Dk0y>~GP4*`p!}2+vG}94p?NeF2
zmmX_@5ve@AIj^pSG3%Npi#2Bkrw0`7*hf3p#ty!;E~2|ftp~~ZvKEhqr4WWml79eE
zR16;JuXYo_ifcO|qCY7Pd>n{I<m*tiP9PYNc_y5ABUT1aK7i^N9zN9Gn_*%w4M<$q
zV`W|+)bQ-QC>gnN6%*tu_*DDTKI^?y^+%NrNIJB{DN%O`PdMpx;l@*YH2v+jHCpdU
zj_amejU4lJSf3FJMLtw|;Z7Us#_ZA9MnT=y@-CtuIuRN!zP3ah;ZC&qv3spGbx|aQ
zq}wE^ZF9P5Gx3A<0DLICqNQs0J6*|3dN=X3rx`IBcW^A`@j@4Y{nA~b(%07rf_64q
z1{Gq#ywW>ko5cdJaw<^8Q5cQrwGru9uaw4!fxy7xYe&&me~CVhn^b{BaWPgC&YNm!
zY+LmKX6n?*8L6-w#X9Z-tLa4qU#}<*!=U5!`vLDiW6#zUrgL5oj|gzouI`2JAH2q<
z7sL6<1r%sx98aF+MgP$DPd#T=fo*DW7>Rr5MN}EG5OADYAOAe+oVqLFc%S?3)x`&c
zXtVyy&X<sN^XXA8U%vv$-XxOBmUn7RV@B_M-!<EmG*PQuPb;$w5-hP10Jx?y5bux1
z4EovgTSoZOF%{9gln;Txr!>kQzf)W^RV>*a)m$w&Y<DWswHDwL1)6(5tD5Lsj@4TG
z<)^aO-_75uFT78imXq9hbx|inpU09NpJ0|xy{*@JL~ax6$JqT!r&U|yY)PykqtkG5
zBh|X6|30juP>kF0bSpi!=~@OCdRU*GUmA)TVtFZ|s*wv*n6&>k_tV4+C?ZVv5uv9p
zHfJ8@j*T@VtKX#3>{lsdiGUiQJXr2|3O!X?gP_~7L=#IL8L9peetD9`{qsu+>Y+m@
z_m37|Srj_3NU&ykR2|Kd*=#{_cGG=hn9KsJ&j6&y@n^5^V?WWlwpr3H6Vi~EQsd3?
zxu{v9r%~g{y8q>*|Mvr8A$Ierjbr-|d(Ot3>~T`4DqGId&GqEO$$@6=hd&sHOUZue
z>o6Bi<GW?E=(cx7nj^-!MurQ=b(3TKexzzC_TZhuyo?BE5A&<gZIY1lQn|F&Id<#G
ziF71gY_T!d4yl91zE8-`3iho%8$%@K@Rk(o1A#Tb;7>>^{o3bu(g$kHQAutNgnX}Y
zY0L|Bm>DD#3PQw3C`Wu6N9k{9&Mr;7KGAbJ;|r@py)20jzIas*=lAS=cbz}KEAR3-
zFii4TLj;#O6lePzpN{R;!|K<KSssW&!q4P9Mw}zcSk-n`L<@eD%XFh~SULE_zkb?A
z2x(PSHDh4$J2sQ?bgR_)xLDFeR&>F&s>$_eZKy#Lawt;RF4f1^zb7N-kYGdAM9M`R
z&9E6S!hcaC1bHgF2HXj!wY@*)5<srvXsy^=vg1xG8Xv!vp3h4(6^D=h{e8_T3fka%
zY>@;l&z&^gkn&zc#7xVJNnl`W+q`yQ-6T(+v|~064kN}JVyt{Ebd^AhuIEbT;Mi)*
zaJ<r=jvJzyMMh48^lZwN$gHgU%wrMmU2%`&6~7T0zG9*+5b$%N^AaUFJoiUfAixSe
zZZ{Urg=h>zUvaa)Ykn-f{;q1?ug|G+^I)Z|;*8s77N~dwch&|2C9oGiC4qFT>>;}3
zi?w6|w2v>3I;-4TuEyj?qO@v6`DpON7rA<vNti{@J$~s;j5ht!DPK~*)^W7-Z~FMS
zoXz>F0lR_vWHq2ty*-U@Sl$G4z3**f0@HoXU(a-dia&K_IlSio&cl_>|E!AS`ONgN
zKrpuPzK4AyHnHG@2SjJdBTp{RnJ~A=#k=pj7|m>j!R*TOR0tqGP#+R}MnB|t(aJ@}
z7L)_NI_}uJymMYQ_xs&_qA7ow^Dw`xZc8Bf;PU5l$jhLQX&)s^by=nqZy-;V2;wj~
zf#)CCBjsAIgo1a6m%cuCOQVD4=>pI=s#h5u9<;zWq{2(VFgi6#wNlj0(eK$|S$k^x
zg}NS(@>fq}AB6`zGx^h!B#$Y4@;N)LUjQ#b_jBcZz&-rLPZ(y6y}LoSkDVJ+q>R4e
zJ_s~z?F;sjdDQ#+H%Ufg3QL+iPSYyPt8k<<kZSC?;7<z7oFb{B)VJOC`3%KatOX==
zfhv$|x^tBta@Y1ol;@(UHc22ZtdGSq?Tgmr?il)qFp>a2i0Oy-D!@~l`glTm^ga}$
z-E1l;Lv&jA%(znxe_Z-7g8_|n(92K&TDti__2)3NXN=C8%Z{|jKpJl%af+b+tSF7m
zm&p%594eg~m|vE7_+I!+hP=)0*9i`<rObnIB{lY}UVp#%^kzEw!X8lYtfFO7lO6ef
z;6M0szLBWb-q_nvg;QVjY11V(w=7VRbFEW$P(hv`O96>nb=ozbsMHXq=g~KikhB9t
z;bVCZPk^DX&yN{#27QvkKlh<GQCierTpqQ58JAN6DA<PZV%p;=aPIS5_a=_JoeU4}
zX+&;`u2-c`*`}9L0qzd5mUSM0v_V6kmN7m6^mxAQrMmxPYtiCYT5TrzW1mwOpltua
zMadN0Gv|GcA~Nx1&uCR?Sb+cq<lH5Jm*X3EunFt)3Qp2D=xqy_-lxU|LE?A;#PmCq
zNMSAd+_XV1c?)l82@6d-Rv+tQp-ffWFIV4bgPs%0gSk@Urh0joDvVQ!Ezri%CHKSd
zpZ2-c)vrEM=MM#lHTVFAvpZa6FBJ=9uPfTUKEQH|Qu~~mA4)cR0lQte<-Wz6wU57{
zLAihqeT-CAzrftE%7C)SA>tVdu?62}62BW6fwh62dl6UOqbgh^fbt5jdo%p$ql)^n
ztzq|?7{a+V=K-(d&K6V1LZ80Qm)hc7C22Wq^eHf9_ID_Ad_VFl6u@*|Zz^B;ct~Pu
zUvS9_nNlqIu;#ATW=-J!1PI*QdHzgJ1-;?`W>5rOE{IQlS-RIF|J#XRZRjCQLYtp6
z_@ZFrt_S_s?bDt&<|C31-)o4V(PIH`ypaWPw5}n{?|2F#12xhVfT^75)dO#u?RURF
z7L-0(ZAbSJxf-p#5fh_4f!D<kbng-3;N<~;)<$@KeigjVjGaEm#L#zZl)Z!Ujc?o5
z$1z}P$obKfb6F;Hen&72{5C&vSomnTCPctj=bT~f`t#dQ-`8j1dn3K1<bF|jQ#upo
z+_a`e^0LIWz|hD8@D<+D#rfF*e?`KdV2k(@nTLOn%wJ|3m&qmYyiFctSkr3r#|0P2
ztLE93SzXjme=e{3bA9K^%lk`AOgglOG9jTx$(7Bs2o2b#K8!`BGt(X$EKQtT91AI$
z(3{Lh5MkGsn<qRC`1Q<cVT7WHc5<}%U};%r2Ch@)UHSR}6PpmaAf5Ab@>0PBy@HPC
z_l`~NgnSb3&7%Cpz*iZAJiKCJs`oqB<P3GWo(Rp8Vg$C)L=nZ>`}w)<p9#MUBlCME
z1ljiM6ON^M`y()LzQKjDz8WH(C*~N?SkyoV5&1TARdzVIDvmp5JJ_&s9n(S{Xv7qt
zwE{qLbO~f|x=>>qPS(FxwMU)CtSlb|dkZl5Yy|~j)q52w$trgenCdXwudLQcuI$_4
zoE-ab>>$=X<7nnfCF-vNinhIzgPXGO6dll*VTu>ElVd6&O0;LAsE?8{#O+ME-YTZ|
z(4YDp{!Da@GspZ^bYixm<|OFdEV0C7Mh^hz>6;THF}RdV*+Gq$(PDUq0p;<&<Xc;A
zpP$SzGuJXL{n7WE=lK}t2;>m$zYw>7C)uGZuWwng^kV2x$aa)c8MExSb8g=7p50WY
zvAPjZO~Bxpj3GTpq>sL{D>vzRZq)nJo&%-iv+YKu<rtoC?y9KL+p2MMwjH)AyySW3
z_(nB?EY+RmQP;VGgv$sEMQiLfen_wOsA!!S`={B;^t#f>L<NTx;ggo$d4^*igL1-f
zS3v_Oda28S@(<n3Fbi}(B`T#AgC-|0s=Sb(X(Yg|pLV_aERv4o1Eq<ALZ9n^=w8CZ
znM*7JX|yR5v_6lR_KCJvpR*2<(%`b+aZJ%0t!W451O^~f+p1RupLUKTQVm@$2S042
z?oSQc<HOI(%;;!E@V?x%&ih{NpEs+2+?1#rnXI3dn}a^sS$ShfEuOUwZCz%5zhbD{
z++Eh~CXPzNzWfHOpN;j3di<N@UE{QR>^2%n^w{SJp<;o(ARn~K2HKC}*+8B?LDXA2
znYh;FjBBA(LjEX%!!``Hm4%ky?}<9%qSqOJIH;zNUT;hV82X?G=Fiys1pPq&rmsfP
z$R;U;7eG5#k>wMokF)h?d~&01V}}!RFj~NRw4E-Qm4ye;YSPMVtT;JA9O-l1vsejb
z<`V(ai^*qOhP}%TM!KI@%HKtl#z5jv$tcg{@y{lmF@Y0peF`k2-AY60FzItitTg}t
zpRtGUhW)Xq575=Q`F!zIHr68-7dN=~jnrk4h(ETdFfD)=&jfJEACG!lY))RiPkc+e
zclKqMmJp{l>13Qo9}283P<#>G6Fwg7=QYR(WzE?ygZ}t!sfXq_URoUP6?OtQ*pC;z
zOX_xFp!H)tQv0jJ)>Bt=pKny9sjC?j-+ny!w)+0vC!@6^75Jy5H(VkDOZceMlq~Z$
z(YyZQ$2aPQjpWjPzx;1ny;@zSrNoIo+8KP?eL{iv+rMC$>CT~xl8ybhA|LwF)SS<E
zffRl}5~`iG!p4@-hI5|qo^ZtsA#b@Gk)_0$Jo+ONinoBI@X(z27;q9=a<))hK!lp9
z71@3|kOuK7=nBLt#%XJ73uIw9OZ)O`B!_}Ix>-E9Afzpgn|UZ9bLV04AQ2TZV8@ZB
zQp%!f^V^KAo8?Z4YtlT&k;{(bhU`X~tmlFTA!I}7yICva$qyA3-T^l9hA+^u&NEKC
zUqff8%S@i~r;?AXGs{<cuSa)Cb4vxI5jYPr2LT}W$Myt@TbZe2Z~x&;Ky6F2Eiy?@
zGvd8*{1^KVAGGGg={ol7_G($F6AQG7Rk<oohF@b}E7p7A%$as_wXYFt3SPJ-BrCN=
z?y}DH00ZIK_2JQb{ZqKv(gZr4kjI~7y*P^(+tTOHPVT+QtY*jX##4Pv@gN8<%6XvX
zm)B*yllP03IQ4u3iA`g^AhiV6WptWP`5H0Bzr#Ie4PqNDws%%-D-Y4zc4B06CAw|C
zPV2!$vJ$v&yb9_Cq|Hq>(}t8sitH?SQDbJwBitf#G`+G5F<;|LblxJ_j;<&ph^uV@
z02k_TFnR{~e<VuQq|gy@#`9+zLPPJO2p74&)Dl#;Jx;Uoo<mj;b}SsHA%lpO<@T;4
zvV=DcCcam{f6M4X(@Qk}Hp+3}w0*4q_<gSGq6%im$D53XQkBDBrp4Y81~cOQl;%^`
z(yixD$`-l~<aJKVRR`(Jala4@u!r@(d`@sGdF|Usig90HS$UxualOgZG>#?kR^x~E
z(rlSilTx&|?+2ofhmF;knv%p11brGrxPsd0eJ&><5L}N=Pi<FrzD=0rQ;*#_vEX7)
zFB(GQH@cEa+7Qg@JVEQtjpfm?@zDk2SSx2V#tiOG^SSz}MrQD@BBsW<v1vspZWD1R
z=Vdm2kpSD~;-dm;S?~cRi?ia@e7W*-{ue~r3bt(|zBKU7>aP#NxL1cZW44({S>KKl
z9Z9{T6MO$lsoTOV)oh|VeZauvzW?Q3Q=}?FJi<(d--wrHU^|LWI2&7XaA8Ci&kRmg
zf^lZVdatE8DN}<m!@Y0+cl!vh7^%y;Lx43F0O%_vb9^CK?Yf%3JKk4ymIl+<BLgU`
zX`hH=OW=j#mo2!AD){-k9lKtlv~zOk=V>tPNWHCv@~{LtoCC+c0;ah%kWe|MoJPS#
zR@?|<6s}Ub;Gzl=!kDBO&(gMUi<=i*L{{EJ2o>yD<&!z<RLeGAf;Ht9%i&N^&C|t1
z;XY-z{a*N6?QkxG`@JdVfwVUB-4MG*y0}^C6UF@a;XoYLV2!ix62Zdu?-nv#Fa<BW
zYf0`>Q`e(Bc*@LZ-OD)$V(wv8i12;+z`0Gs<F|z^qLctl_TXN4tj$w5dZ0@*4Jm!O
ziUQwG1~${bN>s$1;O;e<#M*W~GhP`p`tjOCE(sVCnY;g6@u#E=6(FKBn(&piV(DnP
zUQU>Vm+Z03fkZGZRyF#R_#8K{^rlxJfdK%BL|<F^6kv>*FN(sQk`n4j$<y6B-etmo
z3Q+{2)9{Rc8-o!Nm_p3ip<Z$?6=Rcr8+BrCUgi`a8*24I6k%@e-!kw^@0&glIHyak
z^}v81JF_*yIj%~l!ffED@4z!)NPLcdLUKNfkm>{m0jjwN<JNa8&{I!_B<y`gPRXyG
zCKEY2Y*OU|-tQUjN|rziuJUm_))`4)Y~Y6nJC`930~|)8jMjXLT@K!Chd+jPz3-gT
zbTc>)z)viC2tZ3pniI$acH6$TnRsxyqNUD^atnUItn5v6@i=3d`a~k-E7m%kHq`9C
zCOXHSa}2T70slYOaV&h@)j@uYxoI;b$C7&IyI%(B(ct`*U4q~TafCg@50FIzrU4Zx
zYmPs68|U0+3Pveje~|jjt~e;1txYwtE2_p=_oG|w6ZqfBcH%+Skk}le*RK#YJ+V<{
zbsb-a_T7R7*TfCb%yKJ7jNb!+IVl?AQNArkSAHVU_)k=JZW5yU=e#_WQ{s%DU(X3_
zQ#0WMJbN)I7OdCfd;2(-lkF3N`g_f?WFK=MEx#JZ?&*bei7FBCm2cFil0g~qfxgy|
zx02V?1Sop(r2&?`&KqHCdk1yQlWvP;>)K|3#CnKHqZb|c{e5!NE2pac+WojfQfSRr
zR*8+$Ot1K^FeWXJA`3V5q}$wRMXAzWOU89^?ilId^Xiow3QmHCgo(8kU(C%NLti}&
z-oXP?hWmf&!{*}hdKeiX*8Qh-l|C|KJ6Urg7i-U*qT-B?pPcKc36l`A_uOdx9FW}N
zKM$a}&$DS#qdhge{&rj@`D9!lYrGC!n3c1jpZ1k+thJx+^Gi+ZZgifG5)K|A)a8nV
z5Ko|T`p#N23*{Et*FsjjnFd06c4Kgom5EoAuF4RE)<EFuy8!rCf7av2svMEzrdacP
z9S@7vBRq%1al@Ef2g=8YN&#)s)j8daKbr(MKI;ob0sA3W8`b?6*bR+Ap6{qwAoXC#
z2B-Mhj0ZbM1c8aST6FHuu+f5YO$cM}wp@MwsKAc}qJTReN9MX-)QdKRNnfu2(C-Uv
z7yJrzP_^%tzB4p_BhlJc89?pxz7?lP-Rm-`sj-oWT8ALYnrIP%TjqN`vvple+bld@
z{B}e|$)gx+s=d^~1MOWzM{3mJT=x*M>(p`M+{}&Pv7M7z+p7_#*gFkBM2>Q}hld;e
z0|FN3-_K_)8u4fMJ{ET3%CcMk$)^tuL)lL4PEb{<pEEp3eKO3)So@HEYifa};pq2T
z{|)}W=v1mI@aLgoGfTzgMaFtOq}WMB*$X$)cS(CAcLVb?;Y>i5$uHI3xb$}qm7L+~
z4Y=4+Fq~1vFKukKvgbzV09L!z&?g*M2z=D_@{e6T%WlSkg-!oUtWP{qjD|Qt-=rrg
zY_4<+%`HQHeYLJpp4Dyr;$;tz11=k?$o@#!UiG(%*p1KPPl?3t$+<`^?!3WFe16x(
zv~xDAlI&34Az++R5J>516Ms;^s?j|6$nkFBCd!8NWq%ASx5q)OIU_y2Vc+Axx*gB0
z-ck;^g4bw738e5l1*3*s(FWweQ*>#ns$}jGPAp)_s{Yv>hz#|&<wVHh+iF<(XP!(l
z)HsPLrhuJwmMWj|<-F=_`*U~q#*Oxml4RohH7`h?UwwP09}yi~6=XP9;MV_gTzx7N
z;wQ+K^j22$9z7A%Y}q-p7VhbxxHyaq7AVV2q&Bu%V$=0|C$nVXU^AVOs&4*^rKSFq
zE<96r55sJ!sTlXA&>C%SD(m?B<twe`@t;dwHkJv-KLvCW6ckd2LYW<`vqdp0QA0IW
zmoF|wsM@WxZSmD*&}No{1SW{6=7eM)GVu4f$H37x#;fX)4NZQ(B}kn3Z<5uTGWyyc
zJRFqT?;0hiCA{izpwFPMr$N<GG=ylZ)PEk*(&)Id2@vah*}mV!=X-E`MxGQh+8H_Y
zrnEiz0`EwrhA>4X(sDAEo_4Cqh(#yq_1k+Ldj<V4gDTdH-`u!o$#<ZIbA|q|9{D{t
zr+lRwEN&=Itob#)m)wnmyXnidtM8`~!-S!tdpXtxMgANR9P*t;oqinik^OW#c@|t#
zUR9FJs++xK=-v&!@#cZ|lSlouty554afgH4p9y7v!=opOw)-KDMMnLkud#m+g=7SD
z{8ImYLSR~HwDY=2`@RCiPH<&IS$xnY_{kANXb7UK*YfAsmPt2MhG*oBPKxW;!=u2{
zgH%2&%4FPe1UlCsqj^L*2czmot3Vf~*TZ&Kv_>Sc8xHL9cIf9uP{WMV>uxF9(i!LL
z<SzeTnSL^mFI&7GIlPJk0(R`GWN7pj)CV7Wx}20tByWyRuEW@Lv41`j*Ilcf9$0Ru
z#`Y=ciEZW9mP3`)QGce2AFsPNToad7{Xt4H%PO_><zB{N;mAyEeHHFm0Ak9q;ff|Z
zWV@GRbzLFxy0WNZfavf@(=Zg)9MEHhUR}`N(fVzqj`J&DhmU_&ikeo^T3T8xX2>S-
Z{kT65Jzel|`M;>-Z+o;iR#cM${||7Ja3cT!

literal 0
HcmV?d00001

diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl
index 26cd4f8315..88cd0be397 100644
--- a/Resources/Locale/en-US/research/technologies.ftl
+++ b/Resources/Locale/en-US/research/technologies.ftl
@@ -53,6 +53,8 @@ research-technology-advanced-anomaly-research = Advanced Anomaly Research
 research-technology-rped = Rapid Part Exchange
 research-technology-super-parts = Super Parts
 research-technology-deterrence = Deterrence Technologies
+research-technology-night-vision = Night vision
+research-technology-thermal-vision = Thermal vision
 
 research-technology-janitorial-equipment = Janitorial Equipment
 research-technology-laundry-tech = Laundry Tech
diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl
index 7eaacc5026..214a259296 100644
--- a/Resources/Locale/en-US/store/uplink-catalog.ftl
+++ b/Resources/Locale/en-US/store/uplink-catalog.ftl
@@ -329,6 +329,12 @@ uplink-hardsuit-syndieelite-desc = An elite version of the blood-red hardsuit, w
 uplink-clothing-outer-hardsuit-juggernaut-name = Cybersun Juggernaut Suit
 uplink-clothing-outer-hardsuit-juggernaut-desc = Hyper resilient armor made of materials tested in the Tau chromosphere facility. The only thing that's going to be slowing you down is this suit... and tasers.
 
+uplink-night-vision-name = Night vision goggles
+uplink-night-vision-desc = They allow you to see in the dark, all while looking like normal sunglasses!
+
+uplink-thermal-vision-name = Thermal vision goggles
+uplink-thermal-vision-desc = They allow you to see living creatures regardless of obstacles, all while looking like normal sunglasses!
+
 # Misc
 uplink-cyberpen-name = Cybersun Pen
 uplink-cyberpen-desc = Cybersun's legal department pen, invaluable for forging documents and escaping prisons. Smells vaguely of hard-light and war profiteering.
diff --git a/Resources/Locale/ru-RU/prototypes/actions/types.ftl b/Resources/Locale/ru-RU/prototypes/actions/types.ftl
new file mode 100644
index 0000000000..57aa426632
--- /dev/null
+++ b/Resources/Locale/ru-RU/prototypes/actions/types.ftl
@@ -0,0 +1,8 @@
+ent-ActivateSmokeImplant = Переключить ночное зрение
+    .desc = Переключает ночное зрение.
+
+ent-ActivateSmokeImplant = Переключить тепловизионное зрение
+    .desc = Переключает тепловизионное зрение.
+
+ent-PulseThermalVision = Подать термальный импульт
+    .desc = Временно активируйте тепловизионное зрение.
\ No newline at end of file
diff --git a/Resources/Locale/ru-RU/prototypes/entities/clothing/eyes/goggles.ftl b/Resources/Locale/ru-RU/prototypes/entities/clothing/eyes/goggles.ftl
new file mode 100644
index 0000000000..050e373c86
--- /dev/null
+++ b/Resources/Locale/ru-RU/prototypes/entities/clothing/eyes/goggles.ftl
@@ -0,0 +1,23 @@
+# Night Vision Goggles
+ent-ClothingEyesNightVisionGoggles = ПНВ
+   .desc = Усовершенствованный дисплей, который обеспечивает видимость в полной темноте.
+ent-ClothingEyesNightVisionSecurityGoggles = ПНВ службы безопасности
+   .desc = { ent-ClothingEyesNightVisionGoggles.desc }
+ent-ClothingEyesNightVisionMedicalGoggles = ПНВ медицинский
+   .desc = { ent-ClothingEyesNightVisionGoggles.desc }
+ent-ClothingEyesNightVisionDiagnosticGoggles = ПНВ диагностический
+   .desc = { ent-ClothingEyesNightVisionGoggles.desc }
+ent-ClothingEyesNightVisionGogglesSyndie = { ent-ClothingEyesNightVisionGoggles }
+   .desc = { ent-ClothingEyesNightVisionGoggles.desc }
+ent-ClothingEyesNightVisionGogglesNukie = { ent-ClothingEyesNightVisionGoggles }
+   .desc = { ent-ClothingEyesNightVisionGoggles.desc }
+
+# Thermal Vision Goggles
+ent-ClothingEyesThermalVisionGoggles = ПТВ
+   .desc = Термальность - это как отношения, важно не только наличие тепла, но и его распределение.
+ent-ClothingEyesThermalVisionMonocle = термонокль
+   .desc = Видение сквозь стены ещё никогда не было таким нежным и личностным.
+ent-ClothingEyesThermalVisionGogglesSyndie = { ent-ClothingEyesThermalVisionGoggles }
+   .desc = { ent-ClothingEyesThermalVisionGoggles.desc }
+ent-ClothingEyesThermalVisionGogglesNukie = { ent-ClothingEyesThermalVisionGoggles }
+   .desc = { ent-ClothingEyesThermalVisionGoggles.desc }
diff --git a/Resources/Locale/ru-RU/entities/objects/tools/empflashlight.ftl b/Resources/Locale/ru-RU/prototypes/objects/tools/empflashlight.ftl
similarity index 100%
rename from Resources/Locale/ru-RU/entities/objects/tools/empflashlight.ftl
rename to Resources/Locale/ru-RU/prototypes/objects/tools/empflashlight.ftl
diff --git a/Resources/Locale/ru-RU/research/techologies.ftl b/Resources/Locale/ru-RU/research/techologies.ftl
new file mode 100644
index 0000000000..54f3899255
--- /dev/null
+++ b/Resources/Locale/ru-RU/research/techologies.ftl
@@ -0,0 +1,2 @@
+research-technology-night-vision = Ночное видение
+research-technology-thermal-vision = Термальное видение
\ No newline at end of file
diff --git a/Resources/Locale/ru-RU/store/uplink-catalog.ftl b/Resources/Locale/ru-RU/store/uplink-catalog.ftl
index 5bb4067557..a5ccaace17 100644
--- a/Resources/Locale/ru-RU/store/uplink-catalog.ftl
+++ b/Resources/Locale/ru-RU/store/uplink-catalog.ftl
@@ -1,2 +1,9 @@
 uplink-emp-flashlight-name = Электромагнитный фонарик
 uplink-emp-flashlight-desc = Замаскированное под фонарик устройство. При ударе выпускает ЭМИ, поражающий электрические устройства.
+
+#Armor
+uplink-night-vision-name = Прибор ночного видения
+uplink-night-vision-desc = Позволяет вам видеть в темноте, при этом выглядя как обычные солнцезащитные очки!
+
+uplink-thermal-vision-name = Прибор термального видения
+uplink-thermal-vision-desc = Позволяет вам видеть живых существ независимо от преград, при этом выглядя как обычные солнцезащитные очки!
diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml
index 43aaef4736..0a57157f1b 100644
--- a/Resources/Prototypes/Actions/types.yml
+++ b/Resources/Prototypes/Actions/types.yml
@@ -404,4 +404,43 @@
     useDelay: 40
     event:
       !type:FabricateActionEvent
-      fabrication: FoodGumball
\ No newline at end of file
+      fabrication: FoodGumball
+
+- type: entity
+  id: ToggleNightVision
+  name: Switch night vision
+  description: Switches night vision.
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: InstantAction
+    itemIconStyle: BigAction
+    priority: -20
+    icon:
+      sprite: Clothing/Eyes/Goggles/nightvision.rsi
+      state: icon
+    event: !type:ToggleNightVisionEvent
+
+- type: entity
+  id: ToggleThermalVision
+  name: Switch Thermal vision
+  description: Switches Thermal vision.
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: InstantAction
+    itemIconStyle: BigAction
+    priority: -20
+    icon:
+      sprite: Clothing/Eyes/Goggles/thermal.rsi
+      state: icon
+    event: !type:ToggleThermalVisionEvent
+
+- type: entity
+  id: PulseThermalVision
+  parent: ToggleThermalVision
+  name: Pulse Thermal Vision
+  description: Activate thermal vision temporarily.
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: InstantAction
+    useDelay: 4
+
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml
index 756f295d12..65916a84b9 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml
@@ -44,7 +44,7 @@
       prob: 0.2
     - !type:EntSelector
       id: WeaponFlareGun
-      prob: 0.1
+      prob: 0.05
     - !type:EntSelector
       id: BoxMRE
       prob: 0.1
@@ -165,6 +165,10 @@
     - !type:EntSelector
       id: WeaponSniperMosin
       weight: 2
+    - !type:EntSelector
+      id: ClothingEyesNightVisionGogglesSyndie
+    - !type:EntSelector
+      id: ClothingEyesThermalVisionGogglesSyndie
 
 - type: entityTable
   id: MaintenanceLockerLoot
@@ -235,4 +239,4 @@
         - !type:EntSelector
           id: GeigerCounter
           amount: !type:ConstantNumberSelector
-            value: 2
\ No newline at end of file
+            value: 2
diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml
index 7f9088a3d0..cc0e0bb0f3 100644
--- a/Resources/Prototypes/Catalog/uplink_catalog.yml
+++ b/Resources/Prototypes/Catalog/uplink_catalog.yml
@@ -1532,6 +1532,78 @@
       components:
       - SurplusBundle
 
+- type: listing
+  id: UplinkNightGoggles
+  name: uplink-night-vision-name
+  description: uplink-night-vision-desc
+  productEntity: ClothingEyesNightVisionGogglesSyndie
+  discountCategory: rareDiscounts
+  discountDownTo:
+    Telecrystal: 1
+  cost:
+    Telecrystal: 3
+  categories:
+  - UplinkWearables
+  conditions:
+  - !type:StoreWhitelistCondition
+    blacklist:
+      tags:
+      - NukeOpsUplink
+
+- type: listing
+  id: UplinkNightGogglesNukie
+  name: uplink-night-vision-name
+  description: uplink-night-vision-desc
+  productEntity: ClothingEyesNightVisionGogglesNukie
+  discountCategory: rareDiscounts
+  discountDownTo:
+    Telecrystal: 1
+  cost:
+    Telecrystal: 3
+  categories:
+  - UplinkWearables
+  conditions:
+  - !type:StoreWhitelistCondition
+    whitelist:
+      tags:
+      - NukeOpsUplink
+
+- type: listing
+  id: UplinkThermalGoggles
+  name: uplink-thermal-vision-name
+  description: uplink-thermal-vision-desc
+  productEntity: ClothingEyesThermalVisionGogglesSyndie
+  discountCategory: rareDiscounts
+  discountDownTo:
+    Telecrystal: 1
+  cost:
+    Telecrystal: 3
+  categories:
+  - UplinkWearables
+  conditions:
+  - !type:StoreWhitelistCondition
+    blacklist:
+      tags:
+      - NukeOpsUplink
+
+- type: listing
+  id: UplinkThermalGogglesNukie
+  name: uplink-thermal-vision-name
+  description: uplink-thermal-vision-desc
+  productEntity: ClothingEyesThermalVisionGogglesNukie
+  discountCategory: rareDiscounts
+  discountDownTo:
+    Telecrystal: 1
+  cost:
+    Telecrystal: 3
+  categories:
+  - UplinkWearables
+  conditions:
+  - !type:StoreWhitelistCondition
+    whitelist:
+      tags:
+      - NukeOpsUplink
+
 # Tools
 
 - type: listing
diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml
index f50b0dbca5..59817932c7 100644
--- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml
+++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml
@@ -232,6 +232,7 @@
   - type: Clothing
     sprite: Clothing/Eyes/Glasses/ninjavisor.rsi
   - type: FlashImmunity
+  - type: NightVision
 
 - type: entity #Fake goggles, the latest in anti-valid hunting technology
   parent: ClothingEyesBase
diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/goggles.yml b/Resources/Prototypes/Entities/Clothing/Eyes/goggles.yml
new file mode 100644
index 0000000000..4348c87227
--- /dev/null
+++ b/Resources/Prototypes/Entities/Clothing/Eyes/goggles.yml
@@ -0,0 +1,114 @@
+# Night Vision Goggles
+
+- type: entity
+  parent: ClothingEyesBase
+  id: ClothingEyesNightVisionGoggles
+  name: night vision goggles
+  description: An advanced heads-up display which provides id data and vision in complete darkness.
+  components:
+  - type: Sprite
+    sprite: Clothing/Eyes/Goggles/nightvision.rsi
+  - type: Clothing
+    sprite: Clothing/Eyes/Goggles/nightvision.rsi
+  - type: NightVision
+  - type: IdentityBlocker
+    coverage: EYES
+
+- type: entity
+  parent: [ClothingEyesNightVisionGoggles, ShowSecurityIcons]
+  id: ClothingEyesNightVisionSecurityGoggles
+  name: night vision security goggles
+  components:
+  - type: Sprite
+    sprite: Clothing/Eyes/Goggles/security_nightvision.rsi
+  - type: Clothing
+    sprite: Clothing/Eyes/Goggles/security_nightvision.rsi
+
+- type: entity
+  parent: [ClothingEyesNightVisionGoggles, ClothingEyesHudMedical]
+  id: ClothingEyesNightVisionMedicalGoggles
+  name: night vision medical goggles
+  components:
+  - type: Sprite
+    sprite: Clothing/Eyes/Goggles/medical_nightvision.rsi
+  - type: Clothing
+    sprite: Clothing/Eyes/Goggles/medical_nightvision.rsi
+
+- type: entity
+  parent: [ClothingEyesNightVisionGoggles, ClothingEyesHudDiagnostic]
+  id: ClothingEyesNightVisionDiagnosticGoggles
+  name: night vision diagnostic goggles
+  components:
+  - type: Sprite
+    sprite: Clothing/Eyes/Goggles/diagnostic_nightvision.rsi
+  - type: Clothing
+    sprite: Clothing/Eyes/Goggles/diagnostic_nightvision.rsi
+
+- type: entity
+  parent: ClothingEyesNightVisionGoggles
+  id: ClothingEyesNightVisionGogglesSyndie
+  suffix: "Chameleon"
+  components:
+  - type: ChameleonClothing
+    slot: [eyes]
+    default: ClothingEyesNightVisionGoggles
+  - type: UserInterface
+    interfaces:
+      enum.ChameleonUiKey.Key:
+        type: ChameleonBoundUserInterface
+
+- type: entity
+  parent: [ClothingEyesNightVisionGogglesSyndie, ShowSecurityIcons]
+  id: ClothingEyesNightVisionGogglesNukie
+  suffix: "Chameleon, NukeOps"
+  components:
+  - type: ShowSyndicateIcons
+
+# Thermal Vision Goggles
+
+- type: entity
+  parent: ClothingEyesBase
+  id: ClothingEyesThermalVisionGoggles
+  name: thermal vision goggles
+  description: Thermals in the shape of glasses.
+  components:
+  - type: Sprite
+    sprite: Clothing/Eyes/Goggles/thermal.rsi
+  - type: Clothing
+    sprite: Clothing/Eyes/Goggles/thermal.rsi
+  - type: ThermalVision
+    pulseTime: 2
+    toggleAction: PulseThermalVision
+  - type: IdentityBlocker
+    coverage: EYES
+
+- type: entity
+  parent: ClothingEyesThermalVisionGoggles
+  id: ClothingEyesThermalVisionMonocle
+  name: thermonocle
+  description: Never before has seeing through walls felt so gentlepersonly.
+  components:
+  - type: Sprite
+    sprite: Clothing/Eyes/Goggles/monocle_thermal.rsi
+  - type: Clothing
+    sprite: Clothing/Eyes/Goggles/monocle_thermal.rsi
+
+- type: entity
+  parent: ClothingEyesThermalVisionGoggles
+  id: ClothingEyesThermalVisionGogglesSyndie
+  suffix: "Chameleon"
+  components:
+  - type: ChameleonClothing
+    slot: [eyes]
+    default: ClothingEyesThermalVisionGoggles
+  - type: UserInterface
+    interfaces:
+      enum.ChameleonUiKey.Key:
+        type: ChameleonBoundUserInterface
+
+- type: entity
+  parent: [ClothingEyesThermalVisionGogglesSyndie, ShowSecurityIcons]
+  id: ClothingEyesThermalVisionGogglesNukie
+  suffix: "Chameleon, NukeOps"
+  components:
+  - type: ShowSyndicateIcons
diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml
index caccdd8745..04f796591f 100644
--- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml
+++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml
@@ -744,6 +744,9 @@
         Heat: 0.80
         Radiation: 0.80
         Caustic: 0.95
+  - type: ThermalVision
+    color: "#98EEFB"
+    lightRadius: 15
 
 #MISC. HARDSUITS
 #Clown Hardsuit
diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
index b8ff03abca..ada65ad33f 100644
--- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
+++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml
@@ -126,6 +126,7 @@
       cell_slot:
         name: power-cell-slot-component-slot-name-default
   - type: Body
+    thermalVisibility: false
   - type: StatusEffects
     allowed:
     - Stun
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
index f1932e3ece..faa7fbc22b 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml
@@ -70,6 +70,12 @@
     barkType: mouse
     minTime: 10 # Mice like to squeak, I think. You can always put your pet mouse to sleep if it gets annoying
     maxTime: 160
+  - type: NightVision
+    isActive: true
+    toggleAction: null
+    color: "#808080"
+    activateSound: null
+    deactivateSound: null
 
 - type: entity
   name: bee
@@ -1792,6 +1798,12 @@
       Taco: RatTaco
       Burger: RatBurger
       Skewer: RatSkewer
+  - type: NightVision
+    isActive: true
+    toggleAction: null
+    color: "#808080"
+    activateSound: null
+    deactivateSound: null
 
 - type: entity
   parent: MobMouse
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml
index d241173f2e..356615d2e9 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml
@@ -88,6 +88,12 @@
       interfaces:
         enum.SurgeryUIKey.Key:
           type: SurgeryBui
+    - type: NightVision
+      isActive: true
+      toggleAction: null
+      color: "#808080"
+      activateSound: null
+      deactivateSound: null
 
 - type: entity
   parent: BaseMobCarp
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
index abe602037f..9e4f72bb0c 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml
@@ -132,6 +132,12 @@
     interfaces:
       enum.SurgeryUIKey.Key:
         type: SurgeryBui
+  - type: NightVision
+    isActive: true
+    toggleAction: null
+    color: "#808080"
+    activateSound: null
+    deactivateSound: null
 
 - type: entity
   id: MobRatKingBuff
@@ -317,6 +323,12 @@
   - type: FireVisuals
     sprite: Mobs/Effects/onfire.rsi
     normalState: Mouse_burning
+  - type: NightVision
+    isActive: true
+    toggleAction: null
+    color: "#808080"
+    activateSound: null
+    deactivateSound: null
 
 - type: weightedRandomEntity
   id: RatKingLoot
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
index 7358d07236..db8287e13e 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml
@@ -140,6 +140,12 @@
     - Xeno
     understands:
     - Xeno
+  - type: ThermalVision
+    isActive: true
+    lightRadius: 15
+    color: "#808080"
+    activateSound: null
+    deactivateSound: null
 
 - type: entity
   name: Praetorian
diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml
index c91b209e8c..a0a0d1ed2e 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml
@@ -35,6 +35,7 @@
     bodyType: Kinematic
   - type: Body
     prototype: Aghost
+    thermalVisibility: false
   - type: Access
     groups:
     - AllAccess
diff --git a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml
index 0f24313712..4c03c6c688 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml
@@ -140,6 +140,11 @@
     tags:
     - CannotSuicide
     - DoorBumpOpener
+  - type: NightVision
+    isActive: true
+    color: "#808080"
+    activateSound: null
+    deactivateSound: null
 
 - type: entity
   parent: BaseMobDragon
diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml
index 7c65b89a76..b8de17a55f 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml
@@ -233,6 +233,7 @@
     - type: Body
       prototype: IPC
       requiredLegs: 2
+      thermalVisibility: false
     - type: Ensnareable
       sprite: Objects/Misc/ensnare.rsi
     - type: Speech
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 850b2c0d74..366a4b2166 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -16,7 +16,7 @@
         mask:
         - MachineMask
         layer:
-          - MachineLayer  
+        - MachineLayer
   - type: Lathe
   - type: MaterialStorage
   - type: Destructible
@@ -109,118 +109,118 @@
   - type: MaterialStorage
     whitelist:
       tags:
-        - Sheet
-        - RawMaterial
-        - Ingot
+      - Sheet
+      - RawMaterial
+      - Ingot
   - type: Lathe
     idleState: icon
     runningState: building
     staticRecipes:
-      - Wirecutter
-      - Igniter
-      - Signaller
-      - Screwdriver
-      - Welder
-      - Wrench
-      - Crowbar
-      - Multitool
-      - NetworkConfigurator
-      - SprayPainter
-      - FlashlightLantern
-      - CableStack
-      - CableMVStack
-      - CableHVStack
-      - HandheldGPSBasic
-      - TRayScanner
-      - AirTank
-      - GasAnalyzer
-      - UtilityBelt
-      - Fulton
-      - FultonBeacon
-      - Pickaxe
-      - ModularReceiver
-      - AppraisalTool
-      - SheetRGlass
-      - Beaker
-      - Syringe
-      - HandLabeler
-      - LightTube
-      - LedLightTube
-      - SodiumLightTube
-      - ExteriorLightTube
-      - LightBulb
-      - LedLightBulb
-      - Bucket
-      - DrinkMug
-      - DrinkMugMetal
-      - DrinkGlass
-      - DrinkShotGlass
-      - DrinkGlassCoupeShaped
-      - CustomDrinkJug
-      - FoodPlate
-      - FoodPlateSmall
-      - FoodPlatePlastic
-      - FoodPlateSmallPlastic
-      - FoodBowlBig
-      - FoodPlateTin
-      - FoodKebabSkewer
-      - SprayBottle
-      - MopItem
-      - Holoprojector
-      - Mousetrap
-      - LightReplacer
-      - TrashBag
-      - PowerCellSmall
-      - PowerCellMedium
-      - RollerBedSpawnFolded
-      - CheapRollerBedSpawnFolded
-      - EmergencyRollerBedSpawnFolded
-      - MicroManipulatorStockPart
-      - MatterBinStockPart
-      - CapacitorStockPart
-      - ConveyorBeltAssembly
-      - IntercomElectronics
-      - FirelockElectronics
-      - DoorElectronics
-      - AirAlarmElectronics
-      - StationMapElectronics
-      - FireAlarmElectronics
-      - MailingUnitElectronics
-      - SignalTimerElectronics
-      - APCElectronics
-      - SMESMachineCircuitboard
-      - SubstationMachineCircuitboard
-      - WallmountSubstationElectronics
-      - CellRechargerCircuitboard
-      - BorgChargerCircuitboard
-      - WeaponCapacitorRechargerCircuitboard
-      - HandheldStationMap
-      - ClothingHeadHatWelding
+    - Wirecutter
+    - Igniter
+    - Signaller
+    - Screwdriver
+    - Welder
+    - Wrench
+    - Crowbar
+    - Multitool
+    - NetworkConfigurator
+    - SprayPainter
+    - FlashlightLantern
+    - CableStack
+    - CableMVStack
+    - CableHVStack
+    - HandheldGPSBasic
+    - TRayScanner
+    - AirTank
+    - GasAnalyzer
+    - UtilityBelt
+    - Fulton
+    - FultonBeacon
+    - Pickaxe
+    - ModularReceiver
+    - AppraisalTool
+    - SheetRGlass
+    - Beaker
+    - Syringe
+    - HandLabeler
+    - LightTube
+    - LedLightTube
+    - SodiumLightTube
+    - ExteriorLightTube
+    - LightBulb
+    - LedLightBulb
+    - Bucket
+    - DrinkMug
+    - DrinkMugMetal
+    - DrinkGlass
+    - DrinkShotGlass
+    - DrinkGlassCoupeShaped
+    - CustomDrinkJug
+    - FoodPlate
+    - FoodPlateSmall
+    - FoodPlatePlastic
+    - FoodPlateSmallPlastic
+    - FoodBowlBig
+    - FoodPlateTin
+    - FoodKebabSkewer
+    - SprayBottle
+    - MopItem
+    - Holoprojector
+    - Mousetrap
+    - LightReplacer
+    - TrashBag
+    - PowerCellSmall
+    - PowerCellMedium
+    - RollerBedSpawnFolded
+    - CheapRollerBedSpawnFolded
+    - EmergencyRollerBedSpawnFolded
+    - MicroManipulatorStockPart
+    - MatterBinStockPart
+    - CapacitorStockPart
+    - ConveyorBeltAssembly
+    - IntercomElectronics
+    - FirelockElectronics
+    - DoorElectronics
+    - AirAlarmElectronics
+    - StationMapElectronics
+    - FireAlarmElectronics
+    - MailingUnitElectronics
+    - SignalTimerElectronics
+    - APCElectronics
+    - SMESMachineCircuitboard
+    - SubstationMachineCircuitboard
+    - WallmountSubstationElectronics
+    - CellRechargerCircuitboard
+    - BorgChargerCircuitboard
+    - WeaponCapacitorRechargerCircuitboard
+    - HandheldStationMap
+    - ClothingHeadHatWelding
   - type: EmagLatheRecipes
     emagStaticRecipes:
-      - BoxLethalshot
-      - BoxShotgunFlare
-      - BoxShotgunSlug
-      - MagazineBoxLightRifle
-      - MagazineBoxMagnum
-      - MagazineBoxPistol
-      - MagazineBoxRifle
-      - MagazineLightRifle
-      - MagazineLightRifleEmpty
-      - MagazinePistol
-      - MagazinePistolEmpty
-      - MagazinePistolSubMachineGun
-      - MagazinePistolSubMachineGunEmpty
-      - MagazinePistolSubMachineGunTopMounted
-      - MagazinePistolSubMachineGunTopMountedEmpty
-      - MagazineRifle
-      - MagazineRifleEmpty
-      - MagazineShotgun
-      - MagazineShotgunEmpty
-      - MagazineShotgunSlug
-      - RiotShield
-      - SpeedLoaderMagnum
-      - SpeedLoaderMagnumEmpty
+    - BoxLethalshot
+    - BoxShotgunFlare
+    - BoxShotgunSlug
+    - MagazineBoxLightRifle
+    - MagazineBoxMagnum
+    - MagazineBoxPistol
+    - MagazineBoxRifle
+    - MagazineLightRifle
+    - MagazineLightRifleEmpty
+    - MagazinePistol
+    - MagazinePistolEmpty
+    - MagazinePistolSubMachineGun
+    - MagazinePistolSubMachineGunEmpty
+    - MagazinePistolSubMachineGunTopMounted
+    - MagazinePistolSubMachineGunTopMountedEmpty
+    - MagazineRifle
+    - MagazineRifleEmpty
+    - MagazineShotgun
+    - MagazineShotgunEmpty
+    - MagazineShotgunSlug
+    - RiotShield
+    - SpeedLoaderMagnum
+    - SpeedLoaderMagnumEmpty
 
 - type: entity
   id: AutolatheHyperConvection
@@ -257,9 +257,9 @@
   - type: MaterialStorage
     whitelist:
       tags:
-        - Sheet
-        - RawMaterial
-        - Ingot
+      - Sheet
+      - RawMaterial
+      - Ingot
   - type: Lathe
     idleState: icon
     runningState: building
@@ -268,150 +268,153 @@
     - Dropper
     - ClothingEyesGlassesChemical
     dynamicRecipes:
-      - PowerDrill
-      - MiningDrill
-      - MiningDrillDiamond
-      - AnomalyScanner
-      - AnomalyLocator
-      - AnomalyLocatorWide
-      - HandheldCrewMonitor
-      - Scalpel
-      - Retractor
-      - Cautery
-      - Drill
-      - WeaponParticleDecelerator
-      - HoloprojectorField
-      - Saw
-      - Hemostat
-      - CryostasisBeaker
-      - SyringeCryostasis
-      - Syringe
-      - Implanter
-      - PillCanister
-      - ChemistryEmptyBottle01
-      - AdvancedCapacitorStockPart
-      - AdvancedMatterBinStockPart
-      - NanoManipulatorStockPart
-      - SuperCapacitorStockPart
-      - SuperMatterBinStockPart
-      - PicoManipulatorStockPart
-      - BluespaceCapacitorStockPart
-      - BluespaceManipulatorStockPart
-      - BluespaceMatterBinStockPart
-      - AdvMopItem
-      - WeaponSprayNozzle
-      - ClothingBackpackWaterTank
-      - MegaSprayBottle
-      - TimerTrigger
-      - ChemicalPayload
-      - FlashPayload
-      - Signaller
-      - SignallerAdvanced
-      - SignalTrigger
-      - VoiceTrigger
-      - Igniter
-      - HandHeldMassScanner
-      - PowerCellMicroreactor
-      - PowerCellHigh
-      - WeaponPistolCHIMP
-      - ClothingMaskWeldingGas
-      - WeaponGauntletGorilla
-      - SynthesizerInstrument
-      - RPED
-      - ClothingShoesBootsMagSci
-      - ClothingShoesBootsMoon
-      - ClothingShoesBootsSpeed
-      - NodeScanner
-      - HolofanProjector
-      - BluespaceBeaker
-      - SyringeBluespace
-      - WeaponForceGun
-      - WeaponLaserSvalinn
-      - WeaponProtoKineticAccelerator
-      - WeaponTetherGun
-      - WeaponGrapplingGun
-      - ClothingBackpackHolding
-      - ClothingBackpackSatchelHolding
-      - ClothingBackpackDuffelHolding
-      - WelderExperimental
-      - JawsOfLife
-      - CoreSilver # Nyanotrasen - Silver Golem core
-      - FauxTileAstroGrass
-      - FauxTileMowedAstroGrass
-      - FauxTileJungleAstroGrass
-      - FauxTileAstroIce
-      - FauxTileAstroSnow
-      - OreBagOfHolding
-      - DeviceQuantumSpinInverter
-      - CanilunztTranslator
-      - BubblishTranslator
-      - NekomimeticTranslator
-      - DraconicTranslator
-      - SolCommonTranslator
-      - RootSpeakTranslator
-      - XenoTranslator
-      - BasicGalaticCommonTranslatorImplanter
-      - AdvancedGalaticCommonTranslatorImplanter
-      - BubblishTranslatorImplanter
-      - NekomimeticTranslatorImplanter
-      - DraconicTranslatorImplanter
-      - CanilunztTranslatorImplanter
-      - SolCommonTranslatorImplanter
-      - RootSpeakTranslatorImplanter
-      - AnimalTranslator
-      - MofficTranslatorImplanter
-      - MofficTranslator
-      - RCDAmmo #DeltaV
-      - RCD #EE
-      # Shitmed Change
-      - EnergyScalpel
-      - EnergyCautery
-      - AdvancedRetractor
+    - PowerDrill
+    - MiningDrill
+    - MiningDrillDiamond
+    - AnomalyScanner
+    - AnomalyLocator
+    - AnomalyLocatorWide
+    - HandheldCrewMonitor
+    - Scalpel
+    - Retractor
+    - Cautery
+    - Drill
+    - WeaponParticleDecelerator
+    - HoloprojectorField
+    - Saw
+    - Hemostat
+    - CryostasisBeaker
+    - SyringeCryostasis
+    - Syringe
+    - Implanter
+    - PillCanister
+    - ChemistryEmptyBottle01
+    - AdvancedCapacitorStockPart
+    - AdvancedMatterBinStockPart
+    - NanoManipulatorStockPart
+    - SuperCapacitorStockPart
+    - SuperMatterBinStockPart
+    - PicoManipulatorStockPart
+    - BluespaceCapacitorStockPart
+    - BluespaceManipulatorStockPart
+    - BluespaceMatterBinStockPart
+    - AdvMopItem
+    - WeaponSprayNozzle
+    - ClothingBackpackWaterTank
+    - MegaSprayBottle
+    - TimerTrigger
+    - ChemicalPayload
+    - FlashPayload
+    - Signaller
+    - SignallerAdvanced
+    - SignalTrigger
+    - VoiceTrigger
+    - Igniter
+    - HandHeldMassScanner
+    - PowerCellMicroreactor
+    - PowerCellHigh
+    - WeaponPistolCHIMP
+    - ClothingMaskWeldingGas
+    - WeaponGauntletGorilla
+    - SynthesizerInstrument
+    - RPED
+    - ClothingShoesBootsMagSci
+    - ClothingShoesBootsMoon
+    - ClothingShoesBootsSpeed
+    - NodeScanner
+    - HolofanProjector
+    - BluespaceBeaker
+    - SyringeBluespace
+    - WeaponForceGun
+    - WeaponLaserSvalinn
+    - WeaponProtoKineticAccelerator
+    - WeaponTetherGun
+    - WeaponGrapplingGun
+    - ClothingBackpackHolding
+    - ClothingBackpackSatchelHolding
+    - ClothingBackpackDuffelHolding
+    - WelderExperimental
+    - JawsOfLife
+    - CoreSilver # Nyanotrasen - Silver Golem core
+    - FauxTileAstroGrass
+    - FauxTileMowedAstroGrass
+    - FauxTileJungleAstroGrass
+    - FauxTileAstroIce
+    - FauxTileAstroSnow
+    - OreBagOfHolding
+    - DeviceQuantumSpinInverter
+    - CanilunztTranslator
+    - BubblishTranslator
+    - NekomimeticTranslator
+    - DraconicTranslator
+    - SolCommonTranslator
+    - RootSpeakTranslator
+    - XenoTranslator
+    - BasicGalaticCommonTranslatorImplanter
+    - AdvancedGalaticCommonTranslatorImplanter
+    - BubblishTranslatorImplanter
+    - NekomimeticTranslatorImplanter
+    - DraconicTranslatorImplanter
+    - CanilunztTranslatorImplanter
+    - SolCommonTranslatorImplanter
+    - RootSpeakTranslatorImplanter
+    - AnimalTranslator
+    - MofficTranslatorImplanter
+    - MofficTranslator
+    - ClothingEyesNightVisionGoggles
+    - ClothingEyesNightVisionDiagnosticGoggles
+    - ClothingEyesThermalVisionGoggles
+    - RCDAmmo #DeltaV
+    - RCD #EE
+    # Shitmed Change
+    - EnergyScalpel
+    - EnergyCautery
+    - AdvancedRetractor
   - type: EmagLatheRecipes
     emagDynamicRecipes:
-      - BoxBeanbag
-      - BoxShotgunIncendiary
-      - BoxShotgunUranium
-      - ExplosivePayload
-      - GrenadeBlast
-      - GrenadeEMP
-      - GrenadeFlash
-      - HoloprojectorSecurity
-      - MagazineBoxLightRifleIncendiary
-      - MagazineBoxLightRifleUranium
-      - MagazineBoxMagnumIncendiary
-      - MagazineBoxMagnumUranium
-      - MagazineBoxPistolIncendiary
-      - MagazineBoxPistolUranium
-      - MagazineBoxRifleIncendiary
-      - MagazineBoxRifleUranium
-      - MagazineGrenadeEmpty
-      - MagazineLightRifleIncendiary
-      - MagazineLightRifleUranium
-      - MagazinePistolIncendiary
-      - MagazinePistolUranium
-      - MagazineRifleIncendiary
-      - MagazineRifleUranium
-      - MagazineShotgunBeanbag
-      - MagazineShotgunIncendiary
-      - MagazineShotgunIncendiary
-      - PortableRecharger
-      - PowerCageHigh
-      - PowerCageMedium
-      - PowerCageSmall
-      - ShellTranquilizer
-      - SpeedLoaderMagnumIncendiary
-      - SpeedLoaderMagnumUranium
-      - TelescopicShield
-      - Truncheon
-      - WeaponAdvancedLaser
-      - WeaponLaserCannon
-      - WeaponLaserCarbine
-      - WeaponXrayCannon
-      - WeaponEnergyGun       # DeltaV - Energy Gun
-      - WeaponEnergyGunMini   # DeltaV - Miniature Energy Gun
-      - WeaponEnergyGunPistol # DeltaV - PDW-9 Energy Pistol
-      - WeaponGunLaserCarbineAutomatic # DeltaV - IK-60 Laser Carbine
+    - BoxBeanbag
+    - BoxShotgunIncendiary
+    - BoxShotgunUranium
+    - ExplosivePayload
+    - GrenadeBlast
+    - GrenadeEMP
+    - GrenadeFlash
+    - HoloprojectorSecurity
+    - MagazineBoxLightRifleIncendiary
+    - MagazineBoxLightRifleUranium
+    - MagazineBoxMagnumIncendiary
+    - MagazineBoxMagnumUranium
+    - MagazineBoxPistolIncendiary
+    - MagazineBoxPistolUranium
+    - MagazineBoxRifleIncendiary
+    - MagazineBoxRifleUranium
+    - MagazineGrenadeEmpty
+    - MagazineLightRifleIncendiary
+    - MagazineLightRifleUranium
+    - MagazinePistolIncendiary
+    - MagazinePistolUranium
+    - MagazineRifleIncendiary
+    - MagazineRifleUranium
+    - MagazineShotgunBeanbag
+    - MagazineShotgunIncendiary
+    - MagazineShotgunIncendiary
+    - PortableRecharger
+    - PowerCageHigh
+    - PowerCageMedium
+    - PowerCageSmall
+    - ShellTranquilizer
+    - SpeedLoaderMagnumIncendiary
+    - SpeedLoaderMagnumUranium
+    - TelescopicShield
+    - Truncheon
+    - WeaponAdvancedLaser
+    - WeaponLaserCannon
+    - WeaponLaserCarbine
+    - WeaponXrayCannon
+    - WeaponEnergyGun       # DeltaV - Energy Gun
+    - WeaponEnergyGunMini   # DeltaV - Miniature Energy Gun
+    - WeaponEnergyGunPistol # DeltaV - PDW-9 Energy Pistol
+    - WeaponGunLaserCarbineAutomatic # DeltaV - IK-60 Laser Carbine
 
 - type: entity
   id: ProtolatheHyperConvection
@@ -471,102 +474,102 @@
     - SpaceHeaterMachineCircuitBoard
     - StationAnchorCircuitboard
     dynamicRecipes:
-      - ThermomachineFreezerMachineCircuitBoard
-      - HellfireFreezerMachineCircuitBoard
-      - PortableScrubberMachineCircuitBoard
-      - CloningPodMachineCircuitboard
-      - MedicalScannerMachineCircuitboard
-      - CryoPodMachineCircuitboard
-      - VaccinatorMachineCircuitboard
-      - DiagnoserMachineCircuitboard
-      - BiomassReclaimerMachineCircuitboard
-      - BiofabricatorMachineCircuitboard
-      - SurveillanceCameraRouterCircuitboard
-      - SurveillanceCameraMonitorCircuitboard
-      - SurveillanceWirelessCameraMonitorCircuitboard
-      - SurveillanceCameraWirelessRouterCircuitboard
-      - ComputerTelevisionCircuitboard
-      - JukeboxCircuitBoard
-      - SurveillanceWirelessCameraMovableCircuitboard
-      - SurveillanceWirelessCameraAnchoredCircuitboard
-      - HydroponicsTrayMachineCircuitboard
-      - SolarControlComputerCircuitboard
-      - SolarTrackerElectronics
-      - TurboItemRechargerCircuitboard
-      - PowerComputerCircuitboard
-      - AlertsComputerCircuitboard
-      - AutolatheHyperConvectionMachineCircuitboard
-      - ProtolatheHyperConvectionMachineCircuitboard
-      - CircuitImprinterHyperConvectionMachineCircuitboard
-      - FatExtractorMachineCircuitboard
-      - FlatpackerMachineCircuitboard
-      - SheetifierMachineCircuitboard
-      - ShuttleConsoleCircuitboard
-      - RadarConsoleCircuitboard
-      - TechDiskComputerCircuitboard
-      - DawInstrumentMachineCircuitboard
-      - CloningConsoleComputerCircuitboard
-      - StasisBedMachineCircuitboard
-      - OreProcessorIndustrialMachineCircuitboard
-      - CargoTelepadMachineCircuitboard
-      - RipleyCentralElectronics
-      - RipleyPeripheralsElectronics
-      - HonkerCentralElectronics
-      - HonkerPeripheralsElectronics
-      - HonkerTargetingElectronics
-      - HamtrCentralElectronics
-      - HamtrPeripheralsElectronics
-      - PortableGeneratorPacmanMachineCircuitboard
-      - PortableGeneratorSuperPacmanMachineCircuitboard
-      - PortableGeneratorJrPacmanMachineCircuitboard
-      - WallmountGeneratorElectronics
-      - WallmountGeneratorAPUElectronics
-      - WallmountSubstationElectronics
-      - PowerCageRechargerCircuitboard
-      - EmitterCircuitboard
-      - ThrusterMachineCircuitboard
-      - GyroscopeMachineCircuitboard
-      - MiniGravityGeneratorCircuitboard
-      - ShuttleGunKineticCircuitboard
-      - GasRecyclerMachineCircuitboard
-      - SeedExtractorMachineCircuitboard
-      - AnalysisComputerCircuitboard
-      - ExosuitFabricatorMachineCircuitboard
-      - AnomalyVesselCircuitboard
-      - AnomalyVesselExperimentalCircuitboard
-      - AnomalySynchronizerCircuitboard
-      - APECircuitboard
-      - ArtifactAnalyzerMachineCircuitboard
-      - ArtifactCrusherMachineCircuitboard
-      - TelecomServerCircuitboard
-      - MassMediaCircuitboard
-      - ReagentGrinderIndustrialMachineCircuitboard
-      - ReverseEngineeringMachineCircuitboard
-      - CrewMonitoringComputerCircuitboard
-      - DoorElectronics
-      - FireAlarmElectronics
-      - FirelockElectronics
-      - IntercomElectronics
-      - MailingUnitElectronics
-      - SalvageMagnetMachineCircuitboard
-      - StationMapElectronics
-      - MetempsychoticMachineCircuitboard
-      - SalvageExpeditionsComputerCircuitboard
-      - JukeboxCircuitBoard
-      - AutodocCircuitboard # Shitmed Change
-      - OperatingTableCircuitboard # Shitmed Change
+    - ThermomachineFreezerMachineCircuitBoard
+    - HellfireFreezerMachineCircuitBoard
+    - PortableScrubberMachineCircuitBoard
+    - CloningPodMachineCircuitboard
+    - MedicalScannerMachineCircuitboard
+    - CryoPodMachineCircuitboard
+    - VaccinatorMachineCircuitboard
+    - DiagnoserMachineCircuitboard
+    - BiomassReclaimerMachineCircuitboard
+    - BiofabricatorMachineCircuitboard
+    - SurveillanceCameraRouterCircuitboard
+    - SurveillanceCameraMonitorCircuitboard
+    - SurveillanceWirelessCameraMonitorCircuitboard
+    - SurveillanceCameraWirelessRouterCircuitboard
+    - ComputerTelevisionCircuitboard
+    - JukeboxCircuitBoard
+    - SurveillanceWirelessCameraMovableCircuitboard
+    - SurveillanceWirelessCameraAnchoredCircuitboard
+    - HydroponicsTrayMachineCircuitboard
+    - SolarControlComputerCircuitboard
+    - SolarTrackerElectronics
+    - TurboItemRechargerCircuitboard
+    - PowerComputerCircuitboard
+    - AlertsComputerCircuitboard
+    - AutolatheHyperConvectionMachineCircuitboard
+    - ProtolatheHyperConvectionMachineCircuitboard
+    - CircuitImprinterHyperConvectionMachineCircuitboard
+    - FatExtractorMachineCircuitboard
+    - FlatpackerMachineCircuitboard
+    - SheetifierMachineCircuitboard
+    - ShuttleConsoleCircuitboard
+    - RadarConsoleCircuitboard
+    - TechDiskComputerCircuitboard
+    - DawInstrumentMachineCircuitboard
+    - CloningConsoleComputerCircuitboard
+    - StasisBedMachineCircuitboard
+    - OreProcessorIndustrialMachineCircuitboard
+    - CargoTelepadMachineCircuitboard
+    - RipleyCentralElectronics
+    - RipleyPeripheralsElectronics
+    - HonkerCentralElectronics
+    - HonkerPeripheralsElectronics
+    - HonkerTargetingElectronics
+    - HamtrCentralElectronics
+    - HamtrPeripheralsElectronics
+    - PortableGeneratorPacmanMachineCircuitboard
+    - PortableGeneratorSuperPacmanMachineCircuitboard
+    - PortableGeneratorJrPacmanMachineCircuitboard
+    - WallmountGeneratorElectronics
+    - WallmountGeneratorAPUElectronics
+    - WallmountSubstationElectronics
+    - PowerCageRechargerCircuitboard
+    - EmitterCircuitboard
+    - ThrusterMachineCircuitboard
+    - GyroscopeMachineCircuitboard
+    - MiniGravityGeneratorCircuitboard
+    - ShuttleGunKineticCircuitboard
+    - GasRecyclerMachineCircuitboard
+    - SeedExtractorMachineCircuitboard
+    - AnalysisComputerCircuitboard
+    - ExosuitFabricatorMachineCircuitboard
+    - AnomalyVesselCircuitboard
+    - AnomalyVesselExperimentalCircuitboard
+    - AnomalySynchronizerCircuitboard
+    - APECircuitboard
+    - ArtifactAnalyzerMachineCircuitboard
+    - ArtifactCrusherMachineCircuitboard
+    - TelecomServerCircuitboard
+    - MassMediaCircuitboard
+    - ReagentGrinderIndustrialMachineCircuitboard
+    - ReverseEngineeringMachineCircuitboard
+    - CrewMonitoringComputerCircuitboard
+    - DoorElectronics
+    - FireAlarmElectronics
+    - FirelockElectronics
+    - IntercomElectronics
+    - MailingUnitElectronics
+    - SalvageMagnetMachineCircuitboard
+    - StationMapElectronics
+    - MetempsychoticMachineCircuitboard
+    - SalvageExpeditionsComputerCircuitboard
+    - JukeboxCircuitBoard
+    - AutodocCircuitboard # Shitmed Change
+    - OperatingTableCircuitboard # Shitmed Change
   - type: EmagLatheRecipes
     emagDynamicRecipes:
-      - ShuttleGunDusterCircuitboard
-      - ShuttleGunFriendshipCircuitboard
-      - ShuttleGunPerforatorCircuitboard
-      - ShuttleGunSvalinnMachineGunCircuitboard
+    - ShuttleGunDusterCircuitboard
+    - ShuttleGunFriendshipCircuitboard
+    - ShuttleGunPerforatorCircuitboard
+    - ShuttleGunSvalinnMachineGunCircuitboard
   - type: MaterialStorage
     whitelist:
       tags:
-        - Sheet
-        - RawMaterial
-        - Ingot
+      - Sheet
+      - RawMaterial
+      - Ingot
   - type: RequireProjectileTarget
 
 - type: entity
@@ -694,7 +697,7 @@
     - HamtrLLeg
     - HamtrRLeg
     - VimHarness
-  # Begin Nyano additions
+    # Begin Nyano additions
     - JetpackBlue
     - JetpackMini
   # End Nyano additions
@@ -732,8 +735,8 @@
   - type: MaterialStorage
     whitelist:
       tags:
-        - Sheet
-        - RawMaterial
+      - Sheet
+      - RawMaterial
   - type: Lathe
     idleState: icon
     runningState: building
@@ -910,6 +913,7 @@
       - WeaponDisablerSMG
       - WeaponLaserCannon
       - WeaponLaserCarbine
+      - ClothingEyesNightVisionSecurityGoggles
       - ClothingHeadHelmetInsulated # Nyanotrasen - Insulative headgear
       - ClothingHeadCage # Nyanotrasen - Insulative headgear
       - ShockCollar # Nyanotrasen - Shock Collar
@@ -932,9 +936,9 @@
   - type: MaterialStorage
     whitelist:
       tags:
-        - Sheet
-        - RawMaterial
-        - Ingot
+      - Sheet
+      - RawMaterial
+      - Ingot
 
 - type: entity
   id: AmmoTechFab
@@ -942,52 +946,52 @@
   name: ammo techfab
   description: Prints the bare minimum of bullets that any budget military or armory could need. Nothing fancy.
   components:
-    - type: Sprite
-      sprite: Structures/Machines/techfab.rsi
-      layers:
-        - state: icon
-          map: ["enum.LatheVisualLayers.IsRunning"]
-        - state: ammo
-        - state: unlit
-          shader: unshaded
-          map: ["enum.PowerDeviceVisualLayers.Powered"]
-        - state: inserting
-          map: ["enum.MaterialStorageVisualLayers.Inserting"]
-        - state: panel
-          map: ["enum.WiresVisualLayers.MaintenancePanel"]
-    - type: Machine
-      board: AmmoTechFabCircuitboard
-    - type: Lathe
-      idleState: icon
-      runningState: icon
-      staticRecipes:
-        - BoxLethalshot
-        - BoxShotgunFlare
-        - BoxShotgunSlug
-        - MagazineBoxLightRifle
-        - MagazineBoxMagnum
-        - MagazineBoxPistol
-        - MagazineBoxRifle
-        - MagazineLightRifle
-        - MagazineLightRifleEmpty
-        - MagazinePistol
-        - MagazinePistolEmpty
-        - MagazineRifle
-        - MagazineRifleEmpty
-        - MagazineShotgun
-        - MagazineShotgunEmpty
-        - MagazineShotgunSlug
-        - ShellTranquilizer
-        - SpeedLoaderMagnum
-        - SpeedLoaderMagnumEmpty
-        - CartridgeSpecial
-        - MagazineBoxSpecial
-    - type: MaterialStorage
-      whitelist:
-        tags:
-          - Sheet
-          - RawMaterial
-          - Ingot
+  - type: Sprite
+    sprite: Structures/Machines/techfab.rsi
+    layers:
+    - state: icon
+      map: ["enum.LatheVisualLayers.IsRunning"]
+    - state: ammo
+    - state: unlit
+      shader: unshaded
+      map: ["enum.PowerDeviceVisualLayers.Powered"]
+    - state: inserting
+      map: ["enum.MaterialStorageVisualLayers.Inserting"]
+    - state: panel
+      map: ["enum.WiresVisualLayers.MaintenancePanel"]
+  - type: Machine
+    board: AmmoTechFabCircuitboard
+  - type: Lathe
+    idleState: icon
+    runningState: icon
+    staticRecipes:
+    - BoxLethalshot
+    - BoxShotgunFlare
+    - BoxShotgunSlug
+    - MagazineBoxLightRifle
+    - MagazineBoxMagnum
+    - MagazineBoxPistol
+    - MagazineBoxRifle
+    - MagazineLightRifle
+    - MagazineLightRifleEmpty
+    - MagazinePistol
+    - MagazinePistolEmpty
+    - MagazineRifle
+    - MagazineRifleEmpty
+    - MagazineShotgun
+    - MagazineShotgunEmpty
+    - MagazineShotgunSlug
+    - ShellTranquilizer
+    - SpeedLoaderMagnum
+    - SpeedLoaderMagnumEmpty
+    - CartridgeSpecial
+    - MagazineBoxSpecial
+  - type: MaterialStorage
+    whitelist:
+      tags:
+      - Sheet
+      - RawMaterial
+      - Ingot
 
 - type: entity
   id: MedicalTechFab
@@ -1012,58 +1016,59 @@
     idleState: icon
     runningState: icon
     staticRecipes:
-      - Brutepack
-      - Ointment
-      - Gauze
-      - HandLabeler
-      - Defibrillator
-      - HandheldHealthAnalyzer
-      - ClothingHandsGlovesLatex
-      - ClothingHandsGlovesNitrile
-      - ClothingMaskSterile
-      - DiseaseSwab
-      - Beaker
-      - LargeBeaker
-      - Dropper
-      - Jug
-      - Syringe
-      - Implanter
-      - PillCanister
-      - BodyBag
-      - ChemistryEmptyBottle01
-      - RollerBedSpawnFolded
-      - CheapRollerBedSpawnFolded
-      - EmergencyRollerBedSpawnFolded
-      - Medkit
-      - MedkitBurn
-      - MedkitToxin
-      - MedkitO2
-      - MedkitBrute
-      - MedkitAdvanced
-      - MedkitRadiation
-      - MedkitCombat
-      - Scalpel
-      - Retractor
-      - Cautery
-      - Drill
-      - Saw
-      - Hemostat
-      - ClothingEyesGlassesChemical
-      - BoneGel # Shitmed Change
+    - Brutepack
+    - Ointment
+    - Gauze
+    - HandLabeler
+    - Defibrillator
+    - HandheldHealthAnalyzer
+    - ClothingHandsGlovesLatex
+    - ClothingHandsGlovesNitrile
+    - ClothingMaskSterile
+    - DiseaseSwab
+    - Beaker
+    - LargeBeaker
+    - Dropper
+    - Jug
+    - Syringe
+    - Implanter
+    - PillCanister
+    - BodyBag
+    - ChemistryEmptyBottle01
+    - RollerBedSpawnFolded
+    - CheapRollerBedSpawnFolded
+    - EmergencyRollerBedSpawnFolded
+    - Medkit
+    - MedkitBurn
+    - MedkitToxin
+    - MedkitO2
+    - MedkitBrute
+    - MedkitAdvanced
+    - MedkitRadiation
+    - MedkitCombat
+    - Scalpel
+    - Retractor
+    - Cautery
+    - Drill
+    - Saw
+    - Hemostat
+    - ClothingEyesGlassesChemical
+    - BoneGel # Shitmed Change
     dynamicRecipes:
-      - ChemicalPayload
-      - CryostasisBeaker
-      - BluespaceBeaker
-      - SyringeBluespace
-      - ClothingEyesHudMedical # Nyano
-      - ChemicalPayload # Nyano
-      - SyringeCryostasis
-      # Shitmed Change
-      - EnergyScalpel
-      - EnergyCautery
-      - AdvancedRetractor
-      - OmnimedTool
-      - MedicalCyberneticEyes
+    - ChemicalPayload
+    - CryostasisBeaker
+    - BluespaceBeaker
+    - SyringeBluespace
+    - ClothingEyesHudMedical # Nyano
+    - ChemicalPayload # Nyano
+    - SyringeCryostasis
+    - ClothingEyesNightVisionMedicalGoggles
+    # Shitmed Change
+    - EnergyScalpel
+    - EnergyCautery
+    - AdvancedRetractor
+    - OmnimedTool
+    - MedicalCyberneticEyes
   - type: Machine
     board: MedicalTechFabCircuitboard
   - type: StealTarget
@@ -1090,209 +1095,209 @@
     idleState: icon
     runningState: building
     staticRecipes:
-      - ClothingUniformJumpsuitColorGrey
-      - ClothingUniformJumpskirtColorGrey
-      - ClothingUniformJumpsuitBartender
-      - ClothingUniformJumpskirtBartender
-      - ClothingHeadHatCapcap
-      - ClothingHeadHatCaptain
-      - ClothingUniformJumpsuitCaptain
-      - ClothingUniformJumpskirtCaptain
-      - ClothingUniformJumpsuitCapFormal
-      - ClothingUniformJumpskirtCapFormalDress
-      - ClothingUniformJumpsuitCargo
-      - ClothingUniformJumpskirtCargo
-      - ClothingUniformJumpsuitSalvageSpecialist
-      - ClothingHeadHatBeretEngineering
-      - ClothingUniformJumpsuitChiefEngineer
-      - ClothingUniformJumpskirtChiefEngineer
-      - ClothingUniformJumpsuitChiefEngineerTurtle
-      - ClothingUniformJumpskirtChiefEngineerTurtle
-      - ClothingUniformJumpsuitChaplain
-      - ClothingUniformJumpskirtChaplain
-      - ClothingUniformJumpsuitChef
-      - ClothingUniformJumpskirtChef
-      - ClothingUniformJumpsuitChemistry
-      - ClothingUniformJumpskirtChemistry
-      - ClothingUniformJumpsuitClown
-      - ClothingHeadHatBeretCmo
-      - ClothingUniformJumpsuitCMO
-      - ClothingUniformJumpskirtCMO
-      - ClothingUniformJumpsuitCMOTurtle
-      - ClothingUniformJumpskirtCMOTurtle
-      - ClothingUniformJumpsuitDetective
-      - ClothingUniformJumpskirtDetective
-      - ClothingUniformJumpsuitEngineering
-      - ClothingUniformJumpskirtEngineering
-      - ClothingUniformJumpsuitSeniorEngineer
-      - ClothingUniformJumpskirtSeniorEngineer
-      - ClothingHeadHatHopcap
-      - ClothingUniformJumpsuitHoP
-      - ClothingUniformJumpskirtHoP
-      - ClothingHeadHatBeretHoS
-      - ClothingHeadHatHoshat
-      - ClothingUniformJumpsuitHoS
-      - ClothingUniformJumpskirtHoS
-      - ClothingUniformJumpsuitHoSBlue # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpskirtHoSBlue # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpsuitHoSGrey # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpskirtHoSGrey # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpsuitHosFormal
-      - ClothingUniformJumpskirtHosFormal
-      - ClothingUniformJumpsuitHoSAlt
-      - ClothingUniformJumpskirtHoSAlt
-      - ClothingUniformJumpsuitHoSBlue
-      - ClothingUniformJumpsuitHoSGrey
-      - ClothingUniformJumpsuitHoSParadeMale
-      - ClothingUniformJumpskirtHoSParadeMale
-      - ClothingUniformJumpsuitHydroponics
-      - ClothingUniformJumpskirtHydroponics
-      - ClothingUniformJumpsuitJanitor
-      - ClothingUniformJumpskirtJanitor
-      - ClothingUniformJumpsuitLawyerBlack
-      - ClothingUniformJumpsuitLibrarian
-      - ClothingUniformJumpskirtColorLightBrown
-      - ClothingUniformCourier # DeltaV - Courier Uniform
-      - ClothingUniformSkirtCourier # DeltaV - Courier Uniform
-      - ClothingUniformJumpsuitMantis # Nyanotrasen - Forensic Mantis
-      - ClothingUniformSkirtMantis # Nyanotrasen - Forensic Mantis
-      - ClothingHeadHatBeretSeniorPhysician
-      - ClothingUniformJumpsuitMedicalDoctor
-      - ClothingUniformJumpskirtMedicalDoctor
-      - ClothingUniformJumpsuitSeniorPhysician
-      - ClothingUniformJumpskirtSeniorPhysician
-      - ClothingUniformJumpsuitMime
-      - ClothingUniformJumpskirtMime
-      - ClothingUniformJumpsuitMusician
-      - ClothingUniformJumpsuitParamedic
-      - ClothingUniformJumpskirtParamedic
-      - ClothingUniformJumpsuitSeniorOfficer
-      - ClothingUniformJumpskirtSeniorOfficer
-      - ClothingUniformJumpsuitPrisoner
-      - ClothingUniformJumpskirtPrisoner
-      - ClothingHeadHatQMsoft
-      - ClothingHeadHatBeretQM
-      - ClothingUniformJumpsuitQM
-      - ClothingUniformJumpskirtQM
-      - ClothingUniformJumpsuitQMTurtleneck
-      - ClothingUniformJumpskirtQMTurtleneck
-      - ClothingUniformJumpsuitQMFormal
-      - ClothingHeadHatBeretRND
-      - ClothingUniformJumpsuitResearchDirector
-      - ClothingUniformJumpskirtResearchDirector
-      - ClothingUniformJumpsuitScientist
-      - ClothingUniformJumpskirtScientist
-      - ClothingUniformJumpsuitSeniorResearcher
-      - ClothingUniformJumpskirtSeniorResearcher
-      - ClothingHeadHatBeretSecurity
-      - ClothingUniformJumpsuitSec
-      - ClothingUniformJumpskirtSec
-      - ClothingUniformJumpsuitSecBlue # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpskirtSecBlue # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpsuitSecGrey # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpskirtSecGrey # DeltaV - alternate sec uniforms
-      - ClothingHeadHatBeretBrigmedic
-      - ClothingUniformJumpsuitBrigmedic
-      - ClothingUniformJumpskirtBrigmedic
-      - ClothingHeadHatBeretWarden
-      - ClothingHeadHatWarden
-      - ClothingUniformJumpsuitWarden
-      - ClothingUniformJumpskirtWarden
-      - ClothingUniformJumpsuitWardenBlue # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpskirtWardenBlue # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpsuitWardenGrey # DeltaV - alternate sec uniforms
-      - ClothingUniformJumpskirtWardenGrey # DeltaV - alternate sec uniforms
-      - ClothingHeadHatParamedicsoft
-      # Winter outfits
-      - ClothingOuterWinterCap
-      - ClothingOuterWinterCE
-      - ClothingOuterWinterCMO
-      - ClothingOuterWinterHoP
-      - ClothingOuterWinterHoSUnarmored
-      - ClothingOuterWinterWardenUnarmored
-      - ClothingOuterWinterQM
-      - ClothingOuterWinterRD
-      - ClothingNeckMantleCap
-      - ClothingNeckMantleCE
-      - ClothingNeckMantleCMO
-      - ClothingNeckMantleHOP
-      - ClothingNeckMantleHOS
-      - ClothingNeckMantleRD
-      - ClothingNeckMantleQM
-      - ClothingOuterStasecSweater # DeltaV - added stasec sweater to uniform printer.
-      - ClothingOuterWinterMusician
-      - ClothingOuterWinterClown
-      - ClothingOuterWinterMime
-      - ClothingOuterWinterCoat
-      - ClothingOuterWinterJani
-      - ClothingOuterWinterBar
-      - ClothingOuterWinterChef
-      - ClothingOuterWinterHydro
-      - ClothingOuterWinterAtmos
-      - ClothingOuterWinterEngi
-      - ClothingOuterWinterCargo
-      - ClothingOuterWinterMiner
-      - ClothingOuterWinterMed
-      - ClothingOuterWinterPara
-      - ClothingOuterWinterChem
-      - ClothingOuterWinterGen
-      - ClothingOuterWinterViro
-      - ClothingOuterWinterSci
-      - ClothingOuterWinterRobo
-      - ClothingOuterWinterSec
-      # Ties
-      - ClothingNeckTieRed
-      - ClothingNeckTieDet
-      - ClothingNeckTieSci
-      # Scarfs - All scarfs avaible in winterdrobe
-      - ClothingNeckScarfStripedGreen
-      - ClothingNeckScarfStripedBlue
-      - ClothingNeckScarfStripedRed
-      - ClothingNeckScarfStripedBrown
-      - ClothingNeckScarfStripedLightBlue
-      - ClothingNeckScarfStripedOrange
-      - ClothingNeckScarfStripedBlack
-      - ClothingNeckScarfStripedPurple
-      # Carpets
-      - Carpet
-      - CarpetBlack
-      - CarpetPink
-      - CarpetBlue
-      - CarpetGreen
-      - CarpetOrange
-      - CarpetPurple
-      - CarpetCyan
-      - CarpetWhite
+    - ClothingUniformJumpsuitColorGrey
+    - ClothingUniformJumpskirtColorGrey
+    - ClothingUniformJumpsuitBartender
+    - ClothingUniformJumpskirtBartender
+    - ClothingHeadHatCapcap
+    - ClothingHeadHatCaptain
+    - ClothingUniformJumpsuitCaptain
+    - ClothingUniformJumpskirtCaptain
+    - ClothingUniformJumpsuitCapFormal
+    - ClothingUniformJumpskirtCapFormalDress
+    - ClothingUniformJumpsuitCargo
+    - ClothingUniformJumpskirtCargo
+    - ClothingUniformJumpsuitSalvageSpecialist
+    - ClothingHeadHatBeretEngineering
+    - ClothingUniformJumpsuitChiefEngineer
+    - ClothingUniformJumpskirtChiefEngineer
+    - ClothingUniformJumpsuitChiefEngineerTurtle
+    - ClothingUniformJumpskirtChiefEngineerTurtle
+    - ClothingUniformJumpsuitChaplain
+    - ClothingUniformJumpskirtChaplain
+    - ClothingUniformJumpsuitChef
+    - ClothingUniformJumpskirtChef
+    - ClothingUniformJumpsuitChemistry
+    - ClothingUniformJumpskirtChemistry
+    - ClothingUniformJumpsuitClown
+    - ClothingHeadHatBeretCmo
+    - ClothingUniformJumpsuitCMO
+    - ClothingUniformJumpskirtCMO
+    - ClothingUniformJumpsuitCMOTurtle
+    - ClothingUniformJumpskirtCMOTurtle
+    - ClothingUniformJumpsuitDetective
+    - ClothingUniformJumpskirtDetective
+    - ClothingUniformJumpsuitEngineering
+    - ClothingUniformJumpskirtEngineering
+    - ClothingUniformJumpsuitSeniorEngineer
+    - ClothingUniformJumpskirtSeniorEngineer
+    - ClothingHeadHatHopcap
+    - ClothingUniformJumpsuitHoP
+    - ClothingUniformJumpskirtHoP
+    - ClothingHeadHatBeretHoS
+    - ClothingHeadHatHoshat
+    - ClothingUniformJumpsuitHoS
+    - ClothingUniformJumpskirtHoS
+    - ClothingUniformJumpsuitHoSBlue # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpskirtHoSBlue # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpsuitHoSGrey # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpskirtHoSGrey # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpsuitHosFormal
+    - ClothingUniformJumpskirtHosFormal
+    - ClothingUniformJumpsuitHoSAlt
+    - ClothingUniformJumpskirtHoSAlt
+    - ClothingUniformJumpsuitHoSBlue
+    - ClothingUniformJumpsuitHoSGrey
+    - ClothingUniformJumpsuitHoSParadeMale
+    - ClothingUniformJumpskirtHoSParadeMale
+    - ClothingUniformJumpsuitHydroponics
+    - ClothingUniformJumpskirtHydroponics
+    - ClothingUniformJumpsuitJanitor
+    - ClothingUniformJumpskirtJanitor
+    - ClothingUniformJumpsuitLawyerBlack
+    - ClothingUniformJumpsuitLibrarian
+    - ClothingUniformJumpskirtColorLightBrown
+    - ClothingUniformCourier # DeltaV - Courier Uniform
+    - ClothingUniformSkirtCourier # DeltaV - Courier Uniform
+    - ClothingUniformJumpsuitMantis # Nyanotrasen - Forensic Mantis
+    - ClothingUniformSkirtMantis # Nyanotrasen - Forensic Mantis
+    - ClothingHeadHatBeretSeniorPhysician
+    - ClothingUniformJumpsuitMedicalDoctor
+    - ClothingUniformJumpskirtMedicalDoctor
+    - ClothingUniformJumpsuitSeniorPhysician
+    - ClothingUniformJumpskirtSeniorPhysician
+    - ClothingUniformJumpsuitMime
+    - ClothingUniformJumpskirtMime
+    - ClothingUniformJumpsuitMusician
+    - ClothingUniformJumpsuitParamedic
+    - ClothingUniformJumpskirtParamedic
+    - ClothingUniformJumpsuitSeniorOfficer
+    - ClothingUniformJumpskirtSeniorOfficer
+    - ClothingUniformJumpsuitPrisoner
+    - ClothingUniformJumpskirtPrisoner
+    - ClothingHeadHatQMsoft
+    - ClothingHeadHatBeretQM
+    - ClothingUniformJumpsuitQM
+    - ClothingUniformJumpskirtQM
+    - ClothingUniformJumpsuitQMTurtleneck
+    - ClothingUniformJumpskirtQMTurtleneck
+    - ClothingUniformJumpsuitQMFormal
+    - ClothingHeadHatBeretRND
+    - ClothingUniformJumpsuitResearchDirector
+    - ClothingUniformJumpskirtResearchDirector
+    - ClothingUniformJumpsuitScientist
+    - ClothingUniformJumpskirtScientist
+    - ClothingUniformJumpsuitSeniorResearcher
+    - ClothingUniformJumpskirtSeniorResearcher
+    - ClothingHeadHatBeretSecurity
+    - ClothingUniformJumpsuitSec
+    - ClothingUniformJumpskirtSec
+    - ClothingUniformJumpsuitSecBlue # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpskirtSecBlue # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpsuitSecGrey # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpskirtSecGrey # DeltaV - alternate sec uniforms
+    - ClothingHeadHatBeretBrigmedic
+    - ClothingUniformJumpsuitBrigmedic
+    - ClothingUniformJumpskirtBrigmedic
+    - ClothingHeadHatBeretWarden
+    - ClothingHeadHatWarden
+    - ClothingUniformJumpsuitWarden
+    - ClothingUniformJumpskirtWarden
+    - ClothingUniformJumpsuitWardenBlue # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpskirtWardenBlue # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpsuitWardenGrey # DeltaV - alternate sec uniforms
+    - ClothingUniformJumpskirtWardenGrey # DeltaV - alternate sec uniforms
+    - ClothingHeadHatParamedicsoft
+    # Winter outfits
+    - ClothingOuterWinterCap
+    - ClothingOuterWinterCE
+    - ClothingOuterWinterCMO
+    - ClothingOuterWinterHoP
+    - ClothingOuterWinterHoSUnarmored
+    - ClothingOuterWinterWardenUnarmored
+    - ClothingOuterWinterQM
+    - ClothingOuterWinterRD
+    - ClothingNeckMantleCap
+    - ClothingNeckMantleCE
+    - ClothingNeckMantleCMO
+    - ClothingNeckMantleHOP
+    - ClothingNeckMantleHOS
+    - ClothingNeckMantleRD
+    - ClothingNeckMantleQM
+    - ClothingOuterStasecSweater # DeltaV - added stasec sweater to uniform printer.
+    - ClothingOuterWinterMusician
+    - ClothingOuterWinterClown
+    - ClothingOuterWinterMime
+    - ClothingOuterWinterCoat
+    - ClothingOuterWinterJani
+    - ClothingOuterWinterBar
+    - ClothingOuterWinterChef
+    - ClothingOuterWinterHydro
+    - ClothingOuterWinterAtmos
+    - ClothingOuterWinterEngi
+    - ClothingOuterWinterCargo
+    - ClothingOuterWinterMiner
+    - ClothingOuterWinterMed
+    - ClothingOuterWinterPara
+    - ClothingOuterWinterChem
+    - ClothingOuterWinterGen
+    - ClothingOuterWinterViro
+    - ClothingOuterWinterSci
+    - ClothingOuterWinterRobo
+    - ClothingOuterWinterSec
+    # Ties
+    - ClothingNeckTieRed
+    - ClothingNeckTieDet
+    - ClothingNeckTieSci
+    # Scarfs - All scarfs avaible in winterdrobe
+    - ClothingNeckScarfStripedGreen
+    - ClothingNeckScarfStripedBlue
+    - ClothingNeckScarfStripedRed
+    - ClothingNeckScarfStripedBrown
+    - ClothingNeckScarfStripedLightBlue
+    - ClothingNeckScarfStripedOrange
+    - ClothingNeckScarfStripedBlack
+    - ClothingNeckScarfStripedPurple
+    # Carpets
+    - Carpet
+    - CarpetBlack
+    - CarpetPink
+    - CarpetBlue
+    - CarpetGreen
+    - CarpetOrange
+    - CarpetPurple
+    - CarpetCyan
+    - CarpetWhite
   - type: EmagLatheRecipes
     emagStaticRecipes:
-      - ClothingHeadHatCentcomcap
-      - ClothingHeadHatCentcom
-      - ClothingUniformJumpsuitCentcomAgent
-      - ClothingUniformJumpsuitCentcomFormal
-      - ClothingUniformJumpskirtCentcomFormalDress
-      - ClothingUniformJumpsuitCentcomOfficer
-      - ClothingUniformJumpsuitCentcomOfficial
-      - ClothingHeadHatSyndieMAA
-      - ClothingHeadHatSyndie
-      - ClothingUniformJumpsuitOperative
-      - ClothingUniformJumpskirtOperative
-      - ClothingUniformJumpsuitSyndieFormal
-      - ClothingUniformJumpskirtSyndieFormalDress
-      - ClothingHeadPyjamaSyndicateBlack
-      - ClothingUniformJumpsuitPyjamaSyndicateBlack
-      - ClothingHeadPyjamaSyndicatePink
-      - ClothingUniformJumpsuitPyjamaSyndicatePink
-      - ClothingHeadPyjamaSyndicateRed
-      - ClothingUniformJumpsuitPyjamaSyndicateRed
-      - ClothingOuterWinterCentcom
-      - ClothingOuterWinterSyndie
-      - ClothingOuterWinterSyndieCap
+    - ClothingHeadHatCentcomcap
+    - ClothingHeadHatCentcom
+    - ClothingUniformJumpsuitCentcomAgent
+    - ClothingUniformJumpsuitCentcomFormal
+    - ClothingUniformJumpskirtCentcomFormalDress
+    - ClothingUniformJumpsuitCentcomOfficer
+    - ClothingUniformJumpsuitCentcomOfficial
+    - ClothingHeadHatSyndieMAA
+    - ClothingHeadHatSyndie
+    - ClothingUniformJumpsuitOperative
+    - ClothingUniformJumpskirtOperative
+    - ClothingUniformJumpsuitSyndieFormal
+    - ClothingUniformJumpskirtSyndieFormalDress
+    - ClothingHeadPyjamaSyndicateBlack
+    - ClothingUniformJumpsuitPyjamaSyndicateBlack
+    - ClothingHeadPyjamaSyndicatePink
+    - ClothingUniformJumpsuitPyjamaSyndicatePink
+    - ClothingHeadPyjamaSyndicateRed
+    - ClothingUniformJumpsuitPyjamaSyndicateRed
+    - ClothingOuterWinterCentcom
+    - ClothingOuterWinterSyndie
+    - ClothingOuterWinterSyndieCap
   - type: MaterialStorage
     whitelist:
       tags:
-        - Sheet
-        - RawMaterial
-        - Ingot
+      - Sheet
+      - RawMaterial
+      - Ingot
 
 - type: entity
   parent: BaseLathe
@@ -1300,49 +1305,49 @@
   name: ore processor
   description: It produces sheets and ingots using ores.
   components:
-    - type: Sprite
-      sprite: Structures/Machines/ore_processor.rsi
-      layers:
-        - state: icon
-          map: ["enum.LatheVisualLayers.IsRunning"]
-        - state: unlit
-          shader: unshaded
-          map: ["enum.PowerDeviceVisualLayers.Powered"]
-        - state: inserting
-          map: ["enum.MaterialStorageVisualLayers.Inserting"]
-        - state: panel
-          map: ["enum.WiresVisualLayers.MaintenancePanel"]
-    - type: Machine
-      board: OreProcessorMachineCircuitboard
-    - type: MaterialStorage
-      ignoreColor: true
-      whitelist:
-        tags:
-          - Ore
-    - type: Lathe
-      idleState: icon
-      runningState: building
-      defaultProductionAmount: 10
-      staticRecipes:
-        - BluespaceCrystal
-        - NormalityCrystal
-        - SheetSteel
-        - SheetGlass1
-        - SheetRGlass
-        - SheetPlasma1
-        - SheetPGlass1
-        - SheetRPGlass1
-        - SheetUranium1
-        - IngotGold1
-        - IngotSilver1
-        - MaterialBananium1
-    - type: MaterialStorageMagnetPickup # Delta V - Summary: Adds magnet pull from Frontier
-      magnetEnabled: True
-      range: 0.30 # Delta V - End Magnet Pull
-    - type: MiningPoints # DeltaV - Source of mining points for miners
-      transferSound:
-        path: /Audio/Effects/Cargo/ping.ogg
-    - type: MiningPointsLathe # DeltaV
+  - type: Sprite
+    sprite: Structures/Machines/ore_processor.rsi
+    layers:
+    - state: icon
+      map: ["enum.LatheVisualLayers.IsRunning"]
+    - state: unlit
+      shader: unshaded
+      map: ["enum.PowerDeviceVisualLayers.Powered"]
+    - state: inserting
+      map: ["enum.MaterialStorageVisualLayers.Inserting"]
+    - state: panel
+      map: ["enum.WiresVisualLayers.MaintenancePanel"]
+  - type: Machine
+    board: OreProcessorMachineCircuitboard
+  - type: MaterialStorage
+    ignoreColor: true
+    whitelist:
+      tags:
+      - Ore
+  - type: Lathe
+    idleState: icon
+    runningState: building
+    defaultProductionAmount: 10
+    staticRecipes:
+    - BluespaceCrystal
+    - NormalityCrystal
+    - SheetSteel
+    - SheetGlass1
+    - SheetRGlass
+    - SheetPlasma1
+    - SheetPGlass1
+    - SheetRPGlass1
+    - SheetUranium1
+    - IngotGold1
+    - IngotSilver1
+    - MaterialBananium1
+  - type: MaterialStorageMagnetPickup # Delta V - Summary: Adds magnet pull from Frontier
+    magnetEnabled: True
+    range: 0.30 # Delta V - End Magnet Pull
+  - type: MiningPoints # DeltaV - Source of mining points for miners
+    transferSound:
+      path: /Audio/Effects/Cargo/ping.ogg
+  - type: MiningPointsLathe # DeltaV
 
 - type: entity
   parent: OreProcessor
@@ -1358,22 +1363,22 @@
     materialUseMultiplier: 0.75
     timeMultiplier: 0.5
     staticRecipes:
-      - BluespaceCrystal
-      - NormalityCrystal
-      - SheetSteel
-      - SheetGlass1
-      - SheetRGlass
-      - SheetPlasma1
-      - SheetPGlass1
-      - SheetRPGlass1
-      - SheetPlasteel1
-      - SheetUranium1
-      - SheetUGlass1
-      - SheetRUGlass1
-      - IngotGold1
-      - IngotSilver1
-      - MaterialBananium1
-      - MaterialDiamond
+    - BluespaceCrystal
+    - NormalityCrystal
+    - SheetSteel
+    - SheetGlass1
+    - SheetRGlass
+    - SheetPlasma1
+    - SheetPGlass1
+    - SheetRPGlass1
+    - SheetPlasteel1
+    - SheetUranium1
+    - SheetUGlass1
+    - SheetRUGlass1
+    - IngotGold1
+    - IngotSilver1
+    - MaterialBananium1
+    - MaterialDiamond
 
 - type: entity
   parent: BaseLathe
@@ -1445,105 +1450,105 @@
     idleState: icon
     runningState: icon
     staticRecipes:
-      - PrizeBall
-      - PlushieMothRandom
-      - PlushieShadowkin
-      - PlushieMothMusician
-      - PlushieMothBartender
-      - PlushieBee
-      - PlushieHampter
-      - PlushieRouny
-      - PlushieLamp
-      - PlushieArachind
-      - PlushieLizard
-      - PlushieSpaceLizard
-      - PlushieSharkBlue
-      - PlushieSharkPink
-      - PlushieSharkGrey
-      - PlushieCarp
-      - PlushieMagicarp
-      - PlushieHolocarp
-      - PlushieSlime
-      - PlushieSnake
-      - ToyMouse
-      - ToyRubberDuck
-      - PlushieVox
-      - PlushieAtmosian
-      - PlushiePenguin
-      - PlushieHuman
-      - PlushieArachne
-      - PlushieGnome
-      - PlushieLoveable
-      - PlushieDeer
-      - PlushieIpc
-      - PlushieGrey
-      - PlushieRedFox
-      - PlushiePurpleFox
-      - PlushiePinkFox
-      - PlushieOrangeFox
-      - PlushieMarbleFox
-      - PlushieCrimsonFox
-      - PlushieCoffeeFox
-      - PlushieBlueFox
-      - PlushieBlackFox
-      - PlushieVulp
-      - PlushieCorgi
-      - PlushieGirlyCorgi
-      - PlushieRobotCorgi
-      - PlushieCatBlack
-      - PlushieCatGrey
-      - PlushieCatOrange
-      - PlushieCatSiames
-      - PlushieCatTabby
-      - PlushieCatTuxedo
-      - PlushieCatWhite
-      - ToyAi
-      - ToyIan
-      - BalloonNT
-      - BalloonCorgi
-      - CrayonBox
-      - PetRockCarrier
-      - PlushieXeno
-      - FoamCrossbow
-      - RevolverCapGun
-      - PonderingOrb
-      - ToyAmongPequeno
-      - FoamCutlass
-      - WhoopieCushion
-      - ToyHammer
-      - PlasticBanana
-      - WeaponWaterPistol
-      - WeaponWaterBlaster
-      - NewtonCradle
-      - SnapPopBox
-      - MrDips
-      - MrChips
-      - CrazyGlue
-      - PlushieRatvar
-      - PlushieNar
+    - PrizeBall
+    - PlushieMothRandom
+    - PlushieShadowkin
+    - PlushieMothMusician
+    - PlushieMothBartender
+    - PlushieBee
+    - PlushieHampter
+    - PlushieRouny
+    - PlushieLamp
+    - PlushieArachind
+    - PlushieLizard
+    - PlushieSpaceLizard
+    - PlushieSharkBlue
+    - PlushieSharkPink
+    - PlushieSharkGrey
+    - PlushieCarp
+    - PlushieMagicarp
+    - PlushieHolocarp
+    - PlushieSlime
+    - PlushieSnake
+    - ToyMouse
+    - ToyRubberDuck
+    - PlushieVox
+    - PlushieAtmosian
+    - PlushiePenguin
+    - PlushieHuman
+    - PlushieArachne
+    - PlushieGnome
+    - PlushieLoveable
+    - PlushieDeer
+    - PlushieIpc
+    - PlushieGrey
+    - PlushieRedFox
+    - PlushiePurpleFox
+    - PlushiePinkFox
+    - PlushieOrangeFox
+    - PlushieMarbleFox
+    - PlushieCrimsonFox
+    - PlushieCoffeeFox
+    - PlushieBlueFox
+    - PlushieBlackFox
+    - PlushieVulp
+    - PlushieCorgi
+    - PlushieGirlyCorgi
+    - PlushieRobotCorgi
+    - PlushieCatBlack
+    - PlushieCatGrey
+    - PlushieCatOrange
+    - PlushieCatSiames
+    - PlushieCatTabby
+    - PlushieCatTuxedo
+    - PlushieCatWhite
+    - ToyAi
+    - ToyIan
+    - BalloonNT
+    - BalloonCorgi
+    - CrayonBox
+    - PetRockCarrier
+    - PlushieXeno
+    - FoamCrossbow
+    - RevolverCapGun
+    - PonderingOrb
+    - ToyAmongPequeno
+    - FoamCutlass
+    - WhoopieCushion
+    - ToyHammer
+    - PlasticBanana
+    - WeaponWaterPistol
+    - WeaponWaterBlaster
+    - NewtonCradle
+    - SnapPopBox
+    - MrDips
+    - MrChips
+    - CrazyGlue
+    - PlushieRatvar
+    - PlushieNar
   - type: EmagLatheRecipes
     emagStaticRecipes:
-      - PlushieGhost
-      - PlushieRGBee
-      - PlushieRainbowCarp
-      - PlushieJester
-      - PlushieSlips
-      - PlushieTrystan
-      - PlushieAbductor
-      - PlushieAbductorAgent
-      - PlushieNuke
-      - ToyNuke
-      - FoamBlade
-      - BalloonSyn
-      - SingularityToy
-      - TeslaToy
-      - ToySword
-      - BwoinkHammer
-      - ThronglerToy
+    - PlushieGhost
+    - PlushieRGBee
+    - PlushieRainbowCarp
+    - PlushieJester
+    - PlushieSlips
+    - PlushieTrystan
+    - PlushieAbductor
+    - PlushieAbductorAgent
+    - PlushieNuke
+    - ToyNuke
+    - FoamBlade
+    - BalloonSyn
+    - SingularityToy
+    - TeslaToy
+    - ToySword
+    - BwoinkHammer
+    - ThronglerToy
   - type: MaterialStorage
     whitelist:
       tags:
-        - PrizeTicket
+      - PrizeTicket
 
 - type: entity
   id: MedicalBiofabricator
@@ -1557,20 +1562,20 @@
     layers:
     - state: limbgrower_idleoff
       map: ["enum.LatheVisualLayers.IsRunning"]
-#    - state: limbgrower_idleoff
-#      shader: unshaded
-#      map: ["enum.PowerDeviceVisualLayers.Powered"]
-#    - state: inserting
-#      map: ["enum.MaterialStorageVisualLayers.Inserting"]
-#    - state: panel
-#      map: ["enum.WiresVisualLayers.MaintenancePanel"]
+  #    - state: limbgrower_idleoff
+  #      shader: unshaded
+  #      map: ["enum.PowerDeviceVisualLayers.Powered"]
+  #    - state: inserting
+  #      map: ["enum.MaterialStorageVisualLayers.Inserting"]
+  #    - state: panel
+  #      map: ["enum.WiresVisualLayers.MaintenancePanel"]
   - type: Machine
     board: MedicalBiofabMachineBoard
   - type: MaterialStorage
     whitelist:
       tags:
-        - Sheet
-        - RawMaterial
+      - Sheet
+      - RawMaterial
   - type: Lathe
     idleState: limbgrower_idleoff
     runningState: limbgrower_idleon
@@ -1589,5 +1594,5 @@
     - SynthRightHand
   - type: EmagLatheRecipes
     emagStaticRecipes:
-      - PizzaLeftArm
-      - PizzaRightArm
+    - PizzaLeftArm
+    - PizzaRightArm
diff --git a/Resources/Prototypes/Procedural/salvage_loot.yml b/Resources/Prototypes/Procedural/salvage_loot.yml
index 7e7ddf6ff9..1b941cd1a2 100644
--- a/Resources/Prototypes/Procedural/salvage_loot.yml
+++ b/Resources/Prototypes/Procedural/salvage_loot.yml
@@ -106,6 +106,10 @@
         - proto: WeaponTeslaGun
           prob: 0.1
           cost: 2
+        - proto: ClothingEyesNightVisionGoggles
+          cost: 8
+        - proto: ClothingEyesGlassesThermal
+          cost: 8
 
 # Mob loot table
 
diff --git a/Resources/Prototypes/Recipes/Lathes/devices.yml b/Resources/Prototypes/Recipes/Lathes/devices.yml
index 2b0d6fa44f..56e1739817 100644
--- a/Resources/Prototypes/Recipes/Lathes/devices.yml
+++ b/Resources/Prototypes/Recipes/Lathes/devices.yml
@@ -234,3 +234,33 @@
     Steel: 500
     Glass: 400
     Gold: 100
+
+- type: latheRecipe
+  id: ClothingEyesNightVisionGoggles
+  result: ClothingEyesNightVisionGoggles
+  completetime: 2
+  materials:
+    Steel: 200
+    Glass: 100
+    Silver: 100
+    Gold: 100
+
+- type: latheRecipe
+  id: ClothingEyesNightVisionDiagnosticGoggles
+  result: ClothingEyesNightVisionDiagnosticGoggles
+  completetime: 2
+  materials:
+    Steel: 200
+    Glass: 100
+    Silver: 100
+    Gold: 100
+
+- type: latheRecipe
+  id: ClothingEyesThermalVisionGoggles
+  result: ClothingEyesThermalVisionGoggles
+  completetime: 2
+  materials:
+    Steel: 200
+    Glass: 100
+    Silver: 100
+    Gold: 100
diff --git a/Resources/Prototypes/Recipes/Lathes/medical.yml b/Resources/Prototypes/Recipes/Lathes/medical.yml
index ba8f596d21..29f3fed247 100644
--- a/Resources/Prototypes/Recipes/Lathes/medical.yml
+++ b/Resources/Prototypes/Recipes/Lathes/medical.yml
@@ -250,4 +250,15 @@
   completetime: 2
   materials:
     Steel: 100
-    Plastic: 100
\ No newline at end of file
+    Plastic: 100
+
+- type: latheRecipe
+  id: ClothingEyesNightVisionMedicalGoggles
+  result: ClothingEyesNightVisionMedicalGoggles
+  completetime: 7
+  materials:
+    Steel: 300
+    Glass: 300
+    Silver: 100
+    Gold: 100
+    Plasma: 200
diff --git a/Resources/Prototypes/Recipes/Lathes/security.yml b/Resources/Prototypes/Recipes/Lathes/security.yml
index 6d00f40ce2..e80ba6bbf9 100644
--- a/Resources/Prototypes/Recipes/Lathes/security.yml
+++ b/Resources/Prototypes/Recipes/Lathes/security.yml
@@ -995,4 +995,14 @@
   completetime: 2
   materials:
     Plastic: 15
-    Uranium: 10
\ No newline at end of file
+    Uranium: 10
+
+- type: latheRecipe
+  id: ClothingEyesNightVisionSecurityGoggles
+  result: ClothingEyesNightVisionSecurityGoggles
+  completetime: 5
+  materials:
+    Steel: 500
+    Glass: 300
+    Silver: 100
+    Gold: 100
diff --git a/Resources/Prototypes/Research/experimental.yml b/Resources/Prototypes/Research/experimental.yml
index 423ec0f84d..cf6493847a 100644
--- a/Resources/Prototypes/Research/experimental.yml
+++ b/Resources/Prototypes/Research/experimental.yml
@@ -167,6 +167,33 @@
     - MedicalScannerMachineCircuitboard
     - MetempsychoticMachineCircuitboard
 
+- type: technology
+  id: NightVisionTech
+  name: research-technology-night-vision
+  icon:
+    sprite: Clothing/Eyes/Goggles/nightvision.rsi
+    state: icon
+  discipline: Experimental
+  tier: 2
+  cost: 10000
+  recipeUnlocks:
+  - ClothingEyesNightVisionGoggles
+  - ClothingEyesNightVisionSecurityGoggles
+  - ClothingEyesNightVisionMedicalGoggles
+  - ClothingEyesNightVisionDiagnosticGoggles
+
+- type: technology
+  id: ThermalVisionTech
+  name: research-technology-thermal-vision
+  icon:
+    sprite: Clothing/Eyes/Goggles/thermal.rsi
+    state: icon
+  discipline: Experimental
+  tier: 2
+  cost: 10000
+  recipeUnlocks:
+  - ClothingEyesThermalVisionGoggles
+
 # Tier 3
 
 - type: technology
diff --git a/Resources/Prototypes/Shaders/shaders.yml b/Resources/Prototypes/Shaders/shaders.yml
index 108b9f778b..96c51d1a98 100644
--- a/Resources/Prototypes/Shaders/shaders.yml
+++ b/Resources/Prototypes/Shaders/shaders.yml
@@ -127,4 +127,9 @@
 - type: shader
   id: Ethereal
   kind: source
-  path: "/Textures/Shaders/ethereal.swsl"
\ No newline at end of file
+  path: "/Textures/Shaders/ethereal.swsl"
+
+- type: shader
+  id: NightVision
+  kind: source
+  path: "/Textures/Shaders/nightvision.swsl"
diff --git a/Resources/Prototypes/WhiteDream/Entities/Clothing/Cult/armor.yml b/Resources/Prototypes/WhiteDream/Entities/Clothing/Cult/armor.yml
index 04279d51d2..bdbb4bac46 100644
--- a/Resources/Prototypes/WhiteDream/Entities/Clothing/Cult/armor.yml
+++ b/Resources/Prototypes/WhiteDream/Entities/Clothing/Cult/armor.yml
@@ -113,6 +113,12 @@
     sprite: Clothing/Eyes/Misc/blindfold.rsi
   - type: FlashImmunity
   - type: EyeProtection
+  - type: NightVision
+    isActive: true
+    toggleAction: null
+    activateSound: null
+    deactivateSound: null
+    color: White
   - type: ShowHealthBars
     damageContainers:
     - Biological
@@ -120,5 +126,3 @@
   - type: ShowHealthIcons
     damageContainers:
     - Biological
-  # TODO: ADD NIGHT VISION
-
diff --git a/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/equipped-EYES-off.png b/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/equipped-EYES-off.png
new file mode 100644
index 0000000000000000000000000000000000000000..b63f30fc713a739b08ea1070559e2d3b6abf3f6d
GIT binary patch
literal 452
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R53
zr;B4q#hkaZ9K8-ZNVLvZ2+=sg&GN=-_pVLq1q&5k=x)-e5L(!M$7$j6723PGU#)W5
z#>Fc#EA)*#M@!aG&dIJ7@0$-8IDayh|E%7<CwYQ0qk=ortve#FfjjM|FMBCi)v>wZ
z^T!=~_Ut<L>$ULtZq`>HPbLKH)0w_^@&grxzQ>o$a;58P>sLRUl^pFqX^AoC_sf|-
zH%2Ayz4<4?T9&WSOzL5xS@Ej(Dhux2*`~2dY(w&WnfHDSyN;9=|6h33dcn>2wQv7Q
z)v`MDu{6kVGFS>R6sa&g@nASHkpbcsG>L}w?5&9rY>pRx?sqz^_N1~;=k%T{AC(Rm
zG2dQv;OyJEoDS0?dVgL{4!!Iyw=mT1fxtA;7qilMCvVtaXE^hK>f#Gp@*kwHG1Z^^
z*m`w?m<RushHSTkx2+FU6_qc{t~p-tMU<c$E^z-~V~XkUWDxrF1sE+1p00i_>zopr
E058M1eE<Le

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/equipped-EYES.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd6c763b334af9cd2810f9699a80005a0b30caae
GIT binary patch
literal 739
zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9F5M?jcysy3fA0|V1k
zPZ!6KiaBrZ+GYm_$~1foE-hFo5a`kE_*%guu%OULX_r;W3TJWq26^Rfd53~`kDgpQ
z*e6>v^N50mYoN%&OG`A^vbtyPxmWzq$#J@{|EG+Kx&SYsS@l)(mYpr|D^}r1WthR3
zz}C<!^59kPQl+|g-?upxuM3U+o|2ra=EGrYzx)Y<xL&NL+?{*e%g=2;bm-LY4OMS*
zcYMv*x9i{6)9K0aEf&u|-gW!&Crx{c^<e?|)0h6v7oI&oI;bJ-bI!-wa)Gj4?yFB9
z{wx3V(R|MAa=xkEhAZ;kf4A?;6@2xx@MHO|=B&DyKkeq*4}ZOSSa@cAQJ$Si-~1nM
zw;kNR{-Jli^^$Y`Tmkoge)^SU_`4(`R!=@aQ2hVp_Ol!Rf4Tbk_S}Foa@kX+@4otH
z$B)Ug;_FiOo}c)SP3BKp=W<(Hd-ZtMgFFnz3}+Y&m=BQ5$jM?lGWYazG5w_HEN*k{
zMHye^KK{7IA-j3D{CV9oF@C>qJ^9SI^ZW7tZ~s)iJ6Ozp<xfSPV(6!z4R?M&E<W4e
zy?M{MbNS^}C%;>Y?r&ODX!rS;WqlUYpY<d=1nzttONT%A|GqbiPpme4`E#c#`;Ggz
zc?-MCRw{@!&YK@y)bMLB)1n{CIO}g|+n;N#EPP)Q5mDK9_Pnm8!yRV%`xcE>+5+P9
p=YUjt?g>1!-^SjYoDg~=zRyZNy+M4FAu!c4c)I$ztaD0e0swobG`0W$

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/icon.png b/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..8bcf7105c2ba36f66beaadf560b76a9e095f924d
GIT binary patch
literal 306
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl
z_H+M9WCil21AIbU?VJO24Q(VOltLquw`VCWjnv%JYH?##2vA-%W$|wy#aR;M7yKUz
z7=ryPgg}A?9+AZi419+{nDKc2iWHz=x2KC^h=u>#37&k+iaacL-zNV2-+ei4zDJ<Q
zQ>)Sg7qp~XuIk%3Jr6%9C9(X0nn1$i0KY~V>9=9~Sid|BymH<$dA6Q|OX1S@O)G`n
z`d78ixbDkXrrP|x``z2M%J-f0R4;o?D*hsWD6~k)WQhu=vS@I^?xt5)|0Ev}`lWu9
mpGBE_+J{c}7k{*`{9<~wS!TBVg?x}(89ZJ6T-G@yGywp$pK%)i

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/inhand-left.png b/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..04fff80e4df5f5bfe6b670cf9f68368e945a073a
GIT binary patch
literal 233
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`NC)_YxB_Vj
z2_;=a8$0KKGkM1Mnl&CTboqZO@&Et-xdI8oKxxjBAirP+ARi3OnPy)B3Z{FyIEF;D
zzP)yk?|=dabHI`X|Ne{TZ+A86ev>k7-|S;TdqP_}Ufh?N@s8pCxopE;;RRtO^-kZd
z{2adSo4^0Qd9w|pXvFOLue+Qj#rWKnl$5MImaWkFymHZ|6YAYw9~Q1S!l|RxzKdax
XEW^!ZZ4OI-Rx)_H`njxgN@xNA_h(vM

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/inhand-right.png b/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..d80344136fca4bab3f4e25ae0dc66b77c694904f
GIT binary patch
literal 230
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`NC)_YxB_Vj
z2_;=a8$0KKGkM1Mnl&CTboqZO@&Et-xdI8oKxxjBAirP+ARi3OnPy)B3Z{6vIEF;D
zzP)D6cR+!M`GSD@fxrHD`gG+r6SJS1Cr`ep<l^$5x#GuK=Hj@u83yZ*mgG2ml{<T%
z_wMV}j;z<7t^Rg_=hL46?;rmTGYAR_%0}h(_gwwvVb*h7Iro;_Pw5@Db}yKYTx7V(
T+f$|jw2#5l)z4*}Q$iB}hdx=4

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/meta.json
new file mode 100644
index 0000000000..2b65c68fe8
--- /dev/null
+++ b/Resources/Textures/Clothing/Eyes/Goggles/diagnostic_nightvision.rsi/meta.json
@@ -0,0 +1,48 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from https://github.com/BlueMoon-Labs/MOLOT-BlueMoon-Station/blob/master/icons/obj/clothing/glasses.dmi",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "equipped-EYES",
+      "directions": 4,
+      "delays": [
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-EYES-off",
+      "directions": 4
+    },
+    {
+      "name": "icon"
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/equipped-EYES-off.png b/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/equipped-EYES-off.png
new file mode 100644
index 0000000000000000000000000000000000000000..b63f30fc713a739b08ea1070559e2d3b6abf3f6d
GIT binary patch
literal 452
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R53
zr;B4q#hkaZ9K8-ZNVLvZ2+=sg&GN=-_pVLq1q&5k=x)-e5L(!M$7$j6723PGU#)W5
z#>Fc#EA)*#M@!aG&dIJ7@0$-8IDayh|E%7<CwYQ0qk=ortve#FfjjM|FMBCi)v>wZ
z^T!=~_Ut<L>$ULtZq`>HPbLKH)0w_^@&grxzQ>o$a;58P>sLRUl^pFqX^AoC_sf|-
zH%2Ayz4<4?T9&WSOzL5xS@Ej(Dhux2*`~2dY(w&WnfHDSyN;9=|6h33dcn>2wQv7Q
z)v`MDu{6kVGFS>R6sa&g@nASHkpbcsG>L}w?5&9rY>pRx?sqz^_N1~;=k%T{AC(Rm
zG2dQv;OyJEoDS0?dVgL{4!!Iyw=mT1fxtA;7qilMCvVtaXE^hK>f#Gp@*kwHG1Z^^
z*m`w?m<RushHSTkx2+FU6_qc{t~p-tMU<c$E^z-~V~XkUWDxrF1sE+1p00i_>zopr
E058M1eE<Le

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/equipped-EYES.png
new file mode 100644
index 0000000000000000000000000000000000000000..a6513302b9f52f881d262e2c8652ca37e9786a72
GIT binary patch
literal 733
zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9F5M?jcysy3fA0|QgP
zr;B4q#hkZy&wGUg${hHpEOKMnoPP%*I213c2{lcd*e$lM=>ubw%a%8SRV<w|LbnuM
z-o}1H>``369S$#*7XdTVcwJeySGVP{uof;WesA9Xp4}yl?V0)a8riu=ZSN^NYA_$*
zVK8RMS-@~T|Blw9@9)lqW%T=hc^@59VJ0NybpE`i<$<T#*Si)M&owYC)!MVGz%=Ln
zOm20#yKnFB-?b;?x6%>I$>-;{t(|)JLu#4Yk?Wi4-<KtSF81cSkmoNZ&-d-nzwV2l
zuI2r>^IPQH)NcE46?QpOx&`Immzifrw`A4D{Q3IHv_|*&@uT(i|2=<vdyuC5`FziO
z-nEmL*H`DfzkB;bTDtX;bN*Zbwm*NKEBRQp@9O^8eG8QI{+;gKdaM3do!p%_K89s`
zM8oRO^mpIC^5>KG>teny<`1qntKR$e<<FcyA}q!XXBZ41{v?sHVIil$`IvnbnOwKk
z4PN|N$PqBtOzu0cPM?f*$mhx5*`L_i|BHVfUi^4pV{7}~faUwo_Wu?OQhm>VqPDJP
z-Os{8H|xtU{_OBqx*G6@tLs(G^Q)Hi8B8)^Yz>kOX$&(M6G&!ElTrBh{@>TFqHkh+
zs_ODiGFHj+JK4DI4iV^fIDcN((xG&1gGQXmL;vTeuJ1JX^5@PZ<|EDh;&}_caa{n$
r3g3kztwR5v|J?aglY?{z+-K~|lbbFZd?FT@UKu=H{an^LB{Ts5{kAk(

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/icon.png b/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..52522c080e85e6a1a893ba5bbd642663d48252d5
GIT binary patch
literal 306
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl
z_H+M9WCil21AIbU?VJO24Q(VOltLqu6?*rG<*v6}zd!KWS)hE+0@uAjinAohFZe$c
zFa-No2!R9(JR*x382Ao@Fyrz36)8Z$Zci7-5DWje6Fm8t6?s_hzD@l3zx#69e2+kp
zr&gs0E@(-&T-CR6dLDjIN@Do~HGzc30e+1#(r?4|v3_|Nc;&oh@@zc^m%^p*n^p?D
z^{;B3aov}(OttxW_q(@imG3+0sb2P)RQyH$P-u~o$r2S#Wzpb--A%8q{z*O{^h^CH
mKZ`Q=v=5!`FaBs>`Ni~Vv&?M!3;7_oGI+ZBxvX<aXaWEt?{S|1

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/inhand-left.png b/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..bccfe98d09b26adf2d2164d62bdacb7c4c5a580a
GIT binary patch
literal 233
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`NC)_YxB_Vj
z2_;=a8$0I!m8JJ&``<WUe3J10`~Uy{Tc*{021;|51o;Is0Qq2G&NTZ9P%z!o#W5tJ
z_3gETd<PUbm;;t9`1fBtf4i$m_nVYy`(_^#+7sH+@#4PBjCTz8&t)6-3NHvNsdxHr
z<>&Bq-~9de&6{l)MI&a{f8FIQDaPlnq@-l!v22CT=aq{#olx)g`mk`t5l$Vg_FW8n
XWEpNQYjaovw35No)z4*}Q$iB}O9Nb-

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/inhand-right.png b/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..f9c17318b4ee395b57eb4efab8c1756143523406
GIT binary patch
literal 230
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`NC)_YxB_Vj
z2_;=a8$0I!m8JJ&``<WUe3J10`~Uy{Tc*{021;|51o;Is0Qq2G&NTZ9P%y>Q#W5tJ
z_3brlz5@z8%ohaI5B&AN)2A!1nV9|5JbCg(B^Q_f%oRV@G8f0K%`jMhv?RyjtK8Z9
zymw!(c4WQwZ1uMbJfHpqc>nl!m_blbP&O*Jzvt>V53`=z%DK1XeoF7KwR^#I<RZgO
T-kvfQpnVLUu6{1-oD!M<)C*hB

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/meta.json
new file mode 100644
index 0000000000..2b65c68fe8
--- /dev/null
+++ b/Resources/Textures/Clothing/Eyes/Goggles/medical_nightvision.rsi/meta.json
@@ -0,0 +1,48 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from https://github.com/BlueMoon-Labs/MOLOT-BlueMoon-Station/blob/master/icons/obj/clothing/glasses.dmi",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "equipped-EYES",
+      "directions": 4,
+      "delays": [
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-EYES-off",
+      "directions": 4
+    },
+    {
+      "name": "icon"
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/equipped-EYES-off.png b/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/equipped-EYES-off.png
new file mode 100644
index 0000000000000000000000000000000000000000..5aaa7e580ce25f46a4b1cab0117891eb88c39378
GIT binary patch
literal 477
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R5f
zr;B4q#hkaZHhLWn5NZ1_Z52^aP%t^^nP1<fP^(>C55(qv;yP#7H2K0>|A0A0-$kw5
z6(>6%Pgx<iyyJn=ox^{NPyAev{o_YbasI=33Q7{jlF<!kUobnkEUMeTbMKkS_5K_G
zEskfr$Y>XLE_MH0&uDSA^2;w6CjS(dyMFz}EUxa^+^kEtwA@JEP`!Klx|IbtQZ3@*
z5@)S%nsj@A$JhBsxO_f`YMd5g_+WDX#%~@If5u~W1}lOWWNV#0zSJ?Bb%S5y!8Ht%
z^X0jgJ8*cK|Fu8z>$kn*HU??_17Zn}8E-J<*f2yl^s*;#Z}`ZN!)PYgpnKpL^9I%%
z6%0s<3^UFs&){3oxRc@5XO3q~Up{lpKfhiJ$jocIwQIsZsdpPr7yJrv=bXXKz+nHG
zqg>iDa?f$jjC1TumaXOP{I*>xVgFoCg9WcYUXhurTPl}Q$oeHe{_y=LTmjX;11wnA
iBp0z}JR-(1pLx$LUT)lx{@o84UkskEelF{r5}E*W3du_V

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/equipped-EYES.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc4d9e775b88d077723af637c09a002db51a84a7
GIT binary patch
literal 410
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|TRv
zr;B4q#hkad7J4}+%CvoSkGx>ER!MJtRLSXk4T)z~B*Y5rnRRfJd4g4f^o^X;&51@C
zg1nC|>ieYq`}g$ee>?Gl2Y>bz^EL04os`ZnNu0~T?&a3<{?ocGpM(Rd8>hbvy#2C%
zb8*43r#~3Cu3|iOw!B^Y-ZS3ji-!BxGkAqEPnoQ5{(tL@XTNIZpX3b+Wq$K5tzLfb
z^~%diVK3Y_*zg)SuMB87|D0{>AqKl?;cuV4UJxYF@aX0ALk!>Aw0B<C|2bXZq%i{?
zbjbCM;1WiqNz5Jhlut0O`Ofiv`*$9<<yWg&EE~ScEiBnskrY&EYuWI>y5;aI+a{R<
zX@b=(kqt$^1nZBVW^!2@sKU6&Z@&tsz)sgmEFE(mc`&)8F@U^^iM}(RDDYh>5>Rvo
P7}yM+u6{1-oD!M<%d4uQ

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/icon.png b/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..e0aaa8ae9aa3c281302ad194b0a2b7b1a30f4d21
GIT binary patch
literal 298
zcmV+_0oDGAP)<h;3K|Lk000e1NJLTq001BW001Be0{{R3M5Kzw0000#P)t-sz`(#b
zI4Ea@PfTh=NLVoM#U1OLAD3x4l8#V|Q564XX8$WI_uyhkC?Nj;0BA@kcsLOMTU*rt
z0KotN#eNj*0K2vT0004WQchC<K<3zH0001)Nkl<ZIE~ei%MODu3<OQVYbeg6DgXbi
zP0}K9aEL??Rrip~jJ;Nf{xrkT5pH8g7^km=-VM`bfdMd)%!@SmeO;jtg|oO8?maln
z63qpbd(TidEAXg1u`q(Up>qE$6}EuNQ7bkzjg&GExgwG!?EerK=fwVrJ$Az(jfTU#
wGaKHE%iEaGi#ILUo+rw;(+U14XZUA%0jaqLSXS!5lK=n!07*qoM6N<$f=#%29{>OV

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/meta.json
new file mode 100644
index 0000000000..ad770fb0f8
--- /dev/null
+++ b/Resources/Textures/Clothing/Eyes/Goggles/monocle_thermal.rsi/meta.json
@@ -0,0 +1,22 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from https://github.com/BlueMoon-Labs/MOLOT-BlueMoon-Station/blob/master/icons/obj/clothing/glasses.dmi",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "equipped-EYES",
+      "directions": 4
+    },
+    {
+      "name": "equipped-EYES-off",
+      "directions": 4
+    },
+    {
+      "name": "icon"
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/equipped-EYES-off.png b/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/equipped-EYES-off.png
new file mode 100644
index 0000000000000000000000000000000000000000..b63f30fc713a739b08ea1070559e2d3b6abf3f6d
GIT binary patch
literal 452
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R53
zr;B4q#hkaZ9K8-ZNVLvZ2+=sg&GN=-_pVLq1q&5k=x)-e5L(!M$7$j6723PGU#)W5
z#>Fc#EA)*#M@!aG&dIJ7@0$-8IDayh|E%7<CwYQ0qk=ortve#FfjjM|FMBCi)v>wZ
z^T!=~_Ut<L>$ULtZq`>HPbLKH)0w_^@&grxzQ>o$a;58P>sLRUl^pFqX^AoC_sf|-
zH%2Ayz4<4?T9&WSOzL5xS@Ej(Dhux2*`~2dY(w&WnfHDSyN;9=|6h33dcn>2wQv7Q
z)v`MDu{6kVGFS>R6sa&g@nASHkpbcsG>L}w?5&9rY>pRx?sqz^_N1~;=k%T{AC(Rm
zG2dQv;OyJEoDS0?dVgL{4!!Iyw=mT1fxtA;7qilMCvVtaXE^hK>f#Gp@*kwHG1Z^^
z*m`w?m<RushHSTkx2+FU6_qc{t~p-tMU<c$E^z-~V~XkUWDxrF1sE+1p00i_>zopr
E058M1eE<Le

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/equipped-EYES.png
new file mode 100644
index 0000000000000000000000000000000000000000..199c44122bb0619dec7fbece5484729d8e10d3f2
GIT binary patch
literal 719
zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9F5M?jcysy3fA0|Qf|
zr;B4q#hkZy?Y*M|B^o}O2W?P_@Y*i4qS)*|&(yNl-wTAj*u3pMJDmk~ecim|#=#d?
ztfNmvEn&Q<bFWHC{7BNrmg>(56?F=2Egz13RyoeI)BL=X2J-<P24jYtWejuumhY*L
z4HQ{BL%6DL?k47(yqqbw<EJN8zD}*V|3`LhzjvTqod0@zOWWKU!Ao<>)z>E(+4Mi&
z``V*l_3ymve|Dv^z9`%Mw14qp2|nd*k7}x7qyA(GUV8htZvRHt70;F*_3u~oEMBed
zc=@ya`}foLpF8*H{L!QK+xJGq_L{$b{qgAoh3vYphFATszgRt0$cz7$X)W>QUfjM)
zHn+*EeunSf9vxt6U-fzB{M|eH4KM$1*!^2~<M&ISUq9KcFoQ9HtwE9@je&HAu1`bR
z?$~u}*Cx&vom=|PiN)hMTa2&T$A7oIL~h^t!*3t&eo<@FyV;@(I?o?}zM_x6!lU#I
zgQ>mj_6geB4wJioOZ>O~p_I#bo`3qqpU10zeil#S_HtVs`1;xNlV{^+F!)a;-)*Vv
z9_pv%`j1~e@5I(HFMj*XIL4O_ET3xre)(gS${z7^i_rAFr(ZtZ!tp)7e)nc!-+71a
zWm^nyJbiXu*V^INqLwYJBK$dwzVi>;*CsMs?$5i)_+t9slT10*<v;Z}NDr)fMxjOD
V|NVJkB?L^N44$rjF6*2UngFrmDX0Jd

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/icon.png b/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..bf770f70f8969ba008b8e4d2b2687cd602520849
GIT binary patch
literal 218
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv=>VS)*8>L**f|I28rn!mD1}BQ
zi!9KSs<MkbXu9N?TksQmL!dIok|4ie28U-i(tw;?PZ!4!jfu$#5?Kxb0RfCN^Oxl0
z<aDSU%3)CAd03;ipvu*eHEoBGpt!oSxVSsp42H#vCTv)|sAIxJMxXYKMP4gAH%~IW
z)6rFS*zCK)4kor`9Y)HE{VK{WOBZ#Xa&tR%>clyt1T!<U1c^rs3`h9*yo_ewH3wSE
N;OXk;vd$@?2>`qZMy~(>

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/inhand-left.png b/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..995b37471b38d3dbcef1e91888c4ed58239b2d29
GIT binary patch
literal 385
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVD#{GaSW+oe0ytS)}a8AV;?79
zTDrUS+Q#IAP0lZsthSWoxw9WU{v!DYhg1B5>~=oQcTG*fg=?A>V|Tglb68?=^-eYO
z#s71CKGf`de*CKH@t#%&CJu!LG~z%Yr^~+Gxjp%tUSD5r^X>EFvzGg-|4-4(F^q^Z
znq&F=?YHVp)rX(%y813<x&HodrPFWu&x+XibJNUK;eDT`tp2kpa_ZI0$x&9Ee}9;1
zcQ3HIs_m{F@;T1GVaoH%o>!_Xwq1POdh~sI^pF2$AHG+EHSOm8{6o=W#kb{d*H*u;
zS^a$a*}YN)E5Bwqi(qjds&fl0m=50K3wI1TBe%n+zhXZBibaLCi>F;y-d9lL*MH>|
rOUn$om3QkIfC6>yPr#m?k;`yJy1Mbjqo4nPLCfIj>gTe~DWM4fU$Cme

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/inhand-right.png b/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3efa67f837fbc9cc5851d2ec09ce705d1bc7652
GIT binary patch
literal 410
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU`+IMaSW+oe0ytS)}a82qaV*-
zI(paX^^L%Q0*zQNYmK?LH#R>={vl!4^nkmhv>;%Yc+?A(J}Zr~mvWYk+>A$OyLd19
z_g={GyV~<VJbF9Rcvu7+7#Pusb6yJ`WdFWV!D;e*x#`x_->0qbm+$>=7ys&Nlh=Q<
zJ!dO^ygOUHQG3Fv|Ldli?To*f`uzN=uk8ZK*JtUR*PLIZwZ3S#ynd*fZk_a9R-vmW
zsw=~TEKR3G|E%SZ_IKFwA|qhSyU$x~P2=DG{(Shi#ZG}pxv9aGQ=@<0?f6!7|K*OY
zQ`GdIZ7#TX)%Rz{DfjNVPVE`;cFGM5OdJaMh-%K9T5Fl-U7qDhM|P%(6`OryKf<{%
z{5<>ZPQmAGm2;F^RICj@-Ef>4WXl*eqeQ*!+LOX1|M&}1Z*)FXu}}gTEi?as)UL{^
V#;<v%vw>mG;OXk;vd$@?2>@%NsSE%B

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/meta.json
new file mode 100644
index 0000000000..987b20b9af
--- /dev/null
+++ b/Resources/Textures/Clothing/Eyes/Goggles/nightvision.rsi/meta.json
@@ -0,0 +1,48 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "equipped-EYES",
+      "directions": 4,
+      "delays": [
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-EYES-off",
+      "directions": 4
+    },
+    {
+      "name": "icon"
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/equipped-EYES-off.png b/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/equipped-EYES-off.png
new file mode 100644
index 0000000000000000000000000000000000000000..b63f30fc713a739b08ea1070559e2d3b6abf3f6d
GIT binary patch
literal 452
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R53
zr;B4q#hkaZ9K8-ZNVLvZ2+=sg&GN=-_pVLq1q&5k=x)-e5L(!M$7$j6723PGU#)W5
z#>Fc#EA)*#M@!aG&dIJ7@0$-8IDayh|E%7<CwYQ0qk=ortve#FfjjM|FMBCi)v>wZ
z^T!=~_Ut<L>$ULtZq`>HPbLKH)0w_^@&grxzQ>o$a;58P>sLRUl^pFqX^AoC_sf|-
zH%2Ayz4<4?T9&WSOzL5xS@Ej(Dhux2*`~2dY(w&WnfHDSyN;9=|6h33dcn>2wQv7Q
z)v`MDu{6kVGFS>R6sa&g@nASHkpbcsG>L}w?5&9rY>pRx?sqz^_N1~;=k%T{AC(Rm
zG2dQv;OyJEoDS0?dVgL{4!!Iyw=mT1fxtA;7qilMCvVtaXE^hK>f#Gp@*kwHG1Z^^
z*m`w?m<RushHSTkx2+FU6_qc{t~p-tMU<c$E^z-~V~XkUWDxrF1sE+1p00i_>zopr
E058M1eE<Le

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/equipped-EYES.png
new file mode 100644
index 0000000000000000000000000000000000000000..0e156402bc5eff7cf1ce82fc23b110afd3b4de8b
GIT binary patch
literal 704
zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9F5M?jcysy3fA0|Qf$
zr;B4q#hkZy9lb*W8Qec=?<f#Xl<0Nre(5N!Iibbu;xhdU?r*uz9Lf+j;b@(m;3RRP
zQ7P9;O0nwh?-!kcv#sxb_v3xeo~U*9{=1VUALnhBYcXOt!(hOCU>etl7au2E?VTg*
ze>mZH*ynBOi<f6FRR2=vd6V(oJG(XC{g*4=;ZLmC!tr}?=8futt(CuDH$R^%@3cAo
z=-<LS_Wi#<Cf|&HpTB?08iwYBZ-0IMqtbHH?enikZ?bLvNI!hK-9OPH-sJuKv-ir%
zIK+QH?o~UGB=CLvqkr8y;=gXLul=2NW6!p)w}1QD)p5M<zu$W2?;3`;&HSt9{yO#j
z?2lg+x^)hvR(}?sOnm<TSKZC~y}#M*zpwuH?eY3W{X4H*Z#Z2a`RMYzd-^BeHzlw&
zNHU}`%wQy)vCW9_($v%CW$zNdbL#BgFT{B3^s&o(nU1`Se-mC<KjnM+=J)&>wY7il
zzuUfh`upeu-;V$Mee*l}lzn#luGCr0NffO&X8b<A;>^?^`Wi1k8LvP6cPi(H{m>BR
zVK9aSHSvrMZx~*tf8TFe(;D0D`F{E|*#~b<+br?kvUrvSOV$1@Zy4U5f8~E^vf7`Q
zQ9t$gm({Lg$^wbL{BT*=Jm5PQkN?fTmo_nf`RKy=|5IINoj42WE|71vlDK?Fdg*##
Pl4S67^>bP0l+XkKzim56

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/icon.png b/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..80ae69d53bada105ba124e8045888bb0cc92f94b
GIT binary patch
literal 505
zcmV<V0S5kwP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px$vq?ljR9J=Wls`x#K@^8SgJ6*&<Ud&s16pWt9CDytB+FfM-C>m?l@?Zl_Ff8e
zy@BhkEG+E=K@y0akb^`a5scXEs=Myispg7vf*Z5DL5nMHzG|5_^WN|G-p+tRp-}wq
zOa%oSjfQWmQmu(`>#k$-YyYPwZ?RbP%`+V&U>v2=x=80V04&q+6*o@Ey9Ja=>jDT(
zEcaEaHL>?&J8<trBiP#674byM6O#@{V=tY{Zgqa2`_>5+P^s2LHk0(Mce_0-(;%JG
zSX^9qb?)Ku3F&-mXIH#g!0MOp!gXw<L-~Du)uy29JUl+}GM>#Ohig)xWg6Vy_kHU`
zf&|Fq<#vnZ%Nyc}6s}`a&~-M?jw!cWSf)WXlO&r-(yZ5U9ea4*G7XN74gyVv{)ClI
zll=Su9fxlngK{KBJdq+lH{j$}qoA*_d3H=+MCpE*9Xba>i-&dqpf92T-1TQTnfja9
zb!;}GUpduc0OaQe^dd3Oxk-vcNCzy_;PBIDXt(G^VqAQjC;dEM>9kp|vzA)|4bR*s
vCG-}Idw8TfdEZAFbszK+DijKZ;-B*e%6-anRB9Xj00000NkvXXu0mjf^S9-c

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/inhand-left.png b/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..02b00b1591eea9b0c895e3a2a40ac644df2afe07
GIT binary patch
literal 233
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`NC)_YxB_Vj
z2_;=a8$0KKVsYJBqH=r0gl}8${Qv)7Ep<;nP@1zO$S;@y$Oi*+rrB43g6W<vjv*1P
zZ?7HXJD|Y99I#};zyIR-+g(k%-=s|2H~W~-p3s(#7x!gmykoe3F59qIctKc6z0-Fq
zKZmdT=I_66-fY7t8Zo>6>n>+WF+O)CB_%75Wh-<(uUxe0gnGBvhlMMSaO!Ba?_$^^
W%W!j9o5K>Il?<M)elF{r5}E*AzE|P^

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/inhand-right.png b/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..6ba4b3e64ee173d9d8cc52d6da70949729f3c778
GIT binary patch
literal 309
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9
z?C1WI$O`032l#}z+BpZz5|z_6v?&(Xm5@-{BPRU+|Nq+-JV5!=^5?$*DbA80zhIys
z7%&9;R|tUw3p^r=85sBugD~Uq{1quc!9GtH$B+p3x6`bJ4k&Q23i^Ker`{*=*xdNh
z63>s@0=RB0mld&NVq{@r5#X>F5||mY)-a@ae%B4Fb6>g2rezoG<15a3zWAYuyXUlK
z=E(RtTqmNtf>-*eTYvqX|LTC>J8c061qX&k29ODp7u>Zi`SSPfyM@Ua`Q`kw$>p1?
oU(9$^Hht<@`ST7RA_Wey_TQ^(H(6x73g|KhPgg&ebxsLQ0D|>x_W%F@

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/meta.json
new file mode 100644
index 0000000000..2b65c68fe8
--- /dev/null
+++ b/Resources/Textures/Clothing/Eyes/Goggles/security_nightvision.rsi/meta.json
@@ -0,0 +1,48 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from https://github.com/BlueMoon-Labs/MOLOT-BlueMoon-Station/blob/master/icons/obj/clothing/glasses.dmi",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "equipped-EYES",
+      "directions": 4,
+      "delays": [
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ],
+        [
+          0.1,
+          0.1
+        ]
+      ]
+    },
+    {
+      "name": "equipped-EYES-off",
+      "directions": 4
+    },
+    {
+      "name": "icon"
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/equipped-EYES.png
new file mode 100644
index 0000000000000000000000000000000000000000..9bef0a8c05f0ca0e150da1e9b81aebb13b8dadd7
GIT binary patch
literal 524
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=1yvytB`&GO$wiq3C7Jno3=9=>
zRF7M8H5dr69<ZwJYXA0V{arVuNlxzt3QQU8C+Jkwaxb4Pbl74iYgySBk5eD_9eA;N
z)*0z=-h>j}nF@vcztmTUGcLZM@bZhhV_L6f^To+GC)ukuUkvCh+_+)$V*aYbQomVd
z3Im<M81Cuf7*a9k?X107hXQ2W{|lP8+chbLd=m5e%}~cPQ{<P5>?al0?L61)98Q1L
z)#F>sdhq7KjZ2(YT=?OrFX4Ca{>(`+c|}Fb9R5u#KDTbBl&-^KhAj-eOf7jQHtF#1
z{C9t4d)|k8(ccUI#O#}Q&3d|_)#1}Q)9TlSZM*xH?^>P|Z}zsRYx2E|CRDSr8yMfN
zS#$PGj%DfLb4$XH>{x5(@Z$8}R*(CP;eAXOm`u1FxG!ihz-%B|faSlOKEG4N`?p{J
z=Kd?*S5b7>yJPO6-xqG5SG%+QJzJs7|0w@SOK$ya_{4n4<g9u8(T_z@Z%@w_ZTxP`
i>0aY>v4(UjYnXdl9N2msQpJGL%i!ti=d#Wzp$Py!<<~I)

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/icon.png b/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..3d5f8ef9b65ccfe2ed64fbc2d10c725c5fad51d2
GIT binary patch
literal 510
zcmV<a0RjGrP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800009a7bBm000ie
z000ie0hKEb8vp<Sut`KgRCt_YIdI?r!$1NSh5-hn4j6U7r~`(d1B!VZ{`Y=4z({ik
z)HP4|k1m#Y_$0$GZ5xLBS0n!`?pjWiBS>~YL`2emQAsH<`}Ol@aPemfRt!=?oD8Bs
z_Iz7&h65FI{vYZ{A?OH_900N$L{IK-!7zBCTjc*0Kwsw;*8IP9^%BFvci$Q2H-Gux
zR9k@85kxs)>deJpi)|epQTQ;>tT~TiYH$(*15|v)ig}D6#~!fX$nb)p0I%5u9RQ2#
z_wU}|RFn3~A4t9htI^O<XMi~(6c`$l?eLqA*8w2Q4|e*3+277zV)%3B3YdNU)J+E6
ztY8K%Lp``02zahwV0iiJEj*ndrxCIo0E)|R=jGuR!z>2@kk}_Q@h%{p%Af$|gDeMy
z0!0o0fy>j@!r35SKRIv_%m&diTpTEBLGldK&Vt#*SWeIZAVX4t@pvN37|h?^vy>s{
zBOhFT3d1J`R|kCt784yX-vVekwj4sX13&;|pfWW3iAriPteA<g0Gus1-e(X!^%Jg^
zfkZ%5HpCU2#0E3P4xl9%b-<_tMjbHffKdkk0DP~m!U$LZ-v9sr07*qoM6N<$f;E)T
A`v3p{

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/inhand-left.png b/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/inhand-left.png
new file mode 100644
index 0000000000000000000000000000000000000000..bf67e35d4024bc03b3f3ed80f2cd847027bb8476
GIT binary patch
literal 327
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVC3_3aSW-L^Y)g#UrT~O+sA{4
z+?*XV*W|2Ov$Ls0WVXX@^A8&L4oK-Y$Tce82$b;V+GJ*y6Q}g|n5@qUoBb^<O_ekI
z>v@xb1_FVDPUrWmc)9n>XTSEY{<m-Iw%qgQ^t+O(cKzD2{&4@>`*wGJ@BP4Y`g2W{
z@4IJdS4$$NUAC-T6)(0v=IQU!-9o0C?{~LXu3q)Z-*<K1$q8G<-v46pxL)cRd;Rmi
zcQN<BfBv^pJjv3pbd~s1&Fj0vBUP`|-M^bCp>x{E`|_1p%PfD!?BaNAaVzNkM_opU
zgBm^@;?~~-AyO{a$J#D)zw?~=-)Xhw?t3cy`g2}!MkH6I6yIl9=FY(2cjgU8R89XJ
TA;as_K-xWB{an^LB{Ts51B{c1

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/inhand-right.png b/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/inhand-right.png
new file mode 100644
index 0000000000000000000000000000000000000000..4ede078291d212cabdf7a4d5731153a85f0963c1
GIT binary patch
literal 325
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVC3<1aSW-L^Y)gZUvq-Qv5(vN
zVoi8@dM9^JHV&WAyO49uUdR4NymLM>y%4l$l5Q?cQFwc)^;u?9W)7>Pko}kc-ZOqE
zoOia1sNe;f2?Rgl(_(WE8?3oLJ^$Ojn>Szm+*<rMzk1L9wc_E$)i>gzr=`xV)W7BD
z7WgIbUuIddqrert>EU)yL*kx>{X1yh{dh-R<ULuw!o4-lmP=2rlgoYWU*=Hk7%0-N
zuIV``V&3y}`SpQ*Peq@G^IO0Adh=#bR7~j9si~R!-q*j5E$ZDD>sxpJvySiOlcf;n
zfXIf6JpYn!l?xpXT`Q~<FIg&-yy}-<(w~*G3CwDSF<&2-Pxs_uIN&n#rrcqVt~vcC
Q4cQ=Fp00i_>zopr06im!bN~PV

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/meta.json
new file mode 100644
index 0000000000..205508acfa
--- /dev/null
+++ b/Resources/Textures/Clothing/Eyes/Goggles/thermal.rsi/meta.json
@@ -0,0 +1,26 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "icon"
+    },
+    {
+      "name": "equipped-EYES",
+      "directions": 4
+    },
+    {
+      "name": "inhand-left",
+      "directions": 4
+    },
+    {
+      "name": "inhand-right",
+      "directions": 4
+    }
+  ]
+}
diff --git a/Resources/Textures/Shaders/nightvision.swsl b/Resources/Textures/Shaders/nightvision.swsl
new file mode 100644
index 0000000000..8a3e7706ad
--- /dev/null
+++ b/Resources/Textures/Shaders/nightvision.swsl
@@ -0,0 +1,38 @@
+light_mode unshaded;
+
+uniform sampler2D SCREEN_TEXTURE;
+uniform highp vec3 tint; // Colour of the tint
+uniform highp float luminance_threshold; // number between 0 and 1
+uniform highp float noise_amount; // number between 0 and 1
+
+lowp float rand (lowp vec2 n) {
+  return 0.5 + 0.5 * fract (sin (dot (n.xy, vec2 (12.9898, 78.233)))* 43758.5453);
+}
+
+void fragment() {
+
+    highp vec4 color = zTextureSpec(SCREEN_TEXTURE, FRAGCOORD.xy * SCREEN_PIXEL_SIZE);
+
+    // convert color to grayscale using luminance
+    highp float grey = dot(color.rgb, vec3(0.298, 0.5882, 0.1137));
+
+    // calculate local threshold
+    highp float threshold = grey * luminance_threshold;
+
+    // amplify low luminance parts
+    if (grey < threshold) {
+        grey += (threshold - grey) * 0.5;
+        if (grey > 1.0) {
+            grey = 1.0;
+        }
+    }
+
+    // apply night vision color tint
+    color.rgb = mix(color.rgb, tint, grey);
+
+    // add some noise for realism
+    lowp float noise = rand(FRAGCOORD.xy + TIME) * noise_amount / 10.0;
+    color.rgb += noise;
+
+    COLOR = color;
+}

From 83fa9239d8b6a244e1c5e974cd40351d2435f419 Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Fri, 10 Jan 2025 04:42:01 +0000
Subject: [PATCH 29/38] Automatic Changelog Update (#1462)

---
 Resources/Changelog/Changelog.yml | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 40eee58c48..7f0e09adcb 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9500,3 +9500,20 @@ Entries:
   id: 6656
   time: '2025-01-10T02:27:50.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1471
+- author: Spatison
+  changes:
+    - type: Add
+      message: Added night vision goggle
+    - type: Add
+      message: Added thermal vision goggle
+    - type: Add
+      message: Deathsquad helmet now grants night and thermal vision.
+    - type: Add
+      message: Ninja visor now grants night vision.
+    - type: Tweak
+      message: Some animals have gained night vision.
+    - type: Tweak
+      message: Xenos have gained night vision.
+  id: 6657
+  time: '2025-01-10T04:41:32.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1462

From b38b7f992504496a125ba2f96fb1fe6bf4f09f1c Mon Sep 17 00:00:00 2001
From: VMSolidus <evilexecutive@gmail.com>
Date: Fri, 10 Jan 2025 00:14:46 -0500
Subject: [PATCH 30/38] CyberEyes Night Vision And Thermal Vision Modules
 (#1477)

# Description

Thanks to @Spatison for the Night Vision PR.
This PR adds traits for CyberEyes users that enables the use of either
the Night Vision ability, or the Thermal Vision ability. The former lets
you see in the dark (It can be toggled on and off at will). The latter
lets you see living creatures through walls (for brief pulses). The
latter is on the quite expensive side of things (12 trait points in
total if you include the requirement that you first have CyberEyes).

# TODO

<details><summary><h1>Media</h1></summary>
<p>


![image](https://github.com/user-attachments/assets/465edf95-c0e6-4695-b1f1-e9916ccf10f0)

Sorry the pulse for thermographic was too short for me to be able to
screenshot it. But it does work!

</p>
</details>

# Changelog

:cl:
- add: Added 2 new traits related to CyberEyes. Light Amplification
Module, and Thermographic Scanner Module.
---
 Resources/Locale/en-US/traits/misc.ftl   |  2 ++
 Resources/Locale/en-US/traits/traits.ftl |  9 ++++++
 Resources/Prototypes/Traits/physical.yml | 41 ++++++++++++++++++++++++
 3 files changed, 52 insertions(+)

diff --git a/Resources/Locale/en-US/traits/misc.ftl b/Resources/Locale/en-US/traits/misc.ftl
index 9a17c3afc4..13eae98512 100644
--- a/Resources/Locale/en-US/traits/misc.ftl
+++ b/Resources/Locale/en-US/traits/misc.ftl
@@ -1,3 +1,5 @@
 examine-cybereyes-message = {CAPITALIZE(POSS-ADJ($entity))} eyes shine with a faint inner light.
 examine-dermal-armor-message = {CAPITALIZE(POSS-ADJ($entity))} skin seems to be made of a sturdy, yet flexible plastic.
 examine-bionic-arm-message = {CAPITALIZE(POSS-ADJ($entity))} limbs emit an ever present faint chirp of servomotors.
+examine-thermal-vision-message = {CAPITALIZE(POSS-ADJ($entity))} eyes periodically pulse with a menacing red glare.
+
diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl
index 37de6238d7..92fa6f74a2 100644
--- a/Resources/Locale/en-US/traits/traits.ftl
+++ b/Resources/Locale/en-US/traits/traits.ftl
@@ -500,3 +500,12 @@ trait-name-BrittleBoneDisease = Osteogenesis Imperfecta
 trait-description-BrittleBoneDisease =
     Also known as "brittle bone disease", people with this genetic disorder have bones that are easily broken,
     often simply by moving. This trait reduces your threshold for critical injury by 50 points.
+
+trait-name-LightAmplification = CyberEyes Module: Light Amplification
+trait-description-LightAmplification =
+    Your CyberEyes have been enhanced with a light amplifier module, enabling the user to toggle between standard sight and "Night Vision" mode.
+
+trait-name-ThermographicVision = CyberEyes Module: Thermographic Scanner
+trait-description-ThermographicVision =
+    Your CyberEyes have been enhanced with a Thermographic Scanner. When enabled, it captures a snapshot of the user's surroundings, while highlighting all
+    biological life forms. It can even detect individuals through the walls of a station.
diff --git a/Resources/Prototypes/Traits/physical.yml b/Resources/Prototypes/Traits/physical.yml
index 3f3d460f99..81ae6715d7 100644
--- a/Resources/Prototypes/Traits/physical.yml
+++ b/Resources/Prototypes/Traits/physical.yml
@@ -765,3 +765,44 @@
       components:
         - type: CritModifier
           critThresholdModifier: -50
+
+- type: trait
+  id: LightAmplification
+  category: Physical
+  points: -4
+  requirements:
+    - !type:CharacterJobRequirement
+      inverted: true
+      jobs:
+        - Prisoner # Bionics should be "Confiscated" from long term prisoners.
+    - !type:CharacterTraitRequirement
+      traits:
+        - CyberEyes
+  functions:
+    - !type:TraitAddComponent
+      components:
+        - type: NightVision
+
+- type: trait
+  id: ThermographicVision
+  category: Physical
+  points: -8
+  requirements:
+    - !type:CharacterJobRequirement
+      inverted: true
+      jobs:
+        - Prisoner # Bionics should be "Confiscated" from long term prisoners.
+    - !type:CharacterTraitRequirement
+      traits:
+        - CyberEyes
+  functions:
+    - !type:TraitAddComponent
+      components:
+        - type: ThermalVision
+          pulseTime: 2
+          toggleAction: PulseThermalVision
+    - !type:TraitPushDescription
+      descriptionExtensions:
+        - description: examine-thermal-vision-message
+          fontSize: 12
+          requireDetailRange: true

From 7f32e00f375a4f58b9c36aa97b1d9faab888671b Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Fri, 10 Jan 2025 05:15:12 +0000
Subject: [PATCH 31/38] Automatic Changelog Update (#1477)

---
 Resources/Changelog/Changelog.yml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 7f0e09adcb..357f9b38a7 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9517,3 +9517,12 @@ Entries:
   id: 6657
   time: '2025-01-10T04:41:32.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1462
+- author: VMSolidus
+  changes:
+    - type: Add
+      message: >-
+        Added 2 new traits related to CyberEyes. Light Amplification Module, and
+        Thermographic Scanner Module. 
+  id: 6658
+  time: '2025-01-10T05:14:46.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1477

From df8ffb0605f431b71045862acc159f93f08470b1 Mon Sep 17 00:00:00 2001
From: VMSolidus <evilexecutive@gmail.com>
Date: Fri, 10 Jan 2025 19:13:27 -0500
Subject: [PATCH 32/38] Assay Psionic Power (#1450)

# Description

This PR adds a new psionic power to the game, called Assay. Assay is a
more advanced information gathering tool that is available roundstart to
the Mantis. It essentially acts as the first ingame method for
characters to discover the underlying math behind Psionics, displaying
to them the target's casting stats, potentia, and metapsionic feedback
messages. These messages don't tell the caster directly which powers a
target has, instead providing hints as to what those powers might be.

<details><summary><h1>Media</h1></summary>
<p>


![image](https://github.com/user-attachments/assets/d729e373-0406-4b0b-a47c-ae7c853e72b3)


![image](https://github.com/user-attachments/assets/08457e25-56c3-4ff9-856f-ce917bd40d5a)

</p>
</details>

# Changelog

:cl:
- add: Added Assay as a new psi-power, which is available roundstart to
the Psionic Mantis. Assay allows the caster to obtain more direct
information about the statistics of a specific Psion, as well as vague
hints as to what their powers may be, if any.

---------

Signed-off-by: VMSolidus <evilexecutive@gmail.com>
Co-authored-by: Skubman <ba.fallaria@gmail.com>
Co-authored-by: flyingkarii <123355664+flyingkarii@users.noreply.github.com>
Co-authored-by: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com>
Co-authored-by: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
---
 .../Psionics/Abilities/AssayPowerSystem.cs    | 140 ++++++++++++++++++
 .../Actions/Events/AssayPowerActionEvent.cs   |  30 ++++
 Content.Shared/Psionics/Events.cs             |  27 ++++
 Resources/Locale/en-US/abilities/psionic.ftl  |   3 +
 .../Locale/en-US/psionics/psionic-powers.ftl  |  30 ++++
 Resources/Prototypes/Actions/psionics.yml     |  19 +++
 .../DeltaV/Entities/Mobs/NPCs/familiars.yml   |   2 +
 .../Entities/Mobs/NPCs/elemental.yml          |   7 +
 .../Prototypes/Entities/Mobs/NPCs/flesh.yml   |   5 +
 .../Entities/Mobs/NPCs/glimmer_creatures.yml  |   4 +
 .../Structures/Specific/Anomaly/anomalies.yml |  51 +++++++
 .../Entities/Structures/Specific/oracle.yml   |   2 +
 .../Structures/Research/glimmer_prober.yml    |   4 +
 .../Structures/Research/sophicscribe.yml      |   2 +
 .../Roles/Jobs/Epistemics/forensicmantis.yml  |   1 +
 Resources/Prototypes/Psionics/psionics.yml    |  27 ++++
 .../Interface/Actions/psionics.rsi/assay.png  | Bin 0 -> 2351 bytes
 .../Interface/Actions/psionics.rsi/meta.json  |   5 +-
 18 files changed, 358 insertions(+), 1 deletion(-)
 create mode 100644 Content.Server/Abilities/Psionics/Abilities/AssayPowerSystem.cs
 create mode 100644 Content.Shared/Actions/Events/AssayPowerActionEvent.cs
 create mode 100644 Resources/Textures/Interface/Actions/psionics.rsi/assay.png

diff --git a/Content.Server/Abilities/Psionics/Abilities/AssayPowerSystem.cs b/Content.Server/Abilities/Psionics/Abilities/AssayPowerSystem.cs
new file mode 100644
index 0000000000..4fe08f303c
--- /dev/null
+++ b/Content.Server/Abilities/Psionics/Abilities/AssayPowerSystem.cs
@@ -0,0 +1,140 @@
+using Content.Server.Chat.Managers;
+using Content.Shared.Abilities.Psionics;
+using Content.Shared.Actions.Events;
+using Content.Shared.Chat;
+using Content.Shared.DoAfter;
+using Content.Shared.Popups;
+using Content.Shared.Psionics.Events;
+using Robust.Server.Audio;
+using Robust.Shared.Audio;
+using Robust.Server.Player;
+using Robust.Shared.Timing;
+using Robust.Shared.Player;
+
+namespace Content.Server.Abilities.Psionics;
+
+public sealed class AssayPowerSystem : EntitySystem
+{
+    [Dependency] private readonly SharedPsionicAbilitiesSystem _psionics = default!;
+    [Dependency] private readonly IGameTiming _gameTiming = default!;
+    [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
+    [Dependency] private readonly AudioSystem _audioSystem = default!;
+    [Dependency] private readonly SharedPopupSystem _popups = default!;
+    [Dependency] private readonly IChatManager _chatManager = default!;
+    [Dependency] private readonly IPlayerManager _playerManager = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<PsionicComponent, AssayPowerActionEvent>(OnPowerUsed);
+        SubscribeLocalEvent<PsionicComponent, AssayDoAfterEvent>(OnDoAfter);
+    }
+
+    /// <summary>
+    ///     This power activates when scanning any entity, displaying to the player's chat window a variety of psionic related statistics about the target.
+    /// </summary>
+    private void OnPowerUsed(EntityUid uid, PsionicComponent psionic, AssayPowerActionEvent args)
+    {
+        if (!_psionics.OnAttemptPowerUse(args.Performer, "assay")
+            || psionic.DoAfter is not null)
+            return;
+
+        var ev = new AssayDoAfterEvent(_gameTiming.CurTime, args.FontSize, args.FontColor);
+        _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Performer, args.UseDelay - TimeSpan.FromSeconds(psionic.CurrentAmplification), ev, args.Performer, args.Target, args.Performer)
+        {
+            BlockDuplicate = true,
+            BreakOnMove = true,
+            BreakOnDamage = true,
+        }, out var doAfterId);
+        psionic.DoAfter = doAfterId;
+
+        _popups.PopupEntity(Loc.GetString(args.PopupTarget, ("entity", args.Target)), args.Performer, PopupType.Medium);
+
+        _audioSystem.PlayPvs(args.SoundUse, args.Performer, AudioParams.Default.WithVolume(8f).WithMaxDistance(1.5f).WithRolloffFactor(3.5f));
+        _psionics.LogPowerUsed(args.Performer, args.PowerName, args.MinGlimmer, args.MaxGlimmer);
+        args.Handled = true;
+    }
+
+    /// <summary>
+    ///     Assuming the DoAfter wasn't canceled, the user wasn't mindbroken, and the target still exists, prepare the scan results!
+    /// </summary>
+    private void OnDoAfter(EntityUid uid, PsionicComponent component, AssayDoAfterEvent args)
+    {
+        if (component is null)
+            return;
+        component.DoAfter = null;
+
+        var user = uid;
+        var target = args.Target;
+        if (target == null || args.Cancelled
+            || !_playerManager.TryGetSessionByEntity(user, out var session))
+            return;
+
+        if (InspectSelf(uid, args, session))
+            return;
+
+        if (!TryComp<PsionicComponent>(target, out var targetPsionic))
+        {
+            var noPowers = Loc.GetString("no-powers", ("entity", target));
+            _popups.PopupEntity(noPowers, user, user, PopupType.LargeCaution);
+
+            // Incredibly spooky message for non-psychic targets.
+            var noPowersFeedback = $"[font size={args.FontSize}][color={args.FontColor}]{noPowers}[/color][/font]";
+            SendDescToChat(noPowersFeedback, session);
+            return;
+        }
+
+        InspectOther(targetPsionic, args, session);
+    }
+
+    /// <summary>
+    ///     This is a special use-case for scanning yourself with the power. The player receives a unique feedback message if they do so.
+    ///     It however displays significantly less information when doing so. Consider this an intriguing easter egg.
+    /// </summary>
+    private bool InspectSelf(EntityUid uid, AssayDoAfterEvent args, ICommonSession session)
+    {
+        if (args.Target != args.User)
+            return false;
+
+        var user = uid;
+        var target = args.Target;
+
+        var assaySelf = Loc.GetString("assay-self", ("entity", target!.Value));
+        _popups.PopupEntity(assaySelf, user, user, PopupType.LargeCaution);
+
+        var assaySelfFeedback = $"[font size=20][color=#ff0000]{assaySelf}[/color][/font]";
+        SendDescToChat(assaySelfFeedback, session);
+        return true;
+    }
+
+    /// <summary>
+    ///     If the target turns out to be a psychic, display their feedback messages in chat.
+    /// </summary>
+    private void InspectOther(PsionicComponent targetPsionic, AssayDoAfterEvent args, ICommonSession session)
+    {
+        var target = args.Target;
+        var targetAmp = MathF.Round(targetPsionic.CurrentAmplification, 2).ToString("#.##");
+        var targetDamp = MathF.Round(targetPsionic.CurrentDampening, 2).ToString("#.##");
+        var targetPotentia = MathF.Round(targetPsionic.Potentia, 2).ToString("#.##");
+        var message = $"[font size={args.FontSize}][color={args.FontColor}]{Loc.GetString("assay-body", ("entity", target!.Value), ("amplification", targetAmp), ("dampening", targetDamp), ("potentia", targetPotentia))}[/color][/font]";
+        SendDescToChat(message, session);
+
+        foreach (var feedback in targetPsionic.AssayFeedback)
+        {
+            var locale = Loc.GetString(feedback, ("entity", target!.Value));
+            var feedbackMessage = $"[font size={args.FontSize}][color={args.FontColor}]{locale}[/color][/font]";
+            SendDescToChat(feedbackMessage, session);
+        }
+    }
+
+    private void SendDescToChat(string feedbackMessage, ICommonSession session)
+    {
+        _chatManager.ChatMessageToOne(
+            ChatChannel.Emotes,
+            feedbackMessage,
+            feedbackMessage,
+            EntityUid.Invalid,
+            false,
+            session.Channel);
+    }
+}
diff --git a/Content.Shared/Actions/Events/AssayPowerActionEvent.cs b/Content.Shared/Actions/Events/AssayPowerActionEvent.cs
new file mode 100644
index 0000000000..dc25d34331
--- /dev/null
+++ b/Content.Shared/Actions/Events/AssayPowerActionEvent.cs
@@ -0,0 +1,30 @@
+using Robust.Shared.Audio;
+
+namespace Content.Shared.Actions.Events;
+
+public sealed partial class AssayPowerActionEvent : EntityTargetActionEvent
+{
+    [DataField]
+    public TimeSpan UseDelay = TimeSpan.FromSeconds(8f);
+
+    [DataField]
+    public SoundSpecifier SoundUse = new SoundPathSpecifier("/Audio/Psionics/heartbeat_fast.ogg");
+
+    [DataField]
+    public string PopupTarget = "assay-begin";
+
+    [DataField]
+    public int FontSize = 12;
+
+    [DataField]
+    public string FontColor = "#8A00C2";
+
+    [DataField]
+    public int MinGlimmer = 3;
+
+    [DataField]
+    public int MaxGlimmer = 6;
+
+    [DataField]
+    public string PowerName = "assay";
+}
diff --git a/Content.Shared/Psionics/Events.cs b/Content.Shared/Psionics/Events.cs
index 68ec3097e7..6705e940cd 100644
--- a/Content.Shared/Psionics/Events.cs
+++ b/Content.Shared/Psionics/Events.cs
@@ -1,6 +1,7 @@
 using Robust.Shared.Serialization;
 using Content.Shared.Damage;
 using Content.Shared.DoAfter;
+using Content.Shared.Abilities.Psionics;
 
 namespace Content.Shared.Psionics.Events;
 
@@ -67,3 +68,29 @@ public PsionicHealOtherDoAfterEvent(TimeSpan startedAt)
 
     public override DoAfterEvent Clone() => this;
 }
+
+[Serializable, NetSerializable]
+public sealed partial class AssayDoAfterEvent : DoAfterEvent
+{
+    [DataField(required: true)]
+    public TimeSpan StartedAt;
+
+    [DataField]
+    public int FontSize = 12;
+
+    [DataField]
+    public string FontColor = "#8A00C2";
+
+    private AssayDoAfterEvent()
+    {
+    }
+
+    public AssayDoAfterEvent(TimeSpan startedAt, int fontSize, string fontColor)
+    {
+        StartedAt = startedAt;
+        FontSize = fontSize;
+        FontColor = fontColor;
+    }
+
+    public override DoAfterEvent Clone() => this;
+}
diff --git a/Resources/Locale/en-US/abilities/psionic.ftl b/Resources/Locale/en-US/abilities/psionic.ftl
index d0e8db72f8..c8eb963594 100644
--- a/Resources/Locale/en-US/abilities/psionic.ftl
+++ b/Resources/Locale/en-US/abilities/psionic.ftl
@@ -68,3 +68,6 @@ action-description-psychokinesis = Bend the fabric of space to instantly move ac
 
 action-name-rf-sensitivity = Toggle RF Sensitivity
 action-desc-rf-sensitivity = Toggle your ability to interpret radio waves on and off.
+
+action-name-assay = Assay
+action-description-assay = Probe an entity at close range to glean metaphorical information about any powers they may have
diff --git a/Resources/Locale/en-US/psionics/psionic-powers.ftl b/Resources/Locale/en-US/psionics/psionic-powers.ftl
index ab2a991e06..f7d225f58f 100644
--- a/Resources/Locale/en-US/psionics/psionic-powers.ftl
+++ b/Resources/Locale/en-US/psionics/psionic-powers.ftl
@@ -183,3 +183,33 @@ ghost-role-information-familiar-description = An interdimensional creature bound
 ghost-role-information-familiar-rules =
     Obey the one who summoned you. Do not act against the interests of your Master. You will die for your Master if it is necessary.
 
+# Assay Power
+assay-begin = The air around {CAPITALIZE($entity)} begins to shimmer faintly
+assay-self = I AM.
+no-powers = {CAPITALIZE($entity)} will never awaken from the dream in this life
+assay-body = "My will cast upon {CAPITALIZE($entity)} divines these. Amplification: {$amplification} Dampening: {$dampening} Potentia: {$potentia}"
+assay-power-initialization-feedback =
+    I descend into the dreamlight once more, there I drink more fully of the cup of knowledge. The touch of the noosphere upon others becomes known to me,
+    I can cast my will upon them, divining the inner nature of others.
+assay-power-metapsionic-feedback = {CAPITALIZE($entity)} bears a spark of the divine's judgment, they have drunk deeply of the cup of knowledge.
+
+# Entity Specific Feedback Messages
+ifrit-feedback = A spirit of Gehenna, bound by the will of a powerful psychic
+prober-feedback = A mirror into the end of time, the screaming of dead stars emanates from this machine
+drain-feedback = A mirror into a realm where the stars sit still forever, a cold and distant malevolence stares back
+sophic-grammateus-feedback = SEEKER, YOU NEED ONLY ASK FOR MY WISDOM.
+oracle-feedback = WHY DO YOU BOTHER ME SEEKER? HAVE I NOT MADE MY DESIRES CLEAR?
+orecrab-feedback = Heralds of the Lord of Earth, summoned to this realm from Grome's kingdom
+reagent-slime-feedback = Heralds of the Lord of Water, summoned to this realm from Straasha's kingdom.
+flesh-golem-feedback = Abominations pulled from dead realms, twisted amalgamations of those fallen to the influence of primordial Chaos
+glimmer-mite-feedback = A semi-corporeal parasite native to the dreamlight, its presence here brings forth the screams of dead stars.
+anomaly-pyroclastic-feedback = A small mirror to the plane of Gehenna, truth lies within the Secret of Fire
+anomaly-gravity-feedback = Violet and crimson, blue of blue, impossibly dark yet greater than the whitest of white, a black star shines weakly at the end of it all
+anomaly-electricity-feedback = A mirror to a realm tiled by silicon, the lifeblood of artificial thought flows from it
+anomaly-flesh-feedback = From within it comes the suffering of damned mutants howling for all eternity
+anomaly-bluespace-feedback = A bridge of dreamlight, crossing into the space between realms of the multiverse
+anomaly-ice-feedback = Walls of blackened stone, ruin and famine wait for those who fall within
+anomaly-rock-feedback = A vast old oak dwells high over a plane of stone, it turns to stare back
+anomaly-flora-feedback = Musical notes drift around you, playfully beckoning, they wish to feast
+anomaly-liquid-feedback = A realm of twisting currents. Its placidity is a lie. The eyes within stare hungrilly
+anomaly-shadow-feedback = At the end of time, when all suns have set forever, there amidst the void stands a monument to past sins.
diff --git a/Resources/Prototypes/Actions/psionics.yml b/Resources/Prototypes/Actions/psionics.yml
index c6d9e17c2a..97d19aae5f 100644
--- a/Resources/Prototypes/Actions/psionics.yml
+++ b/Resources/Prototypes/Actions/psionics.yml
@@ -367,3 +367,22 @@
         followMaster: true
         minGlimmer: 5
         maxGlimmer: 10
+
+- type: entity
+  id: ActionAssay
+  name: action-name-assay
+  description: action-description-assay
+  categories: [ HideSpawnMenu ]
+  components:
+    - type: EntityTargetAction
+      icon: { sprite: Interface/Actions/psionics.rsi, state: assay }
+      useDelay: 45
+      checkCanAccess: false
+      range: 2
+      itemIconStyle: BigAction
+      canTargetSelf: true
+      blacklist:
+        components:
+          - PsionicInsulation
+          - Mindbroken
+      event: !type:AssayPowerActionEvent
diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml
index 12b5f7f200..42c12b1fd6 100644
--- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml
@@ -92,6 +92,8 @@
     nameSegments: [names_golem]
   - type: Psionic
     removable: false
+    assayFeedback:
+      - ifrit-feedback
     psychognomicDescriptors:
       - p-descriptor-bound
       - p-descriptor-cyclic
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml
index 94ba7ec418..bc5e0239d6 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml
@@ -74,6 +74,7 @@
   - type: ZombieImmune
   - type: ClothingRequiredStepTriggerImmune
     slots: All
+  - type: Dispellable
 
 - type: entity
   abstract: true
@@ -104,6 +105,9 @@
     damageContainer: StructuralInorganic
   - type: Psionic
     removable: false
+    roller: false
+    assayFeedback:
+      - orecrab-feedback
   - type: InnatePsionicPowers
     powersToAdd:
       - TelepathyPower
@@ -303,6 +307,9 @@
     solution: bloodstream
   - type: Psionic
     removable: false
+    roller: false
+    assayFeedback:
+      - reagent-slime-feedback
   - type: InnatePsionicPowers
     powersToAdd:
       - TelepathyPower
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml b/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml
index 06ab02dedc..bdf87ec87d 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/flesh.yml
@@ -54,6 +54,11 @@
         Slash: 6
   - type: ReplacementAccent
     accent: genericAggressive
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - flesh-golem-feedback
 
 - type: entity
   parent: BaseMobFlesh
diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/glimmer_creatures.yml b/Resources/Prototypes/Entities/Mobs/NPCs/glimmer_creatures.yml
index 52f3844c25..5fcada3f7f 100644
--- a/Resources/Prototypes/Entities/Mobs/NPCs/glimmer_creatures.yml
+++ b/Resources/Prototypes/Entities/Mobs/NPCs/glimmer_creatures.yml
@@ -23,6 +23,10 @@
         - ReagentId: Ectoplasm
           Quantity: 15
   - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - glimmer-mite-feedback
   - type: GlimmerSource
   - type: AmbientSound
     range: 6
diff --git a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml
index 8294586048..02184fc613 100644
--- a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml
+++ b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml
@@ -50,6 +50,7 @@
       path: /Audio/Effects/teleport_arrival.ogg
   - type: Psionic
     removable: false
+    roller: false
   - type: InnatePsionicPowers
     powersToAdd:
       - TelepathyPower
@@ -106,6 +107,11 @@
   - type: IgniteOnCollide
     fixtureId: fix1
     fireStacks: 1
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-pyroclastic-feedback
 
 - type: entity
   id: AnomalyGravity
@@ -138,6 +144,11 @@
   - type: SingularityDistortion
     intensity: 1000
     falloffPower: 2.7
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-gravity-feedback
 
 - type: entity
   id: AnomalyElectricity
@@ -161,6 +172,11 @@
     castShadows: false
   - type: ElectricityAnomaly
   - type: Electrified
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-electricity-feedback
 
 - type: entity
   id: AnomalyFlesh
@@ -254,6 +270,11 @@
       - MobFleshClamp
       - MobFleshLover
       - FleshKudzu
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-flesh-feedback
 
 - type: entity
   id: AnomalyBluespace
@@ -304,6 +325,11 @@
     anomalyContactDamage:
       types:
         Radiation: 10
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-bluespace-feedback
 
 - type: entity
   id: AnomalyIce
@@ -352,6 +378,11 @@
     releasedGas: 8 # Frezon. Please replace if there is a better way to specify this
     releaseOnMaxSeverity: true
     spawnRadius: 0
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-ice-feedback
 
 - type: entity
   id: AnomalyRockBase
@@ -390,6 +421,11 @@
         maxAmount: 50
         maxRange: 12
       floor: FloorAsteroidTile
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-rock-feedback
 
 - type: entity
   id: AnomalyRockUranium
@@ -649,6 +685,11 @@
         maxRange: 6
       spawns:
       - KudzuFlowerAngry
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-flora-feedback
 
 - type: entity
   id: AnomalyFloraBulb
@@ -808,6 +849,11 @@
     solution: anomaly
   - type: InjectableSolution
     solution: beaker
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-liquid-feedback
 
 - type: entity
   id: AnomalyShadow
@@ -864,3 +910,8 @@
   - type: Tag
     tags:
       - SpookyFog
+  - type: Psionic
+    removable: false
+    roller: false
+    assayFeedback:
+      - anomaly-shadow-feedback
diff --git a/Resources/Prototypes/Entities/Structures/Specific/oracle.yml b/Resources/Prototypes/Entities/Structures/Specific/oracle.yml
index 3e2ed9508e..e908ecab66 100644
--- a/Resources/Prototypes/Entities/Structures/Specific/oracle.yml
+++ b/Resources/Prototypes/Entities/Structures/Specific/oracle.yml
@@ -18,6 +18,8 @@
   - type: Actions
   - type: Psionic
     removable: false
+    assayFeedback:
+      - oracle-feedback
     psychognomicDescriptors:
       - p-descriptor-old
       - p-descriptor-demiurgic
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/glimmer_prober.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/glimmer_prober.yml
index 0eede9c281..1bb752ade4 100644
--- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/glimmer_prober.yml
+++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/glimmer_prober.yml
@@ -6,6 +6,8 @@
   components:
   - type: Psionic
     removable: false
+    assayFeedback:
+      - prober-feedback
   - type: InnatePsionicPowers
     powersToAdd:
       - TelepathyPower
@@ -93,6 +95,8 @@
   components:
   - type: Psionic
     removable: false
+    assayFeedback:
+      - drain-feedback
   - type: GlimmerSource
     addToGlimmer: false
   - type: Construction
diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml
index f92c9b0740..6f7b02cb6b 100644
--- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml
+++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml
@@ -25,6 +25,8 @@
   - type: Actions
   - type: Psionic
     removable: false
+    assayFeedback:
+      - sophic-grammateus-feedback
     psychognomicDescriptors:
       - p-descriptor-old
       - p-descriptor-demiurgic
diff --git a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml
index f7a3120570..961bbf05fd 100644
--- a/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml
+++ b/Resources/Prototypes/Nyanotrasen/Roles/Jobs/Epistemics/forensicmantis.yml
@@ -39,6 +39,7 @@
       powersToAdd:
         - MetapsionicPower
         - TelepathyPower
+        - AssayPower
 
 - type: startingGear
   id: ForensicMantisGear
diff --git a/Resources/Prototypes/Psionics/psionics.yml b/Resources/Prototypes/Psionics/psionics.yml
index 548881e61f..b1e9d783a8 100644
--- a/Resources/Prototypes/Psionics/psionics.yml
+++ b/Resources/Prototypes/Psionics/psionics.yml
@@ -170,6 +170,9 @@
     - !type:AddPsionicStatSources
       amplificationModifier: 0.5
       dampeningModifier: 0.5
+    - !type:PsionicAddAvailablePowers
+      powerPrototype: AssayPower
+      weight: 0.1
   removalFunctions:
     - !type:RemovePsionicActions
     - !type:RemovePsionicPowerComponents
@@ -178,6 +181,8 @@
     - !type:RemovePsionicStatSources
     - !type:RemoveAssayFeedback
       assayFeedback: metapsionic-power-metapsionic-feedback
+    - !type:PsionicRemoveAvailablePowers
+      powerPrototype: AssayPower
 
 - type: psionicPower
   id: PsionicRegenerationPower
@@ -661,3 +666,25 @@
     - !type:RemovePsionicPsychognomicDescriptors
       psychognomicDescriptor: calling
   powerSlotCost: 0
+
+- type: psionicPower
+  id: AssayPower
+  name: Assay
+  powerCategories:
+    - Mentalic
+  initializeFunctions:
+    - !type:AddPsionicActions
+      actions:
+        - ActionAssay
+    - !type:PsionicFeedbackPopup
+    - !type:PsionicFeedbackSelfChat
+      feedbackMessage: assay-power-initialization-feedback
+    - !type:AddPsionicAssayFeedback
+      assayFeedback: assay-power-metapsionic-feedback
+    - !type:AddPsionicStatSources
+      dampeningModifier: 0.5
+  removalFunctions:
+    - !type:RemovePsionicActions
+    - !type:RemovePsionicStatSources
+    - !type:RemoveAssayFeedback
+      assayFeedback: assay-power-metapsionic-feedback
diff --git a/Resources/Textures/Interface/Actions/psionics.rsi/assay.png b/Resources/Textures/Interface/Actions/psionics.rsi/assay.png
new file mode 100644
index 0000000000000000000000000000000000000000..f245ca9e5e34e1e240ec8669d544d25a7c480053
GIT binary patch
literal 2351
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
V0002eQ<DGy002ovPDHLkV1jdUM4kWu

literal 0
HcmV?d00001

diff --git a/Resources/Textures/Interface/Actions/psionics.rsi/meta.json b/Resources/Textures/Interface/Actions/psionics.rsi/meta.json
index 735bc293d1..dd9833b560 100644
--- a/Resources/Textures/Interface/Actions/psionics.rsi/meta.json
+++ b/Resources/Textures/Interface/Actions/psionics.rsi/meta.json
@@ -1,12 +1,15 @@
 {
   "version": 1,
   "license": "CC-BY-SA-3.0",
-  "copyright": "healing_word, revivify, shadeskip by leonardo_dabepis (discord), telekinetic_pulse by .mocho (discord), pyrokinetic_flare, summon_remilia, summon_bat and summon_imp by ghost581 (discord)",
+  "copyright": "assay, healing_word, revivify, shadeskip by leonardo_dabepis (discord), telekinetic_pulse by .mocho (discord), pyrokinetic_flare, summon_remilia, summon_bat and summon_imp by ghost581 (discord)",
   "size": {
     "x": 64,
     "y": 64
   },
   "states": [
+    {
+      "name": "assay"
+    },
     {
       "name": "healing_word"
     },

From f0a9bbd5ebf4cdd1e1b5cdf26478206bd41a137b Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Sat, 11 Jan 2025 00:13:53 +0000
Subject: [PATCH 33/38] Automatic Changelog Update (#1450)

---
 Resources/Changelog/Changelog.yml | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 357f9b38a7..78bc7a56f2 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9526,3 +9526,14 @@ Entries:
   id: 6658
   time: '2025-01-10T05:14:46.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1477
+- author: VMSolidus
+  changes:
+    - type: Add
+      message: >-
+        Added Assay as a new psi-power, which is available roundstart to the
+        Psionic Mantis. Assay allows the caster to obtain more direct
+        information about the statistics of a specific Psion, as well as vague
+        hints as to what their powers may be, if any.
+  id: 6659
+  time: '2025-01-11T00:13:27.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1450

From 6941a010283ac4bfc346097e8860013db134e8d9 Mon Sep 17 00:00:00 2001
From: VMSolidus <evilexecutive@gmail.com>
Date: Fri, 10 Jan 2025 20:40:24 -0500
Subject: [PATCH 34/38] Update dev_map.yml

---
 Resources/Maps/Test/dev_map.yml | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/Resources/Maps/Test/dev_map.yml b/Resources/Maps/Test/dev_map.yml
index d4cc1842d7..ad4910d1da 100644
--- a/Resources/Maps/Test/dev_map.yml
+++ b/Resources/Maps/Test/dev_map.yml
@@ -5831,13 +5831,6 @@ entities:
     - type: Transform
       pos: -6.8905525,1.5128828
       parent: 179
-- proto: VehicleKeyJanicart
-  entities:
-  - uid: 14
-    components:
-    - type: Transform
-      pos: 6.5,16.5
-      parent: 179
 - proto: VendingMachineCigs
   entities:
   - uid: 870

From 5a13b27cadda36fd257a5d9b3bb2c8d896cb806f Mon Sep 17 00:00:00 2001
From: VMSolidus <evilexecutive@gmail.com>
Date: Fri, 10 Jan 2025 20:55:49 -0500
Subject: [PATCH 35/38] How the fuck did AI not have these?

---
 Resources/Maps/saltern.yml                    | 1642 ++++++++---------
 .../Entities/Mobs/Player/silicon.yml          |   34 +-
 .../Machines/Computers/computers.yml          |    5 +
 .../Structures/Wallmounts/air_alarm.yml       |    1 +
 Resources/Prototypes/Maps/saltern.yml         |    3 +-
 5 files changed, 860 insertions(+), 825 deletions(-)

diff --git a/Resources/Maps/saltern.yml b/Resources/Maps/saltern.yml
index 36984557db..86122e2f8c 100644
--- a/Resources/Maps/saltern.yml
+++ b/Resources/Maps/saltern.yml
@@ -469,7 +469,7 @@ entities:
             0: 53709
           4,4:
             0: 4573
-            3: 16384
+            2: 16384
           5,0:
             0: 62190
           5,1:
@@ -500,7 +500,7 @@ entities:
             0: 35771
           7,3:
             0: 39135
-            2: 1024
+            3: 1024
           7,4:
             0: 55739
           7,-1:
@@ -533,27 +533,27 @@ entities:
             0: 3581
           1,7:
             0: 4369
-            3: 17484
+            2: 17484
           1,8:
             0: 4369
-            3: 17476
+            2: 17476
           2,5:
             0: 53367
           2,6:
             0: 1405
           2,7:
-            3: 7
+            2: 7
           3,5:
             0: 4210
-            3: 32768
+            2: 32768
           3,6:
             0: 13073
-            3: 8
+            2: 8
           3,7:
-            3: 4
+            2: 4
           4,5:
             0: 273
-            3: 29764
+            2: 29764
           -8,0:
             0: 61550
           -9,0:
@@ -623,7 +623,7 @@ entities:
           7,-2:
             0: 57599
           7,-4:
-            3: 8738
+            2: 8738
           7,-3:
             0: 3808
           8,-3:
@@ -644,7 +644,7 @@ entities:
             0: 65524
           0,-9:
             0: 52416
-            3: 273
+            2: 273
           1,-8:
             0: 65488
           1,-7:
@@ -661,7 +661,7 @@ entities:
             0: 61695
           2,-9:
             0: 13107
-            3: 2176
+            2: 2176
           3,-8:
             0: 52637
           3,-7:
@@ -670,76 +670,76 @@ entities:
             0: 64733
           4,-8:
             0: 4483
-            3: 17484
+            2: 17484
           4,-7:
             0: 65281
-            3: 12
+            2: 12
           4,-6:
             0: 61152
           4,-9:
-            3: 16384
+            2: 16384
             0: 32768
           5,-8:
-            3: 21855
+            2: 21855
             0: 160
           5,-7:
-            3: 15
+            2: 15
             0: 63232
           5,-9:
-            3: 20480
+            2: 20480
             0: 40960
           5,-6:
             0: 26214
           6,-8:
-            3: 21855
+            2: 21855
             0: 160
           6,-7:
-            3: 15
+            2: 15
             0: 56576
           6,-6:
             0: 61919
           6,-9:
-            3: 20480
+            2: 20480
             0: 40960
           7,-8:
-            3: 21855
+            2: 21855
             0: 160
           7,-7:
-            3: 11823
+            2: 11823
           7,-5:
             0: 36846
           7,-9:
-            3: 20767
+            2: 20767
             0: 40960
           7,-6:
-            3: 546
+            2: 546
             0: 32768
           8,-8:
-            3: 21855
+            2: 21855
             0: 160
           8,-7:
-            3: 9007
+            2: 9007
           8,-5:
             0: 4017
           -4,5:
             0: 238
           -4,6:
             0: 255
-            3: 61440
+            2: 61440
           -5,5:
             0: 58982
           -5,6:
             0: 238
-            3: 61440
+            2: 61440
           -3,5:
             0: 3295
           -3,6:
             0: 255
-            3: 61440
+            2: 61440
           -3,7:
-            3: 51406
+            2: 51406
           -3,8:
-            3: 14
+            2: 14
             0: 52224
           -2,5:
             0: 52701
@@ -749,51 +749,51 @@ entities:
             0: 61166
           -1,8:
             0: 34952
-            3: 13104
+            2: 13104
           -9,4:
             0: 65471
           -8,5:
             0: 13072
-            3: 128
+            2: 128
           -9,5:
             0: 65459
           -8,6:
             0: 1
-            3: 63304
+            2: 63304
           -9,6:
             0: 59
-            3: 63488
+            2: 63488
           -8,7:
-            3: 2039
+            2: 2039
           -9,7:
-            3: 28671
+            2: 28671
           -7,6:
-            3: 63249
+            2: 63249
             0: 14
           -7,7:
-            3: 16
+            2: 16
           -7,5:
             0: 1038
-            3: 4352
+            2: 4352
           -6,5:
             0: 65327
           -6,6:
             0: 255
-            3: 61440
+            2: 61440
           -3,9:
             0: 12
-            3: 3584
+            2: 3584
           -2,8:
             0: 30560
           -2,9:
             0: 7
-            3: 3840
+            2: 3840
           -1,9:
-            3: 405
+            2: 405
           0,9:
-            3: 240
+            2: 240
           4,6:
-            3: 550
+            2: 550
             0: 34816
           5,5:
             0: 30583
@@ -803,24 +803,24 @@ entities:
             0: 5
           6,5:
             0: 255
-            3: 61440
+            2: 61440
           6,6:
-            3: 35561
+            2: 35561
           7,5:
             0: 36063
-            3: 4096
+            2: 4096
           7,6:
-            3: 53196
+            2: 53196
           8,4:
             0: 4351
-            3: 57344
+            2: 57344
           8,5:
             0: 272
-            5: 17472
+            4: 17472
           8,6:
-            3: 4081
+            2: 4081
           1,9:
-            3: 18
+            2: 18
           9,0:
             0: 65102
           9,1:
@@ -831,7 +831,7 @@ entities:
             0: 65535
           9,4:
             0: 255
-            3: 61440
+            2: 61440
           9,-1:
             0: 60942
           10,0:
@@ -846,52 +846,52 @@ entities:
             0: 48015
           10,4:
             0: 255
-            3: 61440
+            2: 61440
           11,0:
             0: 65520
           11,1:
             0: 53759
           11,2:
             0: 4319
-            4: 49152
+            5: 49152
           11,3:
             0: 61457
-            4: 204
+            5: 204
           11,-1:
             0: 30583
           11,4:
             0: 255
-            3: 61440
+            2: 61440
           12,0:
             0: 65527
           12,1:
             0: 28791
           12,2:
             0: 119
-            4: 28672
+            5: 28672
           12,3:
-            4: 119
+            5: 119
             0: 61440
           12,-1:
             0: 29311
           12,4:
             0: 255
-            3: 61440
+            2: 61440
           13,0:
             0: 49080
           13,1:
             0: 48058
           13,2:
-            3: 13104
+            2: 13104
             0: 34826
           13,3:
-            3: 35059
+            2: 35059
             0: 12288
           13,-1:
             0: 14119
           13,4:
             0: 51
-            3: 63624
+            2: 63624
           14,0:
             0: 48123
           14,1:
@@ -899,9 +899,9 @@ entities:
           14,2:
             0: 15235
           14,3:
-            3: 65528
+            2: 65528
           14,4:
-            3: 62455
+            2: 62455
           15,0:
             0: 56797
           15,1:
@@ -909,23 +909,23 @@ entities:
           15,2:
             0: 3548
           15,3:
-            3: 32767
+            2: 32767
           15,4:
-            3: 12850
+            2: 12850
           15,-1:
             0: 52701
           16,0:
             0: 13116
-            4: 52416
+            5: 52416
           16,1:
             0: 65484
           16,2:
-            3: 15
+            2: 15
             0: 4080
           16,3:
-            3: 20479
+            2: 20479
           8,-4:
-            3: 8738
+            2: 8738
             0: 34952
           9,-4:
             0: 56789
@@ -937,15 +937,15 @@ entities:
             0: 18295
           10,-4:
             0: 65024
-            3: 14
+            2: 14
           10,-3:
             0: 65520
           10,-2:
             0: 63743
           10,-5:
-            3: 34956
+            2: 34956
           11,-4:
-            3: 2187
+            2: 2187
             0: 13056
           11,-3:
             0: 43946
@@ -953,10 +953,10 @@ entities:
             0: 30250
           11,-5:
             0: 32776
-            3: 17968
+            2: 17968
           12,-4:
             0: 7
-            3: 4088
+            2: 4088
           12,-3:
             0: 65535
           12,-2:
@@ -964,7 +964,7 @@ entities:
           -4,-8:
             0: 4016
           -4,-9:
-            3: 28672
+            2: 28672
             0: 127
           -5,-8:
             0: 2995
@@ -994,15 +994,15 @@ entities:
             0: 57309
           -2,-9:
             0: 61440
-            3: 47
+            2: 47
           -1,-6:
             0: 30065
           -8,-8:
             0: 60931
-            3: 8
+            2: 8
           -8,-9:
             0: 12288
-            3: 35064
+            2: 35064
           -9,-8:
             0: 56653
           -8,-7:
@@ -1013,16 +1013,16 @@ entities:
             0: 36863
           -9,-6:
             0: 3211
-            3: 12288
+            2: 12288
           -8,-5:
             0: 48123
           -9,-5:
             0: 43008
-            3: 4
+            2: 4
           -8,-4:
             0: 35771
           -7,-8:
-            3: 7
+            2: 7
             0: 7936
           -7,-6:
             0: 61428
@@ -1033,7 +1033,7 @@ entities:
           -7,-4:
             0: 36317
           -7,-9:
-            3: 17408
+            2: 17408
             0: 32768
           -6,-8:
             0: 36747
@@ -1043,30 +1043,30 @@ entities:
             0: 62463
           -6,-9:
             0: 61440
-            3: 34
+            2: 34
           -6,-7:
             0: 52878
           -6,-4:
             0: 62463
           -5,-9:
             0: 12799
-            3: 32768
+            2: 32768
           -9,-4:
             0: 34952
-            3: 800
+            2: 800
           -8,-3:
             0: 3663
           -9,-3:
             0: 52428
-            3: 4369
+            2: 4369
           -8,-2:
             0: 59119
           -9,-2:
             0: 52428
-            3: 4369
+            2: 4369
           -9,-1:
             0: 56780
-            3: 1
+            2: 1
           -7,-2:
             0: 65262
           -7,-3:
@@ -1086,11 +1086,11 @@ entities:
           -11,0:
             0: 3855
           -12,1:
-            3: 2056
+            2: 2056
           -11,2:
             0: 3855
           -11,1:
-            3: 546
+            2: 546
             0: 2184
           -10,0:
             0: 65535
@@ -1099,95 +1099,95 @@ entities:
           -10,2:
             0: 53247
           -11,3:
-            3: 34952
+            2: 34952
           -10,3:
             0: 61166
           -10,-1:
             0: 60928
-            3: 15
+            2: 15
           -10,4:
             0: 61182
           -12,-1:
-            3: 2738
+            2: 2738
           -11,-1:
-            3: 3628
+            2: 3628
           -11,-2:
-            3: 32768
+            2: 32768
           -10,-2:
-            3: 4492
+            2: 4492
           -10,-3:
-            3: 57480
+            2: 57480
           -10,-4:
-            3: 136
+            2: 136
           -10,-5:
-            3: 32776
+            2: 32776
           12,-5:
             0: 62079
           13,-4:
-            3: 3064
+            2: 3064
           13,-3:
             0: 48059
           13,-2:
             0: 63243
           13,-5:
-            3: 39912
+            2: 39912
           14,-4:
-            3: 1039
+            2: 1039
           14,-3:
             0: 13107
-            3: 128
+            2: 128
           14,-2:
             0: 65283
           14,-1:
             0: 4095
           14,-5:
-            3: 17600
+            2: 17600
           15,-4:
-            3: 8739
+            2: 8739
           15,-3:
-            3: 62066
+            2: 62066
           15,-2:
             0: 7424
-            3: 206
+            2: 206
           15,-5:
-            3: 8721
+            2: 8721
           16,-3:
-            3: 61440
+            2: 61440
           16,-2:
-            3: 255
+            2: 255
             0: 3840
           16,-1:
             0: 53247
           8,-9:
-            3: 24143
+            2: 24143
             0: 41120
           8,-6:
-            3: 3618
+            2: 3618
           9,-8:
-            3: 15
+            2: 15
           9,-7:
-            3: 15
+            2: 15
           9,-6:
-            3: 3840
+            2: 3840
           10,-8:
-            3: 55703
+            2: 55703
           10,-7:
-            3: 8743
+            2: 8743
             0: 34816
           10,-6:
-            3: 50978
+            2: 50978
             0: 8
           10,-9:
-            3: 40847
+            2: 40847
           11,-8:
-            3: 54
+            2: 54
             0: 2048
           11,-7:
             0: 64988
           11,-6:
             0: 3293
           11,-9:
-            3: 49921
+            2: 49921
           12,-8:
             0: 12144
           12,-7:
@@ -1195,78 +1195,78 @@ entities:
           12,-6:
             0: 24568
           20,-1:
-            3: 256
+            2: 256
           19,-1:
-            3: 65335
+            2: 65335
           20,0:
-            3: 16179
+            2: 16179
           19,0:
-            3: 39118
+            2: 39118
             0: 17441
           20,1:
-            3: 14135
+            2: 14135
           19,1:
-            3: 39321
+            2: 39321
             0: 17476
           20,2:
-            3: 29495
+            2: 29495
           19,2:
-            3: 53179
+            2: 53179
             0: 8260
           20,3:
-            3: 35
+            2: 35
           19,3:
-            3: 4095
+            2: 4095
           12,-9:
-            3: 61440
+            2: 61440
           13,-8:
-            3: 35043
+            2: 35043
           13,-7:
             0: 64849
           13,-6:
             0: 349
-            3: 32768
+            2: 32768
           13,-9:
-            3: 4096
+            2: 4096
           14,-8:
-            3: 6144
+            2: 6144
           14,-7:
-            3: 8739
+            2: 8739
           14,-6:
-            3: 4898
+            2: 4898
           15,-8:
-            3: 4352
+            2: 4352
           15,-7:
-            3: 4369
+            2: 4369
           15,-6:
-            3: 4369
+            2: 4369
           -11,4:
             0: 192
-            3: 32768
+            2: 32768
           -11,6:
             0: 12
-            3: 34816
+            2: 34816
           -11,7:
-            3: 35840
+            2: 35840
           -11,5:
-            3: 2184
+            2: 2184
           -10,6:
             0: 4335
-            3: 57344
+            2: 57344
           -10,7:
-            3: 4040
+            2: 4040
           -11,8:
-            3: 34952
+            2: 34952
           -10,5:
             0: 61166
           -9,8:
             0: 2827
-            3: 25844
+            2: 25844
           0,-12:
-            3: 127
+            2: 127
             0: 12288
           -1,-12:
-            3: 975
+            2: 975
             0: 32768
           0,-11:
             0: 29107
@@ -1274,14 +1274,14 @@ entities:
             0: 2047
           0,-10:
             0: 247
-            3: 57344
+            2: 57344
           -1,-10:
             0: 255
-            3: 36864
+            2: 36864
           -1,-9:
-            3: 3257
+            2: 3257
           1,-12:
-            3: 4375
+            2: 4375
           1,-11:
             0: 3536
           1,-10:
@@ -1291,254 +1291,254 @@ entities:
           2,-10:
             0: 14196
           2,-12:
-            3: 44800
+            2: 44800
           3,-12:
-            3: 768
+            2: 768
           3,-10:
-            3: 18240
+            2: 18240
           3,-9:
-            3: 1908
+            2: 1908
           7,-12:
-            3: 7455
+            2: 7455
           7,-11:
-            3: 7453
+            2: 7453
           7,-10:
-            3: 4381
+            2: 4381
           8,-12:
-            3: 20303
+            2: 20303
           8,-11:
-            3: 20303
+            2: 20303
           8,-10:
-            3: 20047
+            2: 20047
             0: 40960
           9,5:
             6: 4368
-            4: 17472
+            5: 17472
           9,6:
-            3: 12272
+            2: 12272
           10,5:
-            4: 4368
+            5: 4368
             7: 17472
           10,6:
-            3: 4080
+            2: 4080
           11,5:
-            4: 21840
+            5: 21840
           11,6:
-            3: 61424
+            2: 61424
           11,7:
-            3: 12
+            2: 12
           12,5:
-            3: 65535
+            2: 65535
           12,6:
-            3: 65535
+            2: 65535
           12,7:
-            3: 15
+            2: 15
           13,5:
-            3: 55705
+            2: 55705
           13,6:
-            3: 16383
+            2: 16383
           13,7:
-            3: 1
+            2: 1
           14,5:
-            3: 30591
+            2: 30591
           14,6:
-            3: 7
+            2: 7
           15,5:
-            3: 35
+            2: 35
           -4,-11:
-            3: 3840
+            2: 3840
           -5,-11:
-            3: 11776
+            2: 11776
           -4,-10:
             0: 6143
           -5,-10:
             0: 14472
-            3: 2
+            2: 2
           -3,-11:
-            3: 304
+            2: 304
             0: 34944
           -3,-10:
             0: 29949
           -2,-10:
             0: 1019
           -2,-11:
-            3: 544
+            2: 544
             0: 2176
           -2,-12:
-            3: 2048
+            2: 2048
           17,-3:
-            3: 61696
+            2: 61696
           17,-2:
-            3: 3327
+            2: 3327
             0: 768
           17,-1:
             0: 4369
-            3: 52428
+            2: 52428
           17,0:
             0: 19969
-            3: 8
-            4: 4368
+            2: 8
+            5: 4368
           18,-3:
-            3: 4096
+            2: 4096
           18,-2:
-            3: 59381
+            2: 59381
           18,-1:
-            3: 15358
+            2: 15358
             0: 33792
           18,0:
-            3: 65399
+            2: 65399
           19,-2:
-            3: 12288
+            2: 12288
           17,1:
             0: 65365
           17,2:
             0: 4095
           17,3:
-            3: 16383
+            2: 16383
           18,1:
-            3: 61167
+            2: 61167
           18,2:
             0: 1792
-            3: 2190
+            2: 2190
           18,3:
-            3: 40959
+            2: 40959
           12,-10:
-            3: 61440
+            2: 61440
           11,-10:
-            3: 61440
+            2: 61440
           13,-10:
-            3: 7936
+            2: 7936
           14,-10:
-            3: 256
+            2: 256
           9,-12:
-            3: 1807
+            2: 1807
           9,-11:
-            3: 1799
+            2: 1799
           9,-10:
-            3: 7
+            2: 7
           9,-9:
-            3: 3855
+            2: 3855
           10,-12:
-            3: 4369
+            2: 4369
           10,-11:
-            3: 4369
+            2: 4369
           10,-10:
-            3: 4369
+            2: 4369
           -12,-8:
-            3: 64170
+            2: 64170
           -13,-8:
-            3: 64170
+            2: 64170
           -12,-7:
-            3: 64170
+            2: 64170
           -13,-7:
-            3: 64170
+            2: 64170
           -12,-9:
-            3: 61440
+            2: 61440
           -11,-8:
-            3: 64170
+            2: 64170
           -11,-7:
-            3: 64170
+            2: 64170
           -11,-9:
-            3: 61440
+            2: 61440
           -10,-8:
-            3: 12834
+            2: 12834
             0: 34828
           -10,-7:
-            3: 12834
+            2: 12834
             0: 34952
           -10,-9:
-            3: 13288
+            2: 13288
             0: 32768
           -10,-6:
-            3: 57378
+            2: 57378
             0: 8
           -9,-9:
             0: 61440
-            3: 248
+            2: 248
           -13,-9:
-            3: 61440
+            2: 61440
           -11,-10:
-            3: 8
+            2: 8
           -10,-10:
-            3: 63631
+            2: 63631
           -10,-12:
-            3: 59592
+            2: 59592
           -9,-12:
-            3: 63743
+            2: 63743
           -10,-11:
-            3: 34952
+            2: 34952
           -9,-11:
-            3: 63736
+            2: 63736
           -9,-10:
-            3: 63736
+            2: 63736
           -9,-13:
-            3: 61440
+            2: 61440
           -8,-12:
-            3: 63743
+            2: 63743
           -8,-11:
-            3: 63736
+            2: 63736
           -8,-10:
-            3: 63736
+            2: 63736
           -8,-13:
-            3: 29696
+            2: 29696
           -7,-12:
-            3: 1808
+            2: 1808
           -7,-11:
-            3: 240
+            2: 240
           -6,-11:
-            3: 8192
+            2: 8192
           -6,-10:
-            3: 25262
+            2: 25262
           -14,0:
             0: 3598
           -14,2:
             0: 3598
           -13,-1:
-            3: 3648
+            2: 3648
           -11,9:
-            3: 35980
+            2: 35980
           -11,10:
-            3: 51336
+            2: 51336
           -10,8:
-            3: 497
+            2: 497
             0: 3084
           -10,9:
-            3: 449
+            2: 449
             0: 3084
           -10,10:
-            3: 4593
+            2: 4593
             0: 3084
           -10,11:
-            3: 227
+            2: 227
           -9,9:
             0: 2827
-            3: 21748
+            2: 21748
           -9,10:
             0: 2827
-            3: 58612
+            2: 58612
           -9,11:
-            3: 254
+            2: 254
           -8,8:
             0: 1799
-            3: 112
+            2: 112
           -8,9:
             0: 1799
-            3: 4208
+            2: 4208
           -8,10:
             0: 1799
-            3: 112
+            2: 112
           -8,11:
-            3: 112
+            2: 112
           -15,-8:
-            3: 34944
+            2: 34944
           -14,-8:
-            3: 64443
+            2: 64443
           -15,-7:
-            3: 136
+            2: 136
           -14,-7:
-            3: 64443
+            2: 64443
           -14,-9:
-            3: 61440
+            2: 61440
         uniqueMixes:
         - volume: 2500
           temperature: 293.15
@@ -1571,10 +1571,8 @@ entities:
           - 0
           - 0
         - volume: 2500
-          temperature: 293.14975
+          immutable: True
           moles:
-          - 20.078888
-          - 75.53487
           - 0
           - 0
           - 0
@@ -1585,11 +1583,13 @@ entities:
           - 0
           - 0
           - 0
-        - volume: 2500
-          immutable: True
-          moles:
           - 0
           - 0
+        - volume: 2500
+          temperature: 293.14975
+          moles:
+          - 20.078888
+          - 75.53487
           - 0
           - 0
           - 0
@@ -1604,7 +1604,7 @@ entities:
           temperature: 293.15
           moles:
           - 0
-          - 0
+          - 6666.982
           - 0
           - 0
           - 0
@@ -1619,7 +1619,7 @@ entities:
           temperature: 293.15
           moles:
           - 0
-          - 6666.982
+          - 0
           - 0
           - 0
           - 0
@@ -1673,55 +1673,55 @@ entities:
             color: '#FFFFFFFF'
             id: Arrows
           decals:
-            446: -12,-30
+            440: -12,-30
         - node:
             color: '#FFFFFFFF'
             id: Arrows
           decals:
-            383: 20,17
-            398: 20,17
-            402: 20,27
-            447: -12,-29
+            377: 20,17
+            392: 20,17
+            396: 20,27
+            441: -12,-29
         - node:
             angle: 3.141592653589793 rad
             color: '#FFFFFFFF'
             id: Arrows
           decals:
-            399: 22,17
-            403: 22,27
+            393: 22,17
+            397: 22,27
         - node:
             color: '#C3C3C3FF'
             id: Bot
           decals:
-            757: -35,-24
-            762: -32,-32
-            763: -31,-32
+            704: -35,-24
+            709: -32,-32
+            710: -31,-32
         - node:
             color: '#FFFFFFFF'
             id: Bot
           decals:
-            377: -35,6
-            378: -30,11
-            408: -3,-31
-            613: 31,8
-            614: 31,9
+            375: -35,6
+            376: -30,11
+            402: -3,-31
+            566: 31,8
+            567: 31,9
         - node:
             zIndex: 1
             color: '#FFFFFFFF'
             id: Bot
           decals:
-            481: 20,7
-            482: 21,7
-            483: 22,7
-            550: -7,-26
-            551: -6,-26
+            442: 20,7
+            443: 21,7
+            444: 22,7
+            511: -7,-26
+            512: -6,-26
         - node:
             angle: 3.141592653589793 rad
             color: '#FFFFFFFF'
             id: Bot
           decals:
-            400: 20,17
-            401: 22,17
+            394: 20,17
+            395: 22,17
         - node:
             color: '#FFFFFFFF'
             id: BotRight
@@ -1732,577 +1732,577 @@ entities:
             color: '#C3C3C3FF'
             id: Box
           decals:
-            775: -33,-29
-            776: -33,-28
+            722: -33,-29
+            723: -33,-28
         - node:
             color: '#FFFFFFFF'
             id: Box
           decals:
-            914: -33,21
-            915: -32,21
-            916: -32,24
-            917: -33,24
-            926: -31,23
-            927: -31,22
+            824: -33,21
+            825: -32,21
+            826: -32,24
+            827: -33,24
+            834: -31,23
+            835: -31,22
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: BrickTileDarkCornerNe
           decals:
-            556: -9,-28
+            517: -9,-28
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: BrickTileDarkCornerNw
           decals:
-            557: -10,-28
+            518: -10,-28
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: BrickTileDarkCornerSe
           decals:
-            555: -9,-30
+            516: -9,-30
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: BrickTileDarkCornerSw
           decals:
-            554: -10,-30
+            515: -10,-30
         - node:
             color: '#FFFFFFFF'
             id: BrickTileDarkInnerSe
           decals:
-            612: -11,20
+            565: -11,20
         - node:
             zIndex: 1
             color: '#FFFFFFFF'
             id: BrickTileDarkInnerSe
           decals:
-            488: 6,17
+            449: 6,17
         - node:
             color: '#FFFFFFFF'
             id: BrickTileDarkLineE
           decals:
-            530: 0,-25
-            736: -1,29
-            737: -1,28
+            491: 0,-25
+            683: -1,29
+            684: -1,28
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: BrickTileDarkLineE
           decals:
-            558: -9,-29
+            519: -9,-29
         - node:
             color: '#FFFFFFFF'
             id: BrickTileDarkLineN
           decals:
-            525: -6,-23
-            526: -5,-23
-            527: -4,-23
-            734: 3,30
-            735: 4,30
+            486: -6,-23
+            487: -5,-23
+            488: -4,-23
+            681: 3,30
+            682: 4,30
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: BrickTileDarkLineN
           decals:
-            565: 12,-14
-            566: 13,-14
-            567: 14,-14
-            568: 15,-14
+            526: 12,-14
+            527: 13,-14
+            528: 14,-14
+            529: 15,-14
         - node:
             color: '#FFFFFFFF'
             id: BrickTileDarkLineS
           decals:
-            609: -8,20
-            610: -9,20
-            611: -10,20
+            562: -8,20
+            563: -9,20
+            564: -10,20
         - node:
             zIndex: 1
             color: '#FFFFFFFF'
             id: BrickTileDarkLineS
           decals:
-            484: 10,17
-            485: 9,17
-            486: 8,17
-            487: 7,17
+            445: 10,17
+            446: 9,17
+            447: 8,17
+            448: 7,17
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: BrickTileDarkLineS
           decals:
-            569: 12,-18
-            570: 13,-18
-            571: 14,-18
-            572: 15,-18
+            530: 12,-18
+            531: 13,-18
+            532: 14,-18
+            533: 15,-18
         - node:
             color: '#FFFFFFFF'
             id: BrickTileDarkLineW
           decals:
-            531: -2,-25
+            492: -2,-25
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: BrickTileDarkLineW
           decals:
-            559: -10,-29
+            520: -10,-29
         - node:
             zIndex: 2
             color: '#D381C9FF'
             id: BrickTileSteelCornerNe
           decals:
-            553: -6,-26
+            514: -6,-26
         - node:
             color: '#D381C9FF'
             id: BrickTileSteelCornerNw
           decals:
-            539: -4,-26
+            500: -4,-26
         - node:
             color: '#D381C9FF'
             id: BrickTileSteelCornerSe
           decals:
-            545: -8,-24
+            506: -8,-24
         - node:
             color: '#D381C9E5'
             id: BrickTileSteelCornerSw
           decals:
-            437: -12,-32
+            431: -12,-32
         - node:
             color: '#FFFFFFFF'
             id: BrickTileSteelCornerSw
           decals:
-            625: 25,19
+            578: 25,19
         - node:
             color: '#C3C3C3FF'
             id: BrickTileSteelInnerNe
           decals:
-            751: -34,-32
-            780: -35,-27
+            698: -34,-32
+            727: -35,-27
         - node:
             color: '#D381C9E5'
             id: BrickTileSteelInnerNe
           decals:
-            441: -10,-26
+            435: -10,-26
         - node:
             color: '#D381C9FF'
             id: BrickTileSteelInnerNe
           decals:
-            529: -6,-27
-            544: 0,-29
-            549: -13,-19
+            490: -6,-27
+            505: 0,-29
+            510: -13,-19
         - node:
             color: '#D381C9FF'
             id: BrickTileSteelInnerNw
           decals:
-            538: -4,-27
-            540: -3,-26
+            499: -4,-27
+            501: -3,-26
         - node:
             color: '#C3C3C3FF'
             id: BrickTileSteelInnerSe
           decals:
-            761: -34,-30
-            771: -36,-28
-            772: -33,-30
+            708: -34,-30
+            718: -36,-28
+            719: -33,-30
         - node:
             color: '#D381C9E5'
             id: BrickTileSteelInnerSe
           decals:
-            431: -18,-28
-            434: -7,-33
+            425: -18,-28
+            428: -7,-33
         - node:
             color: '#D381C9FF'
             id: BrickTileSteelInnerSe
           decals:
-            541: 0,-26
-            546: -8,-23
+            502: 0,-26
+            507: -8,-23
         - node:
             color: '#C3C3C3FF'
             id: BrickTileSteelInnerSw
           decals:
-            738: -34,-28
+            685: -34,-28
         - node:
             color: '#D381C9E5'
             id: BrickTileSteelInnerSw
           decals:
-            413: -12,-20
-            438: -12,-31
+            407: -12,-20
+            432: -12,-31
         - node:
             color: '#C3C3C3FF'
             id: BrickTileSteelLineE
           decals:
-            748: -33,-29
-            749: -33,-28
-            750: -34,-31
-            755: -35,-26
-            756: -35,-25
-            759: -33,-30
-            770: -36,-29
-            779: -36,-30
+            695: -33,-29
+            696: -33,-28
+            697: -34,-31
+            702: -35,-26
+            703: -35,-25
+            706: -33,-30
+            717: -36,-29
+            726: -36,-30
         - node:
             color: '#D381C9FF'
             id: BrickTileSteelLineE
           decals:
-            542: 0,-27
-            543: 0,-28
+            503: 0,-27
+            504: 0,-28
         - node:
             color: '#C3C3C3FF'
             id: BrickTileSteelLineN
           decals:
-            746: -37,-24
-            747: -36,-24
-            752: -33,-32
-            753: -33,-27
-            754: -34,-27
+            693: -37,-24
+            694: -36,-24
+            699: -33,-32
+            700: -33,-27
+            701: -34,-27
         - node:
             color: '#D381C9E5'
             id: BrickTileSteelLineN
           decals:
-            415: -8,-19
-            416: -9,-19
-            417: -10,-19
-            418: -11,-19
-            440: -9,-26
+            409: -8,-19
+            410: -9,-19
+            411: -10,-19
+            412: -11,-19
+            434: -9,-26
         - node:
             color: '#D381C9FF'
             id: BrickTileSteelLineN
           decals:
-            528: -8,-26
-            548: -12,-19
+            489: -8,-26
+            509: -12,-19
         - node:
             zIndex: 2
             color: '#D381C9FF'
             id: BrickTileSteelLineN
           decals:
-            552: -7,-26
+            513: -7,-26
         - node:
             color: '#FFFFFFFF'
             id: BrickTileSteelLineN
           decals:
-            409: -11,-24
+            403: -11,-24
         - node:
             color: '#C3C3C3FF'
             id: BrickTileSteelLineS
           decals:
-            741: -33,-33
-            760: -33,-30
-            764: -34,-33
-            769: -37,-30
-            777: -35,-28
-            778: -36,-30
+            688: -33,-33
+            707: -33,-30
+            711: -34,-33
+            716: -37,-30
+            724: -35,-28
+            725: -36,-30
         - node:
             color: '#D381C9E5'
             id: BrickTileSteelLineS
           decals:
-            414: -13,-20
-            427: -17,-28
-            428: -16,-28
-            429: -15,-28
-            430: -14,-28
-            432: -5,-33
-            433: -6,-33
-            436: -11,-32
-            439: -13,-31
+            408: -13,-20
+            421: -17,-28
+            422: -16,-28
+            423: -15,-28
+            424: -14,-28
+            426: -5,-33
+            427: -6,-33
+            430: -11,-32
+            433: -13,-31
         - node:
             color: '#D381C9FF'
             id: BrickTileSteelLineS
           decals:
-            547: -9,-24
+            508: -9,-24
         - node:
             color: '#FFFFFFFF'
             id: BrickTileSteelLineS
           decals:
-            498: 57,5
-            499: 56,5
-            622: 26,19
-            623: 27,19
-            624: 28,19
+            459: 57,5
+            460: 56,5
+            575: 26,19
+            576: 27,19
+            577: 28,19
         - node:
             color: '#C3C3C3FF'
             id: BrickTileSteelLineW
           decals:
-            739: -34,-29
-            740: -34,-32
-            742: -37,-27
-            743: -37,-26
-            744: -37,-25
-            745: -37,-24
-            758: -34,-30
-            768: -37,-28
+            686: -34,-29
+            687: -34,-32
+            689: -37,-27
+            690: -37,-26
+            691: -37,-25
+            692: -37,-24
+            705: -34,-30
+            715: -37,-28
         - node:
             color: '#D381C9E5'
             id: BrickTileSteelLineW
           decals:
-            410: -12,-23
-            411: -12,-22
-            412: -12,-21
+            404: -12,-23
+            405: -12,-22
+            406: -12,-21
         - node:
             color: '#FFFFFFFF'
             id: BrickTileSteelLineW
           decals:
-            626: 25,20
-            627: 25,21
+            579: 25,20
+            580: 25,21
         - node:
             color: '#689F54FF'
             id: BrickTileWhiteCornerNe
           decals:
-            791: -21,-5
+            738: -21,-5
         - node:
             color: '#689F54FF'
             id: BrickTileWhiteCornerNw
           decals:
-            792: -23,-5
+            739: -23,-5
         - node:
             zIndex: 2
             color: '#EFB34196'
             id: BrickTileWhiteCornerSe
           decals:
-            592: -8,7
+            547: -8,7
         - node:
             zIndex: 2
             color: '#52B4E996'
             id: BrickTileWhiteCornerSw
           decals:
-            588: 7,-18
+            543: 7,-18
         - node:
             color: '#A4610696'
             id: BrickTileWhiteCornerSw
           decals:
-            632: 18,15
+            585: 18,15
         - node:
             zIndex: 2
             color: '#EFB34196'
             id: BrickTileWhiteCornerSw
           decals:
-            593: -14,7
+            548: -14,7
         - node:
             color: '#52B4E996'
             id: BrickTileWhiteEndE
           decals:
-            512: 49,-12
+            473: 49,-12
         - node:
             color: '#9FED5896'
             id: BrickTileWhiteEndE
           decals:
-            508: 52,-10
+            469: 52,-10
         - node:
             color: '#A4610696'
             id: BrickTileWhiteEndE
           decals:
-            515: 52,-8
+            476: 52,-8
         - node:
             color: '#D381C996'
             id: BrickTileWhiteEndE
           decals:
-            511: 52,-12
+            472: 52,-12
         - node:
             color: '#D4D4D496'
             id: BrickTileWhiteEndE
           decals:
-            507: 49,-10
+            468: 49,-10
         - node:
             color: '#EFB34196'
             id: BrickTileWhiteEndE
           decals:
-            500: 49,-8
+            461: 49,-8
         - node:
             color: '#334E6DC8'
             id: BrickTileWhiteEndN
           decals:
-            502: 57,-8
+            463: 57,-8
         - node:
             color: '#DE3A3A96'
             id: BrickTileWhiteEndN
           decals:
-            505: 57,-11
+            466: 57,-11
         - node:
             color: '#334E6DC8'
             id: BrickTileWhiteEndS
           decals:
-            503: 57,-9
+            464: 57,-9
         - node:
             color: '#DE3A3A96'
             id: BrickTileWhiteEndS
           decals:
-            504: 57,-12
+            465: 57,-12
         - node:
             color: '#52B4E996'
             id: BrickTileWhiteEndW
           decals:
-            513: 48,-12
+            474: 48,-12
         - node:
             color: '#9FED5896'
             id: BrickTileWhiteEndW
           decals:
-            509: 51,-10
+            470: 51,-10
         - node:
             color: '#A4610696'
             id: BrickTileWhiteEndW
           decals:
-            514: 51,-8
+            475: 51,-8
         - node:
             color: '#D381C996'
             id: BrickTileWhiteEndW
           decals:
-            510: 51,-12
+            471: 51,-12
         - node:
             color: '#D4D4D496'
             id: BrickTileWhiteEndW
           decals:
-            506: 48,-10
+            467: 48,-10
         - node:
             color: '#EFB34196'
             id: BrickTileWhiteEndW
           decals:
-            501: 48,-8
+            462: 48,-8
         - node:
             color: '#759DBCFF'
             id: BrickTileWhiteInnerSe
           decals:
-            975: 19,-18
+            879: 19,-18
         - node:
             color: '#A4610696'
             id: BrickTileWhiteInnerSe
           decals:
-            630: 22,15
+            583: 22,15
         - node:
             zIndex: 2
             color: '#52B4E996'
             id: BrickTileWhiteInnerSw
           decals:
-            580: 17,-13
+            536: 17,-13
         - node:
             color: '#A4610696'
             id: BrickTileWhiteInnerSw
           decals:
-            631: 19,15
+            584: 19,15
         - node:
             color: '#689F54FF'
             id: BrickTileWhiteLineE
           decals:
-            789: -21,-8
-            790: -21,-7
+            736: -21,-8
+            737: -21,-7
         - node:
             color: '#759DBCFF'
             id: BrickTileWhiteLineE
           decals:
-            971: 19,-19
-            972: 20,-18
-            973: 20,-17
-            974: 20,-16
+            875: 19,-19
+            876: 20,-18
+            877: 20,-17
+            878: 20,-16
         - node:
             zIndex: 2
             color: '#EFB34196'
             id: BrickTileWhiteLineE
           decals:
-            594: -8,8
+            549: -8,8
         - node:
             color: '#689F54FF'
             id: BrickTileWhiteLineN
           decals:
-            793: -22,-5
+            740: -22,-5
         - node:
             color: '#759DBCFF'
             id: BrickTileWhiteLineN
           decals:
-            979: 20,-16
-            980: 19,-16
-            981: 17,-16
+            883: 20,-16
+            884: 19,-16
+            885: 17,-16
         - node:
             color: '#A4610696'
             id: BrickTileWhiteLineN
           decals:
-            618: 26,10
-            619: 27,10
+            571: 26,10
+            572: 27,10
         - node:
             zIndex: 2
             color: '#52B4E996'
             id: BrickTileWhiteLineS
           decals:
-            582: 8,-18
-            583: 9,-18
-            589: 10,-18
+            537: 8,-18
+            538: 9,-18
+            544: 10,-18
         - node:
             color: '#759DBCFF'
             id: BrickTileWhiteLineS
           decals:
-            976: 20,-18
-            977: 17,-19
-            978: 19,-19
+            880: 20,-18
+            881: 17,-19
+            882: 19,-19
         - node:
             color: '#A4610696'
             id: BrickTileWhiteLineS
           decals:
-            620: 26,8
-            621: 27,8
-            628: 24,15
-            629: 23,15
-            635: 26,15
-            636: 27,15
-            637: 28,15
+            573: 26,8
+            574: 27,8
+            581: 24,15
+            582: 23,15
+            588: 26,15
+            589: 27,15
+            590: 28,15
         - node:
             zIndex: 2
             color: '#EFB34196'
             id: BrickTileWhiteLineS
           decals:
-            590: -9,7
-            591: -13,7
+            545: -9,7
+            546: -13,7
         - node:
             zIndex: 2
             color: '#52B4E996'
             id: BrickTileWhiteLineW
           decals:
-            579: 17,-14
-            584: 7,-17
-            585: 7,-16
-            586: 7,-15
-            587: 7,-14
+            535: 17,-14
+            539: 7,-17
+            540: 7,-16
+            541: 7,-15
+            542: 7,-14
         - node:
             color: '#689F54FF'
             id: BrickTileWhiteLineW
           decals:
-            787: -23,-7
-            788: -23,-6
-            794: -23,-8
+            734: -23,-7
+            735: -23,-6
+            741: -23,-8
         - node:
             color: '#759DBCFF'
             id: BrickTileWhiteLineW
           decals:
-            968: 17,-19
-            969: 17,-18
-            970: 17,-17
-            982: 17,-16
+            872: 17,-19
+            873: 17,-18
+            874: 17,-17
+            886: 17,-16
         - node:
             color: '#A4610696'
             id: BrickTileWhiteLineW
           decals:
-            633: 18,16
-            634: 18,17
+            586: 18,16
+            587: 18,17
         - node:
             color: '#EFB34196'
             id: BrickTileWhiteLineW
           decals:
-            642: 48,-6
-            643: 48,-5
-            644: 48,-4
-            645: 48,-3
+            595: 48,-6
+            596: 48,-5
+            597: 48,-4
+            598: 48,-3
         - node:
             zIndex: 2
             color: '#EFB34196'
             id: BrickTileWhiteLineW
           decals:
-            595: -14,8
+            550: -14,8
         - node:
             color: '#FFFFFFFF'
             id: BrickTileWhiteLineW
           decals:
-            965: 18,-22
-            966: 18,-23
-            967: 18,-21
+            869: 18,-22
+            870: 18,-23
+            871: 18,-21
         - node:
             color: '#FFFFFFFF'
             id: Caution
           decals:
-            524: 58,-5
+            485: 58,-5
         - node:
             angle: 1.5707963267948966 rad
             color: '#FFFFFFFF'
@@ -2354,8 +2354,8 @@ entities:
             color: '#FFFFFFFF'
             id: Delivery
           decals:
-            435: -8,-33
-            533: -1,-31
+            429: -8,-33
+            494: -1,-31
         - node:
             color: '#FFFFFFFF'
             id: DirtHeavy
@@ -2367,23 +2367,23 @@ entities:
             color: '#FFFFFFFF'
             id: DirtHeavy
           decals:
-            393: -24,-25
+            387: -24,-25
         - node:
             cleanable: True
             zIndex: 2
             color: '#FFFFFFFF'
             id: DirtHeavy
           decals:
-            597: -20,10
-            601: -20,9
-            602: -18,9
+            552: -20,10
+            556: -20,9
+            557: -18,9
         - node:
             cleanable: True
             zIndex: 2
             color: '#FFFFFFFF'
             id: DirtHeavyMonotile
           decals:
-            600: -20,8
+            555: -20,8
         - node:
             color: '#FFFFFFFF'
             id: DirtLight
@@ -2430,25 +2430,25 @@ entities:
             365: -36,1
             366: -38,7
             367: -40,8
-            370: -24,-9
-            371: -24,3
-            372: -25,2
-            373: -7,3
-            375: -36,8
-            376: -38,9
-            384: -23,-24
-            385: -25,-23
-            386: -23,-22
-            387: -25,-25
-            388: -24,-24
-            389: -24,-22
+            368: -24,-9
+            369: -24,3
+            370: -25,2
+            371: -7,3
+            373: -36,8
+            374: -38,9
+            378: -23,-24
+            379: -25,-23
+            380: -23,-22
+            381: -25,-25
+            382: -24,-24
+            383: -24,-22
         - node:
             cleanable: True
             zIndex: 2
             color: '#FFFFFFFF'
             id: DirtLight
           decals:
-            598: -19,9
+            553: -19,9
         - node:
             color: '#FFFFFFFF'
             id: DirtMedium
@@ -2464,18 +2464,18 @@ entities:
             44: 24,17
             65: 37,6
             82: 53,1
-            374: -35,8
-            390: -23,-25
-            391: -25,-22
-            392: -25,-24
+            372: -35,8
+            384: -23,-25
+            385: -25,-22
+            386: -25,-24
         - node:
             cleanable: True
             zIndex: 2
             color: '#FFFFFFFF'
             id: DirtMedium
           decals:
-            596: -19,10
-            599: -19,8
+            551: -19,10
+            554: -19,8
         - node:
             color: '#52B4E996'
             id: FullTileOverlayGreyscale
@@ -2493,11 +2493,11 @@ entities:
             color: '#52B4E996'
             id: FullTileOverlayGreyscale
           decals:
-            560: 9,-3
-            561: 9,-2
-            562: 10,-2
-            563: 8,-2
-            564: 9,-1
+            521: 9,-3
+            522: 9,-2
+            523: 10,-2
+            524: 8,-2
+            525: 9,-1
         - node:
             color: '#EFB34196'
             id: FullTileOverlayGreyscale
@@ -2537,19 +2537,19 @@ entities:
             color: '#AA4D53FF'
             id: HalfTileOverlayGreyscale
           decals:
-            907: -32,19
-            908: -31,19
-            909: -30,19
+            817: -32,19
+            818: -31,19
+            819: -30,19
         - node:
             color: '#BD575DFF'
             id: HalfTileOverlayGreyscale
           decals:
-            808: -9,17
-            809: -8,17
-            810: -7,17
-            820: -11,11
-            821: -12,11
-            822: -13,11
+            752: -9,17
+            753: -8,17
+            754: -7,17
+            764: -11,11
+            765: -12,11
+            766: -13,11
         - node:
             color: '#DE3A3A96'
             id: HalfTileOverlayGreyscale
@@ -2621,19 +2621,19 @@ entities:
             color: '#AA4D53FF'
             id: HalfTileOverlayGreyscale180
           decals:
-            897: -32,16
-            898: -31,16
-            899: -30,16
+            809: -32,16
+            810: -31,16
+            811: -30,16
         - node:
             color: '#BD575DFF'
             id: HalfTileOverlayGreyscale180
           decals:
-            798: -7,10
-            799: -8,10
-            800: -9,10
-            817: -11,10
-            818: -12,10
-            819: -13,10
+            745: -7,10
+            746: -8,10
+            747: -9,10
+            761: -11,10
+            762: -12,10
+            763: -13,10
         - node:
             color: '#DE3A3A96'
             id: HalfTileOverlayGreyscale180
@@ -2697,19 +2697,19 @@ entities:
             color: '#AA4D53FF'
             id: HalfTileOverlayGreyscale270
           decals:
-            880: -10,15
-            881: -10,14
-            893: -10,16
-            894: -33,17
-            895: -33,16
-            910: -33,18
+            803: -10,15
+            804: -10,14
+            805: -10,16
+            806: -33,17
+            807: -33,16
+            820: -33,18
         - node:
             color: '#BD575DFF'
             id: HalfTileOverlayGreyscale270
           decals:
-            802: -10,11
-            803: -10,12
-            804: -10,13
+            749: -10,11
+            750: -10,12
+            751: -10,13
         - node:
             color: '#DE3A3A96'
             id: HalfTileOverlayGreyscale270
@@ -2740,7 +2740,7 @@ entities:
             185: 37,6
             201: 42,8
             202: 42,7
-            497: 55,2
+            458: 55,2
         - node:
             color: '#FFD886FF'
             id: HalfTileOverlayGreyscale270
@@ -2778,7 +2778,7 @@ entities:
             105: 12,1
             307: 12,-9
             308: 12,-10
-            654: 12,-11
+            601: 12,-11
         - node:
             color: '#A4610696'
             id: HalfTileOverlayGreyscale90
@@ -2798,26 +2798,26 @@ entities:
             color: '#AA4D53FF'
             id: HalfTileOverlayGreyscale90
           decals:
-            903: -29,17
-            904: -29,18
-            911: -35,18
-            912: -35,19
-            913: -35,16
+            813: -29,17
+            814: -29,18
+            821: -35,18
+            822: -35,19
+            823: -35,16
         - node:
             color: '#BD575DFF'
             id: HalfTileOverlayGreyscale90
           decals:
-            797: -5,8
-            811: -6,16
-            812: -6,15
-            816: -5,12
+            744: -5,8
+            755: -6,16
+            756: -6,15
+            760: -5,12
         - node:
             color: '#C05B60FF'
             id: HalfTileOverlayGreyscale90
           decals:
-            845: -5,13
-            846: -5,11
-            858: -5,10
+            789: -5,13
+            790: -5,11
+            802: -5,10
         - node:
             color: '#DE3A3A96'
             id: HalfTileOverlayGreyscale90
@@ -2853,56 +2853,56 @@ entities:
             color: '#FFFFFFFF'
             id: LoadingArea
           decals:
-            984: 31,-20
+            887: 31,-20
         - node:
             angle: 3.141592653589793 rad
             color: '#FFFFFFFF'
             id: LoadingArea
           decals:
-            985: 31,-18
+            888: 31,-18
         - node:
             color: '#FFFFFFFF'
             id: MiniTileDarkLineN
           decals:
-            407: -16,-25
+            401: -16,-25
         - node:
             color: '#D381C9E5'
             id: MiniTileSteelCornerSe
           decals:
-            419: -14,-23
+            413: -14,-23
         - node:
             color: '#D381C9E5'
             id: MiniTileSteelCornerSw
           decals:
-            425: -18,-24
+            419: -18,-24
         - node:
             color: '#D381C9E5'
             id: MiniTileSteelInnerSe
           decals:
-            420: -15,-23
+            414: -15,-23
         - node:
             color: '#D381C9E5'
             id: MiniTileSteelInnerSw
           decals:
-            426: -17,-24
+            420: -17,-24
         - node:
             color: '#D381C9E5'
             id: MiniTileSteelLineE
           decals:
-            421: -14,-22
+            415: -14,-22
         - node:
             color: '#D381C9E5'
             id: MiniTileSteelLineW
           decals:
-            422: -18,-21
-            423: -18,-22
-            424: -18,-23
+            416: -18,-21
+            417: -18,-22
+            418: -18,-23
         - node:
             color: '#FFFFFFFF'
             id: MiniTileSteelLineW
           decals:
-            825: -5,-13
-            826: -5,-12
+            769: -5,-13
+            770: -5,-12
         - node:
             color: '#334E6DC8'
             id: QuarterTileOverlayGreyscale
@@ -2919,15 +2919,15 @@ entities:
             color: '#848586FF'
             id: QuarterTileOverlayGreyscale
           decals:
-            931: -37,10
-            932: -37,13
-            933: -37,14
-            934: -37,15
-            935: -37,16
-            944: -37,20
-            945: -37,21
-            946: -37,22
-            947: -37,23
+            836: -37,10
+            837: -37,13
+            838: -37,14
+            839: -37,15
+            840: -37,16
+            849: -37,20
+            850: -37,21
+            851: -37,22
+            852: -37,23
         - node:
             color: '#D4D4D428'
             id: QuarterTileOverlayGreyscale
@@ -2951,7 +2951,7 @@ entities:
             187: 50,5
             198: 44,9
             203: 42,6
-            496: 55,1
+            457: 55,1
         - node:
             color: '#52B4E996'
             id: QuarterTileOverlayGreyscale180
@@ -2964,14 +2964,14 @@ entities:
             color: '#848586FF'
             id: QuarterTileOverlayGreyscale180
           decals:
-            936: -37,13
-            937: -37,14
-            938: -37,15
-            939: -37,16
-            940: -37,20
-            941: -37,21
-            942: -37,22
-            943: -37,23
+            841: -37,13
+            842: -37,14
+            843: -37,15
+            844: -37,16
+            845: -37,20
+            846: -37,21
+            847: -37,22
+            848: -37,23
         - node:
             color: '#A4610696'
             id: QuarterTileOverlayGreyscale180
@@ -2981,7 +2981,7 @@ entities:
             color: '#AA4D53FF'
             id: QuarterTileOverlayGreyscale180
           decals:
-            896: -33,16
+            808: -33,16
         - node:
             color: '#D4D4D428'
             id: QuarterTileOverlayGreyscale180
@@ -3007,17 +3007,17 @@ entities:
             color: '#848586FF'
             id: QuarterTileOverlayGreyscale270
           decals:
-            954: -38,17
-            955: -38,18
-            956: -38,19
-            957: -36,19
-            958: -36,18
-            959: -36,17
+            859: -38,17
+            860: -38,18
+            861: -38,19
+            862: -36,19
+            863: -36,18
+            864: -36,17
         - node:
             color: '#C05B60FF'
             id: QuarterTileOverlayGreyscale270
           decals:
-            857: -6,10
+            801: -6,10
         - node:
             color: '#DE3A3A96'
             id: QuarterTileOverlayGreyscale270
@@ -3029,7 +3029,7 @@ entities:
           decals:
             125: 35,-5
             200: 42,9
-            495: 55,3
+            456: 55,3
         - node:
             color: '#FFD886FF'
             id: QuarterTileOverlayGreyscale270
@@ -3046,12 +3046,12 @@ entities:
             color: '#848586FF'
             id: QuarterTileOverlayGreyscale90
           decals:
-            948: -36,19
-            949: -36,18
-            950: -36,17
-            951: -38,19
-            952: -38,18
-            953: -38,17
+            853: -36,19
+            854: -36,18
+            855: -36,17
+            856: -38,19
+            857: -38,18
+            858: -38,17
         - node:
             color: '#A4610696'
             id: QuarterTileOverlayGreyscale90
@@ -3088,18 +3088,18 @@ entities:
             color: '#8F6CFFAD'
             id: Rust
           decals:
-            781: -31,-3
-            782: -30,-3
-            783: -30,0
-            784: -31,0
-            785: -31,1
-            786: -30,1
+            728: -31,-3
+            729: -30,-3
+            730: -30,0
+            731: -31,0
+            732: -31,1
+            733: -30,1
         - node:
             color: '#FFFFFFFF'
             id: StandClear
           decals:
-            396: 21,24
-            532: 1,-30
+            390: 21,24
+            493: 1,-30
         - node:
             angle: 1.5707963267948966 rad
             color: '#FFFFFFFF'
@@ -3110,13 +3110,13 @@ entities:
             color: '#AA4D53FF'
             id: ThreeQuarterTileOverlayGreyscale
           decals:
-            906: -33,19
+            816: -33,19
         - node:
             color: '#BD575DFF'
             id: ThreeQuarterTileOverlayGreyscale
           decals:
-            815: -10,17
-            824: -14,11
+            759: -10,17
+            768: -14,11
         - node:
             color: '#52B4E996'
             id: ThreeQuarterTileOverlayGreyscale180
@@ -3126,7 +3126,7 @@ entities:
             color: '#AA4D53FF'
             id: ThreeQuarterTileOverlayGreyscale180
           decals:
-            901: -29,16
+            812: -29,16
         - node:
             color: '#52B4E996'
             id: ThreeQuarterTileOverlayGreyscale270
@@ -3136,8 +3136,8 @@ entities:
             color: '#BD575DFF'
             id: ThreeQuarterTileOverlayGreyscale270
           decals:
-            801: -10,10
-            823: -14,10
+            748: -10,10
+            767: -14,10
         - node:
             color: '#52B4E996'
             id: ThreeQuarterTileOverlayGreyscale90
@@ -3147,18 +3147,18 @@ entities:
             color: '#AA4D53FF'
             id: ThreeQuarterTileOverlayGreyscale90
           decals:
-            905: -29,19
+            815: -29,19
         - node:
             color: '#BD575DFF'
             id: ThreeQuarterTileOverlayGreyscale90
           decals:
-            813: -5,14
-            814: -6,17
+            757: -5,14
+            758: -6,17
         - node:
             color: '#FF0000FF'
             id: WarnBox
           decals:
-            695: 69,2
+            642: 69,2
         - node:
             color: '#FFFFFFFF'
             id: WarnBox
@@ -3168,174 +3168,174 @@ entities:
             color: '#FF0000FF'
             id: WarnCornerNE
           decals:
-            698: 68,3
+            645: 68,3
         - node:
             color: '#FF0000FF'
             id: WarnCornerNW
           decals:
-            699: 66,3
+            646: 66,3
         - node:
             color: '#FF0000FF'
             id: WarnCornerSE
           decals:
-            697: 68,1
+            644: 68,1
         - node:
             color: '#FF0000FF'
             id: WarnCornerSW
           decals:
-            696: 66,1
+            643: 66,1
         - node:
             color: '#FFFFFFFF'
             id: WarnCornerSmallNW
           decals:
-            963: -39,23
+            868: -39,23
         - node:
             color: '#FFFFFFFF'
             id: WarnCornerSmallSW
           decals:
-            962: -39,18
+            867: -39,18
         - node:
             color: '#FFFFFFFF'
             id: WarnEndE
           decals:
-            653: 12,-12
+            600: 12,-12
         - node:
             color: '#FF0000FF'
             id: WarnEndN
           decals:
-            694: 70,3
+            641: 70,3
         - node:
             color: '#FF0000FF'
             id: WarnEndS
           decals:
-            693: 70,2
+            640: 70,2
         - node:
             color: '#FFFFFFFF'
             id: WarnEndW
           decals:
-            652: 11,-12
+            599: 11,-12
         - node:
             color: '#C3C3C3FF'
             id: WarnLineE
           decals:
-            767: -36,-33
+            714: -36,-33
         - node:
             color: '#FF0000FF'
             id: WarnLineE
           decals:
-            667: 60,7
-            668: 60,6
-            700: 68,2
+            614: 60,7
+            615: 60,6
+            647: 68,2
         - node:
             color: '#FFFFFFFF'
             id: WarnLineE
           decals:
-            442: -15,-30
-            443: -15,-31
-            516: 54,-4
-            517: 54,-5
-            518: 54,-6
-            656: 57,7
-            657: 57,6
-            658: 57,8
-            659: 57,5
-            660: 57,4
-            661: 57,3
-            662: 57,2
-            663: 57,1
-            664: 57,0
-            795: -21,-6
-            922: -32,23
-            923: -32,22
+            436: -15,-30
+            437: -15,-31
+            477: 54,-4
+            478: 54,-5
+            479: 54,-6
+            603: 57,7
+            604: 57,6
+            605: 57,8
+            606: 57,5
+            607: 57,4
+            608: 57,3
+            609: 57,2
+            610: 57,1
+            611: 57,0
+            742: -21,-6
+            832: -32,23
+            833: -32,22
         - node:
             color: '#FF0000FF'
             id: WarnLineN
           decals:
-            688: 62,0
-            689: 63,0
-            690: 63,5
-            691: 62,5
-            692: 67,1
+            635: 62,0
+            636: 63,0
+            637: 63,5
+            638: 62,5
+            639: 67,1
         - node:
             color: '#FFFFFFFF'
             id: WarnLineN
           decals:
-            404: 20,26
-            405: 21,26
-            406: 22,26
-            519: 56,-4
-            520: 57,-4
-            521: 58,-4
-            522: 59,-4
-            523: 60,-4
-            534: -3,-29
-            535: -2,-29
-            536: -1,-29
-            537: 0,-29
-            703: 70,5
-            920: -33,22
-            921: -32,22
+            398: 20,26
+            399: 21,26
+            400: 22,26
+            480: 56,-4
+            481: 57,-4
+            482: 58,-4
+            483: 59,-4
+            484: 60,-4
+            495: -3,-29
+            496: -2,-29
+            497: -1,-29
+            498: 0,-29
+            650: 70,5
+            830: -33,22
+            831: -32,22
         - node:
             color: '#C3C3C3FF'
             id: WarnLineS
           decals:
-            765: -34,-33
-            766: -36,-33
-            773: -37,-30
-            774: -37,-29
+            712: -34,-33
+            713: -36,-33
+            720: -37,-30
+            721: -37,-29
         - node:
             color: '#FF0000FF'
             id: WarnLineS
           decals:
-            669: 62,10
-            670: 62,8
-            671: 62,9
-            672: 62,7
-            673: 62,6
-            674: 62,5
-            675: 62,4
-            676: 62,3
-            677: 62,2
-            678: 62,1
-            679: 62,0
-            680: 62,-1
-            681: 62,-2
-            682: 62,-3
-            683: 62,-4
-            701: 66,2
+            616: 62,10
+            617: 62,8
+            618: 62,9
+            619: 62,7
+            620: 62,6
+            621: 62,5
+            622: 62,4
+            623: 62,3
+            624: 62,2
+            625: 62,1
+            626: 62,0
+            627: 62,-1
+            628: 62,-2
+            629: 62,-3
+            630: 62,-4
+            648: 66,2
         - node:
             color: '#FFFFFFFF'
             id: WarnLineS
           decals:
-            444: -17,-31
-            445: -17,-30
-            605: -15,18
-            606: -15,19
-            607: -15,20
-            608: -15,21
-            665: 59,7
-            666: 59,6
-            796: -19,-6
-            960: -39,17
-            961: -39,24
+            438: -17,-31
+            439: -17,-30
+            558: -15,18
+            559: -15,19
+            560: -15,20
+            561: -15,21
+            612: 59,7
+            613: 59,6
+            743: -19,-6
+            865: -39,17
+            866: -39,24
         - node:
             color: '#FF0000FF'
             id: WarnLineW
           decals:
-            684: 62,4
-            685: 63,4
-            686: 63,-1
-            687: 62,-1
-            702: 67,3
+            631: 62,4
+            632: 63,4
+            633: 63,-1
+            634: 62,-1
+            649: 67,3
         - node:
             color: '#FFFFFFFF'
             id: WarnLineW
           decals:
-            394: 21,24
-            395: 22,24
-            397: 20,24
-            918: -33,23
-            919: -32,23
+            388: 21,24
+            389: 22,24
+            391: 20,24
+            828: -33,23
+            829: -32,23
         - node:
             angle: -1.5707963267948966 rad
             color: '#FFFFFFFF'
@@ -3419,145 +3419,145 @@ entities:
             color: '#FFFFFFFF'
             id: WoodTrimThinCornerNe
           decals:
-            705: 0,1
-            830: -18,-11
-            844: 0,14
+            652: 0,1
+            774: -18,-11
+            788: 0,14
         - node:
             zIndex: 1
             color: '#FFFFFFFF'
             id: WoodTrimThinCornerNe
           decals:
-            494: -4,-6
+            455: -4,-6
         - node:
             color: '#FFFFFFFF'
             id: WoodTrimThinCornerNw
           decals:
-            704: -10,1
-            829: -21,-11
-            843: -4,14
+            651: -10,1
+            773: -21,-11
+            787: -4,14
         - node:
             color: '#FFFFFFFF'
             id: WoodTrimThinCornerSe
           decals:
-            706: 0,-7
-            831: -18,-13
-            847: 0,10
+            653: 0,-7
+            775: -18,-13
+            791: 0,10
         - node:
             color: '#FFFFFFFF'
             id: WoodTrimThinCornerSw
           decals:
-            708: -10,-2
-            832: -21,-13
-            842: -4,10
+            655: -10,-2
+            776: -21,-13
+            786: -4,10
         - node:
             color: '#FFFFFFFF'
             id: WoodTrimThinInnerSw
           decals:
-            707: -8,-2
+            654: -8,-2
         - node:
             color: '#FFFFFFFF'
             id: WoodTrimThinLineE
           decals:
-            720: 0,0
-            721: 0,-1
-            722: 0,-2
-            723: 0,-3
-            724: 0,-5
-            725: 0,-4
-            726: 0,-6
-            833: -18,-12
-            850: 0,11
-            851: 0,12
-            852: 0,13
+            667: 0,0
+            668: 0,-1
+            669: 0,-2
+            670: 0,-3
+            671: 0,-5
+            672: 0,-4
+            673: 0,-6
+            777: -18,-12
+            794: 0,11
+            795: 0,12
+            796: 0,13
         - node:
             zIndex: 1
             color: '#FFFFFFFF'
             id: WoodTrimThinLineE
           decals:
-            493: -4,-7
-            615: 27,10
-            616: 27,9
-            617: 27,8
+            454: -4,-7
+            568: 27,10
+            569: 27,9
+            570: 27,8
         - node:
             zIndex: 2
             color: '#FFFFFFFF'
             id: WoodTrimThinLineE
           decals:
-            577: 20,-12
+            534: 20,-12
         - node:
             color: '#FFFFFFFF'
             id: WoodTrimThinLineN
           decals:
-            711: -8,1
-            712: -9,1
-            713: -7,1
-            714: -6,1
-            715: -5,1
-            716: -4,1
-            717: -3,1
-            718: -2,1
-            719: -1,1
-            834: -19,-11
-            835: -20,-11
-            853: -1,14
-            854: -2,14
-            855: -3,14
+            658: -8,1
+            659: -9,1
+            660: -7,1
+            661: -6,1
+            662: -5,1
+            663: -4,1
+            664: -3,1
+            665: -2,1
+            666: -1,1
+            778: -19,-11
+            779: -20,-11
+            797: -1,14
+            798: -2,14
+            799: -3,14
         - node:
             zIndex: 1
             color: '#FFFFFFFF'
             id: WoodTrimThinLineN
           decals:
-            489: -8,-6
-            490: -7,-6
-            491: -6,-6
-            492: -5,-6
+            450: -8,-6
+            451: -7,-6
+            452: -6,-6
+            453: -5,-6
         - node:
             color: '#FFFFFFFF'
             id: WoodTrimThinLineS
           decals:
-            638: 37,0
-            639: 38,0
-            640: 39,0
-            641: 40,0
-            727: -1,-7
-            728: -2,-7
-            729: -3,-7
-            733: -9,-2
-            837: -20,-13
-            838: -19,-13
-            848: -1,10
-            849: -2,10
-            856: -3,10
+            591: 37,0
+            592: 38,0
+            593: 39,0
+            594: 40,0
+            674: -1,-7
+            675: -2,-7
+            676: -3,-7
+            680: -9,-2
+            781: -20,-13
+            782: -19,-13
+            792: -1,10
+            793: -2,10
+            800: -3,10
         - node:
             color: '#FFFFFFFF'
             id: WoodTrimThinLineW
           decals:
-            709: -10,-1
-            710: -10,0
-            730: -8,-5
-            731: -8,-4
-            732: -8,-3
-            827: -14,-12
-            828: -14,-11
-            836: -21,-12
-            839: -4,13
-            840: -4,12
-            841: -4,11
+            656: -10,-1
+            657: -10,0
+            677: -8,-5
+            678: -8,-4
+            679: -8,-3
+            771: -14,-12
+            772: -14,-11
+            780: -21,-12
+            783: -4,13
+            784: -4,12
+            785: -4,11
         - node:
             color: '#FFFF00FF'
             id: radiation
           decals:
-            655: 59,7
+            602: 59,7
         - node:
             color: '#FFFFFFFF'
             id: space
           decals:
-            986: -21,-33
+            889: -21,-33
         - node:
             color: '#010102FF'
             id: taser
           decals:
-            989: -34,19
+            890: -34,19
     - type: OccluderTree
     - type: SpreaderGrid
     - type: Shuttle
@@ -4332,7 +4332,7 @@ entities:
       pos: 3.5,22.5
       parent: 31
     - type: Door
-      secondsUntilStateChange: -32364.002
+      secondsUntilStateChange: -32451.49
       state: Opening
     - type: DeviceLinkSource
       lastSignals:
@@ -28272,18 +28272,6 @@ entities:
     - type: Transform
       pos: 24.491184,-6.41413
       parent: 31
-- proto: chem_master
-  entities:
-  - uid: 606
-    components:
-    - type: Transform
-      pos: 19.5,-0.5
-      parent: 31
-  - uid: 5075
-    components:
-    - type: Transform
-      pos: 15.5,1.5
-      parent: 31
 - proto: ChemDispenser
   entities:
   - uid: 5076
@@ -28303,6 +28291,18 @@ entities:
     - type: Transform
       pos: 18.5,1.5
       parent: 31
+- proto: ChemMaster
+  entities:
+  - uid: 606
+    components:
+    - type: Transform
+      pos: 19.5,-0.5
+      parent: 31
+  - uid: 5075
+    components:
+    - type: Transform
+      pos: 15.5,1.5
+      parent: 31
 - proto: ChessBoard
   entities:
   - uid: 841
@@ -56679,7 +56679,7 @@ entities:
     - type: Transform
       pos: 54.5,-1.5
       parent: 31
-- proto: LogicGate
+- proto: LogicGateOr
   entities:
   - uid: 11306
     components:
@@ -57997,6 +57997,13 @@ entities:
     - type: Transform
       pos: -35.5,-16.5
       parent: 31
+- proto: PlayerStationAi
+  entities:
+  - uid: 7046
+    components:
+    - type: Transform
+      pos: 49.5,-24.5
+      parent: 31
 - proto: PlushieAtmosian
   entities:
   - uid: 7433
@@ -65856,7 +65863,7 @@ entities:
     - type: Transform
       pos: 12.820141,26.438648
       parent: 31
-- proto: soda_dispenser
+- proto: SodaDispenser
   entities:
   - uid: 1418
     components:
@@ -69250,12 +69257,6 @@ entities:
     - type: Transform
       pos: -28.5,18.5
       parent: 31
-  - uid: 7046
-    components:
-    - type: Transform
-      rot: 1.5707963267948966 rad
-      pos: 49.5,-24.5
-      parent: 31
   - uid: 8138
     components:
     - type: Transform
@@ -69964,11 +69965,6 @@ entities:
       parent: 31
 - proto: ToyAi
   entities:
-  - uid: 8292
-    components:
-    - type: Transform
-      pos: 49.509567,-24.29748
-      parent: 31
   - uid: 10982
     components:
     - type: Transform
diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
index ed36325586..6c169821ab 100644
--- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
+++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml
@@ -224,6 +224,22 @@
         unshaded:
           Empty: { state: ai_empty }
           Occupied: { state: ai }
+  - type: LanguageKnowledge
+    speaks:
+    - TauCetiBasic
+    - SolCommon
+    - Tradeband
+    - Freespeak
+    - Elyran
+    - RobotTalk
+    understands:
+    - TauCetiBasic
+    - SolCommon
+    - Tradeband
+    - Freespeak
+    - Elyran
+    - RobotTalk
+    - Sign # It's intentional that they don't "Speak" sign language.
 
 # The job-ready version of an AI spawn.
 - type: entity
@@ -299,6 +315,22 @@
     - state: default
       shader: unshaded
       map: ["base"]
+  - type: LanguageKnowledge
+    speaks:
+    - TauCetiBasic
+    - SolCommon
+    - Tradeband
+    - Freespeak
+    - Elyran
+    - RobotTalk
+    understands:
+    - TauCetiBasic
+    - SolCommon
+    - Tradeband
+    - Freespeak
+    - Elyran
+    - RobotTalk
+    - Sign # It's intentional that they don't "Speak" sign language.
 
 # Borgs
 - type: entity
@@ -353,4 +385,4 @@
     slots:
       cell_slot:
         name: power-cell-slot-component-slot-name-default
-        startingItem: PowerCellHyper
\ No newline at end of file
+        startingItem: PowerCellHyper
diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
index 19e5c478d2..59e6b5fa4d 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml
@@ -40,6 +40,7 @@
     interfaces:
       enum.AtmosAlertsComputerUiKey.Key:
         type: AtmosAlertsComputerBoundUserInterface
+  - type: StationAiWhitelist
 
 - type: entity
   parent: BaseComputer
@@ -297,6 +298,7 @@
     interfaces:
       enum.PowerMonitoringConsoleUiKey.Key:
         type: PowerMonitoringConsoleBoundUserInterface
+  - type: StationAiWhitelist
 
 - type: entity
   parent: BaseComputer
@@ -677,6 +679,7 @@
     radius: 1.5
     energy: 1.6
     color: "#e6e227"
+  - type: StationAiWhitelist
 
 - type: entity
   parent: BaseComputer
@@ -790,6 +793,7 @@
   - type: GuideHelp
     guides:
     - Cargo
+  - type: StationAiWhitelist
 
 - type: entity
   id: ComputerCargoBounty
@@ -1027,6 +1031,7 @@
   - type: GuideHelp
     guides:
     - Cargo
+  - type: StationAiWhitelist
 
 - type: entity
   parent: BaseComputer
diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml
index 6090aae882..3e97255960 100644
--- a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml
+++ b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml
@@ -111,6 +111,7 @@
               collection: MetalGlassBreak
               params:
                 volume: -4
+  - type: StationAiWhitelist
 
 - type: entity
   id: AirAlarmAssembly
diff --git a/Resources/Prototypes/Maps/saltern.yml b/Resources/Prototypes/Maps/saltern.yml
index 9b26bbc3c1..26ae4a74ce 100644
--- a/Resources/Prototypes/Maps/saltern.yml
+++ b/Resources/Prototypes/Maps/saltern.yml
@@ -62,4 +62,5 @@
             Mime: [ 1, 1 ]
             Musician: [ 1, 2 ]
             Passenger: [ -1, -1 ]
-
+            #silicon
+            StationAi: [ 1, 1 ]

From 0b0e9a8892d1df6e2fb72d81f3a5b51e64fc1f5e Mon Sep 17 00:00:00 2001
From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Date: Thu, 29 Aug 2024 15:27:47 +1000
Subject: [PATCH 36/38] I managed to get both AI Latejoin and Prisoner Latejoin
 working at the same time

---
 .../Shuttles/Systems/ArrivalsSystem.cs        | 17 +++++++++-
 .../ContainerSpawnPointSystem.cs              | 24 ++++++++++----
 .../Station/Systems/StationSpawningSystem.cs  | 32 -------------------
 Content.Shared/CCVar/CCVars.cs                | 13 ++++++++
 4 files changed, 47 insertions(+), 39 deletions(-)

diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs
index 9dabf6f40a..f7b5f220e2 100644
--- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs
+++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs
@@ -10,6 +10,7 @@
 using Content.Server.Shuttles.Components;
 using Content.Server.Shuttles.Events;
 using Content.Server.Spawners.Components;
+using Content.Server.Spawners.EntitySystems;
 using Content.Server.Station.Components;
 using Content.Server.Station.Events;
 using Content.Server.Station.Systems;
@@ -20,6 +21,7 @@
 using Content.Shared.Movement.Components;
 using Content.Shared.Parallax.Biomes;
 using Content.Shared.Roles;
+using Content.Shared.Preferences;
 using Content.Shared.Salvage;
 using Content.Shared.Shuttles.Components;
 using Content.Shared.Tiles;
@@ -64,6 +66,11 @@ public sealed class ArrivalsSystem : EntitySystem
     /// </summary>
     public bool Enabled { get; private set; }
 
+    /// <summary>
+    /// Flags if all players spawning at the departure terminal have godmode until they leave the terminal.
+    /// </summary>
+    public bool ArrivalsGodmode { get; private set; }
+
     /// <summary>
     ///     The first arrival is a little early, to save everyone 10s
     /// </summary>
@@ -80,6 +87,8 @@ public override void Initialize()
     {
         base.Initialize();
 
+        SubscribeLocalEvent<PlayerSpawningEvent>(HandlePlayerSpawning, before: new []{ typeof(ContainerSpawnPointSystem), typeof(SpawnPointSystem)});
+
         SubscribeLocalEvent<StationArrivalsComponent, StationPostInitEvent>(OnStationPostInit);
 
         SubscribeLocalEvent<ArrivalsShuttleComponent, ComponentStartup>(OnShuttleStartup);
@@ -95,7 +104,10 @@ public override void Initialize()
 
         // Don't invoke immediately as it will get set in the natural course of things.
         Enabled = _cfgManager.GetCVar(CCVars.ArrivalsShuttles);
-        Subs.CVar(_cfgManager, CCVars.ArrivalsShuttles, SetArrivals);
+        ArrivalsGodmode = _cfgManager.GetCVar(CCVars.GodmodeArrivals);
+
+        _cfgManager.OnValueChanged(CCVars.ArrivalsShuttles, SetArrivals);
+        _cfgManager.OnValueChanged(CCVars.GodmodeArrivals, b => ArrivalsGodmode = b);
 
         // Command so admins can set these for funsies
         _console.RegisterCommand("arrivals", ArrivalsCommand, ArrivalsCompletion);
@@ -309,6 +321,9 @@ public void HandlePlayerSpawning(PlayerSpawningEvent ev)
         if (ev.SpawnResult != null)
             return;
 
+        if (ev.HumanoidCharacterProfile?.SpawnPriority != SpawnPriorityPreference.Arrivals)
+            return;
+
         // Only works on latejoin even if enabled.
         if (!Enabled || _ticker.RunLevel != GameRunLevel.InRound)
             return;
diff --git a/Content.Server/Spawners/EntitySystems/ContainerSpawnPointSystem.cs b/Content.Server/Spawners/EntitySystems/ContainerSpawnPointSystem.cs
index 4d38571b90..6b0033124e 100644
--- a/Content.Server/Spawners/EntitySystems/ContainerSpawnPointSystem.cs
+++ b/Content.Server/Spawners/EntitySystems/ContainerSpawnPointSystem.cs
@@ -1,8 +1,11 @@
 using Content.Server.GameTicking;
 using Content.Server.Spawners.Components;
 using Content.Server.Station.Systems;
+using Content.Shared.Preferences;
+using Content.Shared.Roles;
 using Robust.Server.Containers;
 using Robust.Shared.Containers;
+using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 
 namespace Content.Server.Spawners.EntitySystems;
@@ -11,17 +14,25 @@ public sealed class ContainerSpawnPointSystem : EntitySystem
 {
     [Dependency] private readonly GameTicker _gameTicker = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
+    [Dependency] private readonly IPrototypeManager _proto = default!;
     [Dependency] private readonly ContainerSystem _container = default!;
     [Dependency] private readonly StationSystem _station = default!;
     [Dependency] private readonly StationSpawningSystem _stationSpawning = default!;
 
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<PlayerSpawningEvent>(HandlePlayerSpawning, before: new []{ typeof(SpawnPointSystem) });
+    }
+
     public void HandlePlayerSpawning(PlayerSpawningEvent args)
     {
         if (args.SpawnResult != null)
             return;
 
-        // DeltaV - Ignore these two desired spawn types
-        if (args.DesiredSpawnPointType is SpawnPointType.Observer or SpawnPointType.LateJoin)
+        // If it's just a spawn pref check if it's for cryo (silly).
+        if (args.HumanoidCharacterProfile?.SpawnPriority != SpawnPriorityPreference.Cryosleep &&
+            (!_proto.TryIndex(args.Job?.Prototype, out var jobProto) || jobProto.JobEntity == null))
             return;
 
         var query = EntityQueryEnumerator<ContainerSpawnPointComponent, ContainerManagerComponent, TransformComponent>();
@@ -33,11 +44,12 @@ public void HandlePlayerSpawning(PlayerSpawningEvent args)
                 continue;
 
             // DeltaV - Custom override for override spawnpoints, only used for prisoners currently. This shouldn't run for any other jobs
-            if (args.DesiredSpawnPointType == SpawnPointType.Job)
+            if (args.DesiredSpawnPointType == SpawnPointType.Job
+                && spawnPoint.SpawnType == SpawnPointType.Job
+                && args.Job is not null
+                && spawnPoint.Job is not ""
+                && spawnPoint.Job == args.Job.Prototype)
             {
-                if (spawnPoint.SpawnType != SpawnPointType.Job || spawnPoint.Job != args.Job?.Prototype)
-                    continue;
-
                 possibleContainers.Add((uid, spawnPoint, container, xform));
                 continue;
             }
diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs
index 66a9554954..85f5662b42 100644
--- a/Content.Server/Station/Systems/StationSpawningSystem.cs
+++ b/Content.Server/Station/Systems/StationSpawningSystem.cs
@@ -53,19 +53,11 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
 
     private bool _randomizeCharacters;
 
-    private Dictionary<SpawnPriorityPreference, Action<PlayerSpawningEvent>> _spawnerCallbacks = new();
-
     /// <inheritdoc/>
     public override void Initialize()
     {
         base.Initialize();
         Subs.CVar(_configurationManager, CCVars.ICRandomCharacters, e => _randomizeCharacters = e, true);
-
-        _spawnerCallbacks = new Dictionary<SpawnPriorityPreference, Action<PlayerSpawningEvent>>()
-        {
-            { SpawnPriorityPreference.Arrivals, _arrivalsSystem.HandlePlayerSpawning },
-            { SpawnPriorityPreference.Cryosleep, _containerSpawnPointSystem.HandlePlayerSpawning }
-        };
     }
 
     /// <summary>
@@ -88,31 +80,7 @@ public override void Initialize()
 
         var ev = new PlayerSpawningEvent(job, profile, station, spawnPointType);
 
-        if (station != null && profile != null)
-        {
-            // Try to call the character's preferred spawner first.
-            if (_spawnerCallbacks.TryGetValue(profile.SpawnPriority, out var preferredSpawner))
-            {
-                preferredSpawner(ev);
-
-                foreach (var (key, remainingSpawner) in _spawnerCallbacks)
-                {
-                    if (key == profile.SpawnPriority)
-                        continue;
-
-                    remainingSpawner(ev);
-                }
-            }
-            else
-            {
-                // Call all of them in the typical order.
-                foreach (var typicalSpawner in _spawnerCallbacks.Values)
-                    typicalSpawner(ev);
-            }
-        }
-
         RaiseLocalEvent(ev);
-
         DebugTools.Assert(ev.SpawnResult is { Valid: true } or null);
 
         return ev.SpawnResult;
diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs
index c93eaa77f9..28055d866e 100644
--- a/Content.Shared/CCVar/CCVars.cs
+++ b/Content.Shared/CCVar/CCVars.cs
@@ -1738,6 +1738,19 @@ public static readonly CVarDef<int>
         public static readonly CVarDef<bool> ArrivalsReturns =
             CVarDef.Create("shuttle.arrivals_returns", false, CVar.SERVERONLY);
 
+        /// <summary>
+        /// Should all players who spawn at arrivals have godmode until they leave the map?
+        /// </summary>
+        public static readonly CVarDef<bool> GodmodeArrivals =
+            CVarDef.Create("shuttle.godmode_arrivals", false, CVar.SERVERONLY);
+
+        /// <summary>
+        /// If a grid is split then hide any smaller ones under this mass (kg) from the map.
+        /// This is useful to avoid split grids spamming out labels.
+        /// </summary>
+        public static readonly CVarDef<int> HideSplitGridsUnder =
+            CVarDef.Create("shuttle.hide_split_grids_under", 30, CVar.SERVERONLY);
+
         /// <summary>
         /// Whether to automatically spawn escape shuttles.
         /// </summary>

From 5242ceb33ce0c553ae5dd5924e946f1c624b4a99 Mon Sep 17 00:00:00 2001
From: VMSolidus <evilexecutive@gmail.com>
Date: Fri, 10 Jan 2025 23:24:22 -0500
Subject: [PATCH 37/38] Make AI Not Spawn With Clothes

---
 Content.Server/Traits/TraitSystem.cs                        | 3 +++
 .../Clothing/Loadouts/Systems/SharedLoadoutSystem.cs        | 2 ++
 Content.Shared/Roles/JobPrototype.cs                        | 6 ++++++
 Resources/Prototypes/Roles/Jobs/Science/borg.yml            | 4 +++-
 4 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/Content.Server/Traits/TraitSystem.cs b/Content.Server/Traits/TraitSystem.cs
index 3e0866a2ba..57103c4a5d 100644
--- a/Content.Server/Traits/TraitSystem.cs
+++ b/Content.Server/Traits/TraitSystem.cs
@@ -48,6 +48,9 @@ private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent args)
     {
         var pointsTotal = _configuration.GetCVar(CCVars.GameTraitsDefaultPoints);
         var traitSelections = _configuration.GetCVar(CCVars.GameTraitsMax);
+        if (args.JobId is not null && !_prototype.TryIndex<JobPrototype>(args.JobId, out var jobPrototype)
+            && jobPrototype is not null && !jobPrototype.ApplyTraits)
+            return;
 
         foreach (var traitId in args.Profile.TraitPreferences)
         {
diff --git a/Content.Shared/Clothing/Loadouts/Systems/SharedLoadoutSystem.cs b/Content.Shared/Clothing/Loadouts/Systems/SharedLoadoutSystem.cs
index e759c904af..865908c706 100644
--- a/Content.Shared/Clothing/Loadouts/Systems/SharedLoadoutSystem.cs
+++ b/Content.Shared/Clothing/Loadouts/Systems/SharedLoadoutSystem.cs
@@ -75,6 +75,8 @@ private void OnMapInit(EntityUid uid, LoadoutComponent component, MapInitEvent a
         var failedLoadouts = new List<EntityUid>();
         var allLoadouts = new List<(EntityUid, LoadoutPreference, int)>();
         heirlooms = new();
+        if (!job.SpawnLoadout)
+            return (failedLoadouts, allLoadouts);
 
         foreach (var loadout in profile.LoadoutPreferences)
         {
diff --git a/Content.Shared/Roles/JobPrototype.cs b/Content.Shared/Roles/JobPrototype.cs
index 8b21ffef20..5ea9da0224 100644
--- a/Content.Shared/Roles/JobPrototype.cs
+++ b/Content.Shared/Roles/JobPrototype.cs
@@ -134,6 +134,12 @@ public sealed partial class JobPrototype : IPrototype
 
         [DataField]
         public bool Whitelisted;
+
+        [DataField]
+        public bool SpawnLoadout = true;
+
+        [DataField]
+        public bool ApplyTraits = true;
     }
 
     /// <summary>
diff --git a/Resources/Prototypes/Roles/Jobs/Science/borg.yml b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
index 0c60faccfa..91ee25357e 100644
--- a/Resources/Prototypes/Roles/Jobs/Science/borg.yml
+++ b/Resources/Prototypes/Roles/Jobs/Science/borg.yml
@@ -13,6 +13,8 @@
   supervisors: job-supervisors-rd
   jobEntity: StationAiBrain
   nameDataset: NamesAI
+  spawnLoadout: false
+  applyTraits: false
 
 - type: job
   id: Borg
@@ -25,4 +27,4 @@
   canBeAntag: false
   icon: JobIconBorg
   supervisors: job-supervisors-rd
-  jobEntity: PlayerBorgGeneric
\ No newline at end of file
+  jobEntity: PlayerBorgGeneric

From 14f738d43f622fbf158b35acb85ca3884cf16090 Mon Sep 17 00:00:00 2001
From: SimpleStation Changelogs <SimpleStation14@users.noreply.github.com>
Date: Sat, 11 Jan 2025 04:39:56 +0000
Subject: [PATCH 38/38] Automatic Changelog Update (#1423)

---
 Resources/Changelog/Changelog.yml | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 78bc7a56f2..3152a61643 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -9537,3 +9537,12 @@ Entries:
   id: 6659
   time: '2025-01-11T00:13:27.0000000+00:00'
   url: https://github.com/Simple-Station/Einstein-Engines/pull/1450
+- author: sleepyyapril
+  changes:
+    - type: Add
+      message: Ported Station AI.
+    - type: Add
+      message: Saltern is now fitted with a Station AI
+  id: 6660
+  time: '2025-01-11T04:39:29.0000000+00:00'
+  url: https://github.com/Simple-Station/Einstein-Engines/pull/1423