diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs
index 48256031b0..c052a17946 100644
--- a/Content.Client/Entry/IgnoredComponents.cs
+++ b/Content.Client/Entry/IgnoredComponents.cs
@@ -348,7 +348,8 @@ namespace Content.Client.Entry
"HealthAnalyzer",
"Thirst",
"CanEscapeInventory",
- "Wires"
+ "PowerSink",
+ "Wires",
};
}
}
diff --git a/Content.Server/PowerSink/PowerSinkComponent.cs b/Content.Server/PowerSink/PowerSinkComponent.cs
new file mode 100644
index 0000000000..4654205a38
--- /dev/null
+++ b/Content.Server/PowerSink/PowerSinkComponent.cs
@@ -0,0 +1,8 @@
+namespace Content.Server.PowerSink
+{
+ ///
+ /// Absorbs power up to its capacity when anchored then explodes.
+ ///
+ [RegisterComponent]
+ public sealed class PowerSinkComponent : Component {}
+}
diff --git a/Content.Server/PowerSink/PowerSinkSystem.cs b/Content.Server/PowerSink/PowerSinkSystem.cs
new file mode 100644
index 0000000000..f72713e52e
--- /dev/null
+++ b/Content.Server/PowerSink/PowerSinkSystem.cs
@@ -0,0 +1,56 @@
+using Content.Server.Explosion.EntitySystems;
+using Content.Server.Power.Components;
+using Content.Shared.Body.Events;
+using Content.Shared.Examine;
+using Robust.Shared.Utility;
+
+namespace Content.Server.PowerSink
+{
+ public sealed class PowerSinkSystem : EntitySystem
+ {
+ [Dependency] private readonly ExplosionSystem _explosionSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnExamine);
+ }
+
+ private void OnExamine(EntityUid uid, PowerSinkComponent component, ExaminedEvent args)
+ {
+ if (!args.IsInDetailsRange || !TryComp(uid, out var consumer))
+ return;
+
+ var drainAmount = (int) consumer.NetworkLoad.ReceivingPower / 1000;
+ args.PushMarkup(
+ Loc.GetString(
+ "powersink-examine-drain-amount",
+ ("amount", drainAmount),
+ ("markupDrainColor", "orange"))
+ );
+ }
+
+ public override void Update(float frameTime)
+ {
+ var toRemove = new RemQueue<(PowerSinkComponent Sink, BatteryComponent Battery)>();
+
+ // Realistically it's gonna be like <5 per station.
+ foreach (var (comp, networkLoad, battery, xform) in EntityManager.EntityQuery())
+ {
+ if (!xform.Anchored) continue;
+
+ battery.CurrentCharge += networkLoad.NetworkLoad.ReceivingPower / 1000;
+ if (battery.CurrentCharge < battery.MaxCharge) continue;
+
+ toRemove.Add((comp, battery));
+ }
+
+ foreach (var (comp, battery) in toRemove)
+ {
+ _explosionSystem.QueueExplosion(comp.Owner, "Default", 5 * (battery.MaxCharge / 2500000), 0.5f, 10, canCreateVacuum: false);
+ EntityManager.RemoveComponent(comp.Owner, comp);
+ }
+ }
+ }
+}
diff --git a/Resources/Locale/en-US/powersink/powersink.ftl b/Resources/Locale/en-US/powersink/powersink.ftl
new file mode 100644
index 0000000000..2d5b73be19
--- /dev/null
+++ b/Resources/Locale/en-US/powersink/powersink.ftl
@@ -0,0 +1 @@
+powersink-examine-drain-amount = The power sink is draining [color={$markupDrainColor}]{$amount} kW[/color].
diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml
index 71bac31e75..305c0ea1ec 100644
--- a/Resources/Prototypes/Catalog/uplink_catalog.yml
+++ b/Resources/Prototypes/Catalog/uplink_catalog.yml
@@ -255,6 +255,12 @@
itemId: ClothingBackpackDuffelSyndicateFilledMedical
price: 5
+- type : uplinkListing
+ id: UplinkPowerSink
+ category: Tools
+ itemId: PowerSink
+ price: 5
+
- type: uplinkListing
id: UplinkCarpDehydrated
category: Tools
diff --git a/Resources/Prototypes/Entities/Objects/Power/powersink.yml b/Resources/Prototypes/Entities/Objects/Power/powersink.yml
new file mode 100644
index 0000000000..a2db90d32a
--- /dev/null
+++ b/Resources/Prototypes/Entities/Objects/Power/powersink.yml
@@ -0,0 +1,46 @@
+- type: entity
+ id: PowerSink
+ parent: BaseMachine
+ name: power sink
+ description: Drains immense amounts of electricity from the grid.
+ components:
+ - type: Item
+ size: 150
+ - type: NodeContainer
+ examinable: true
+ nodes:
+ input:
+ !type:CableDeviceNode
+ nodeGroupID: HVPower
+ - type: Transform
+ anchored: true
+ - type: Physics
+ - type: Fixtures
+ fixtures:
+ - shape:
+ !type:PhysShapeAabb
+ bounds: "-0.40,-0.40,0.40,0.40"
+ mass: 15
+ mask:
+ - MachineMask
+ layer:
+ - MachineLayer
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 25
+ behaviors:
+ - !type:DoActsBehavior
+ acts: [ "Destruction" ]
+ - type: PowerSink
+ - type: Battery
+ maxCharge: 7500000
+ - type: ExaminableBattery
+ - type: PowerConsumer
+ voltage: High
+ drawRate: 1000000
+ - type: Sprite
+ netsync: false
+ sprite: Objects/Power/powersink.rsi
+ state: powersink
diff --git a/Resources/Textures/Objects/Power/powersink.rsi/meta.json b/Resources/Textures/Objects/Power/powersink.rsi/meta.json
new file mode 100644
index 0000000000..d85868d1db
--- /dev/null
+++ b/Resources/Textures/Objects/Power/powersink.rsi/meta.json
@@ -0,0 +1,14 @@
+{
+ "version": 1,
+ "license": "CC-BY-NC-SA-3.0",
+ "copyright": "Taken from goonstation at commit https://github.com/goonstation/goonstation/commit/17c4392b75abd87a0f740e116c44dd4c7dfff6f7",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "powersink"
+ }
+ ]
+}
diff --git a/Resources/Textures/Objects/Power/powersink.rsi/powersink.png b/Resources/Textures/Objects/Power/powersink.rsi/powersink.png
new file mode 100644
index 0000000000..9a8db0358a
Binary files /dev/null and b/Resources/Textures/Objects/Power/powersink.rsi/powersink.png differ