From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Date: Sat, 22 Apr 2023 07:03:50 +0000 (-0400)
Subject: Lipid Extractor (#15597)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=4f9ae1116e9319c06f725b306ea0dae82c1529df;p=space-station-14.git
Lipid Extractor (#15597)
---
diff --git a/Content.Server/Nutrition/Components/FatExtractorComponent.cs b/Content.Server/Nutrition/Components/FatExtractorComponent.cs
new file mode 100644
index 0000000000..8a0826c29c
--- /dev/null
+++ b/Content.Server/Nutrition/Components/FatExtractorComponent.cs
@@ -0,0 +1,94 @@
+using Content.Server.Nutrition.EntitySystems;
+using Content.Shared.Construction.Prototypes;
+using Content.Shared.Nutrition.Components;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Nutrition.Components;
+
+///
+/// This is used for a machine that extracts hunger from entities and creates meat. Yum!
+///
+[RegisterComponent, Access(typeof(FatExtractorSystem))]
+public sealed class FatExtractorComponent : Component
+{
+ ///
+ /// Whether or not the extractor is currently extracting fat from someone
+ ///
+ [DataField("processing")]
+ public bool Processing = true;
+
+ ///
+ /// How much nutrition is extracted per second.
+ ///
+ [DataField("nutritionPerSecond"), ViewVariables(VVAccess.ReadWrite)]
+ public int NutritionPerSecond = 10;
+
+ ///
+ /// The base rate of extraction
+ ///
+ [DataField("baseNutritionPerSecond"), ViewVariables(VVAccess.ReadWrite)]
+ public int BaseNutritionPerSecond = 10;
+
+ #region Machine Upgrade
+ ///
+ /// Which machine part affects the nutrition rate
+ ///
+ [DataField("machinePartNutritionRate", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string MachinePartNutritionRate = "Laser";
+
+ ///
+ /// The increase in rate per each rating above 1.
+ ///
+ [DataField("partRatingRateMultiplier")]
+ public float PartRatingRateMultiplier = 10;
+ #endregion
+
+ ///
+ /// An accumulator which tracks extracted nutrition to determine
+ /// when to spawn a meat.
+ ///
+ [DataField("nutrientAccumulator"), ViewVariables(VVAccess.ReadWrite)]
+ public int NutrientAccumulator;
+
+ ///
+ /// How high has to be to spawn meat
+ ///
+ [DataField("nutrientPerMeat"), ViewVariables(VVAccess.ReadWrite)]
+ public int NutrientPerMeat = 60;
+
+ ///
+ /// Meat spawned by the extractor.
+ ///
+ [DataField("meatPrototype", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)]
+ public string MeatPrototype = "FoodMeat";
+
+ ///
+ /// When the next update will occur
+ ///
+ [DataField("nextUpdate", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
+ public TimeSpan NextUpdate;
+
+ ///
+ /// How long each update takes
+ ///
+ [DataField("updateTime"), ViewVariables(VVAccess.ReadWrite)]
+ public TimeSpan UpdateTime = TimeSpan.FromSeconds(1);
+
+ ///
+ /// The sound played when extracting
+ ///
+ [DataField("processSound")]
+ public SoundSpecifier? ProcessSound;
+
+ public IPlayingAudioStream? Stream;
+
+ ///
+ /// A minium hunger threshold for extracting nutrition.
+ /// Ignored when emagged.
+ ///
+ [DataField("minHungerThreshold")]
+ public HungerThreshold MinHungerThreshold = HungerThreshold.Okay;
+}
diff --git a/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs b/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs
new file mode 100644
index 0000000000..6ab432d490
--- /dev/null
+++ b/Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs
@@ -0,0 +1,164 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using Content.Server.Construction;
+using Content.Server.Nutrition.Components;
+using Content.Server.Power.Components;
+using Content.Server.Power.EntitySystems;
+using Content.Server.Storage.Components;
+using Content.Shared.Emag.Components;
+using Content.Shared.Emag.Systems;
+using Content.Shared.Nutrition.Components;
+using Content.Shared.Nutrition.EntitySystems;
+using Content.Shared.Storage.Components;
+using Robust.Shared.Timing;
+
+namespace Content.Server.Nutrition.EntitySystems;
+
+///
+/// This handles logic and interactions relating to
+///
+public sealed class FatExtractorSystem : EntitySystem
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly HungerSystem _hunger = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+
+ ///
+ public override void Initialize()
+ {
+ SubscribeLocalEvent(OnRefreshParts);
+ SubscribeLocalEvent(OnUpgradeExamine);
+ SubscribeLocalEvent(OnUnpaused);
+ SubscribeLocalEvent(OnGotEmagged);
+ SubscribeLocalEvent(OnClosed);
+ SubscribeLocalEvent(OnOpen);
+ SubscribeLocalEvent(OnPowerChanged);
+ }
+
+ private void OnRefreshParts(EntityUid uid, FatExtractorComponent component, RefreshPartsEvent args)
+ {
+ var rating = args.PartRatings[component.MachinePartNutritionRate] - 1;
+ component.NutritionPerSecond = component.BaseNutritionPerSecond + (int) (component.PartRatingRateMultiplier * rating);
+ }
+
+ private void OnUpgradeExamine(EntityUid uid, FatExtractorComponent component, UpgradeExamineEvent args)
+ {
+ args.AddPercentageUpgrade("fat-extractor-component-rate", (float) component.NutritionPerSecond / component.BaseNutritionPerSecond);
+ }
+
+ private void OnUnpaused(EntityUid uid, FatExtractorComponent component, ref EntityUnpausedEvent args)
+ {
+ component.NextUpdate += args.PausedTime;
+ }
+
+ private void OnGotEmagged(EntityUid uid, FatExtractorComponent component, ref GotEmaggedEvent args)
+ {
+ args.Handled = true;
+ args.Repeatable = false;
+ }
+
+ private void OnClosed(EntityUid uid, FatExtractorComponent component, ref StorageAfterCloseEvent args)
+ {
+ StartProcessing(uid, component);
+ }
+
+ private void OnOpen(EntityUid uid, FatExtractorComponent component, ref StorageAfterOpenEvent args)
+ {
+ StopProcessing(uid, component);
+ }
+
+ private void OnPowerChanged(EntityUid uid, FatExtractorComponent component, ref PowerChangedEvent args)
+ {
+ if (!args.Powered)
+ StopProcessing(uid, component);
+ }
+
+ public void StartProcessing(EntityUid uid, FatExtractorComponent? component = null, EntityStorageComponent? storage = null)
+ {
+ if (!Resolve(uid, ref component, ref storage))
+ return;
+
+ if (component.Processing)
+ return;
+
+ if (!this.IsPowered(uid, EntityManager))
+ return;
+
+ if (!TryGetValidOccupant(uid, out _, component, storage))
+ return;
+
+ component.Processing = true;
+ _appearance.SetData(uid, FatExtractorVisuals.Processing, true);
+ component.Stream = _audio.PlayPvs(component.ProcessSound, uid);
+ component.NextUpdate = _timing.CurTime + component.UpdateTime;
+ }
+
+ public void StopProcessing(EntityUid uid, FatExtractorComponent? component = null)
+ {
+ if (!Resolve(uid, ref component))
+ return;
+
+ if (!component.Processing)
+ return;
+
+ component.Processing = false;
+ _appearance.SetData(uid, FatExtractorVisuals.Processing, false);
+ component.Stream?.Stop();
+ }
+
+ public bool TryGetValidOccupant(EntityUid uid, [NotNullWhen(true)] out EntityUid? occupant, FatExtractorComponent? component = null, EntityStorageComponent? storage = null)
+ {
+ occupant = null;
+ if (!Resolve(uid, ref component, ref storage))
+ return false;
+
+ occupant = storage.Contents.ContainedEntities.FirstOrDefault();
+
+ if (!TryComp(occupant, out var hunger))
+ return false;
+
+ if (hunger.CurrentHunger < component.NutritionPerSecond)
+ return false;
+
+ if (hunger.CurrentThreshold < component.MinHungerThreshold && !HasComp(uid))
+ return false;
+
+ return true;
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var fat, out var storage))
+ {
+ if (TryGetValidOccupant(uid, out var occupant, fat, storage))
+ {
+ if (!fat.Processing)
+ StartProcessing(uid, fat, storage);
+ }
+ else
+ {
+ StopProcessing(uid, fat);
+ continue;
+ }
+
+ if (!fat.Processing)
+ continue;
+
+ if (_timing.CurTime < fat.NextUpdate)
+ continue;
+ fat.NextUpdate += fat.UpdateTime;
+
+ _hunger.ModifyHunger(occupant.Value, -fat.NutritionPerSecond);
+ fat.NutrientAccumulator += fat.NutritionPerSecond;
+ if (fat.NutrientAccumulator >= fat.NutrientPerMeat)
+ {
+ fat.NutrientAccumulator -= fat.NutrientPerMeat;
+ Spawn(fat.MeatPrototype, Transform(uid).Coordinates);
+ }
+ }
+ }
+}
diff --git a/Content.Shared/Lock/LockComponent.cs b/Content.Shared/Lock/LockComponent.cs
index d8c0963830..fae5788612 100644
--- a/Content.Shared/Lock/LockComponent.cs
+++ b/Content.Shared/Lock/LockComponent.cs
@@ -34,6 +34,12 @@ public sealed class LockComponent : Component
///
[DataField("lockingSound"), ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier LockSound = new SoundPathSpecifier("/Audio/Machines/door_lock_on.ogg");
+
+ ///
+ /// Whether or not an emag disables it.
+ ///
+ [DataField("breakOnEmag")]
+ public bool BreakOnEmag = true;
}
[Serializable, NetSerializable]
diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs
index 2af6366982..79a0e26fbd 100644
--- a/Content.Shared/Lock/LockSystem.cs
+++ b/Content.Shared/Lock/LockSystem.cs
@@ -203,7 +203,7 @@ public sealed class LockSystem : EntitySystem
private bool HasUserAccess(EntityUid uid, EntityUid user, AccessReaderComponent? reader = null, bool quiet = true)
{
// Not having an AccessComponent means you get free access. woo!
- if (!Resolve(uid, ref reader))
+ if (!Resolve(uid, ref reader, false))
return true;
if (_accessReader.IsAllowed(user, reader))
@@ -234,7 +234,7 @@ public sealed class LockSystem : EntitySystem
private void OnEmagged(EntityUid uid, LockComponent component, ref GotEmaggedEvent args)
{
- if (!component.Locked)
+ if (!component.Locked || !component.BreakOnEmag)
return;
_audio.PlayPredicted(component.UnlockSound, uid, null, AudioParams.Default.WithVolume(-5));
_appearanceSystem.SetData(uid, StorageVisuals.Locked, false);
diff --git a/Content.Shared/Nutrition/Components/SharedFatExtractor.cs b/Content.Shared/Nutrition/Components/SharedFatExtractor.cs
new file mode 100644
index 0000000000..b52e1a9022
--- /dev/null
+++ b/Content.Shared/Nutrition/Components/SharedFatExtractor.cs
@@ -0,0 +1,16 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Nutrition.Components;
+
+[Serializable, NetSerializable]
+public enum FatExtractorVisuals : byte
+{
+ Processing
+}
+
+public enum FatExtractorVisualLayers : byte
+{
+ Light,
+ Stack,
+ Smoke
+}
diff --git a/Resources/Locale/en-US/nutrition/components/fat-extractor.ftl b/Resources/Locale/en-US/nutrition/components/fat-extractor.ftl
new file mode 100644
index 0000000000..b2df0e079e
--- /dev/null
+++ b/Resources/Locale/en-US/nutrition/components/fat-extractor.ftl
@@ -0,0 +1,8 @@
+fat-extractor-component-rate = extraction rate
+
+fat-extractor-fact-1 = Fats are triglycerides made up of a combination of different building blocks; glycerol and fatty acids.
+fat-extractor-fact-2 = Adults should get a recommended 20-35% of their energy intake from fat.
+fat-extractor-fact-3 = Being overweight or obese puts you at an increased risk of chronic diseases, such as cardiovascular diseases, metabolic syndrome, type 2 diabetes, and some types of cancers.
+fat-extractor-fact-4 = Not all fats are bad. A certain amount of fat is an essential part of a healthy balanced diet.
+fat-extractor-fact-5 = Saturated fat should form no more than 11% of your daily calories.
+fat-extractor-fact-6 = Unsaturated fat, that is monounsaturated fats, polyunsaturated fats, and omega-3 fatty acids, is found in plants and fish.
\ No newline at end of file
diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml
index bfbae68d97..8641bc892e 100644
--- a/Resources/Prototypes/Catalog/Research/technologies.yml
+++ b/Resources/Prototypes/Catalog/Research/technologies.yml
@@ -61,6 +61,7 @@
- MicrowaveMachineCircuitboard
- BoozeDispenserMachineCircuitboard
- SodaDispenserMachineCircuitboard
+ - FatExtractorMachineCircuitboard
# Biological Technology Tree
diff --git a/Resources/Prototypes/Catalog/VendingMachines/Advertisements/fatextractor.yml b/Resources/Prototypes/Catalog/VendingMachines/Advertisements/fatextractor.yml
new file mode 100644
index 0000000000..4e8b3eb88e
--- /dev/null
+++ b/Resources/Prototypes/Catalog/VendingMachines/Advertisements/fatextractor.yml
@@ -0,0 +1,9 @@
+- type: advertisementsPack
+ id: FatExtractorFacts
+ advertisements:
+ - fat-extractor-fact-1
+ - fat-extractor-fact-2
+ - fat-extractor-fact-3
+ - fat-extractor-fact-4
+ - fat-extractor-fact-5
+ - fat-extractor-fact-6
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
index 4ace8ea4f0..7df228de48 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
@@ -673,6 +673,23 @@
Glass: 2
Cable: 2
+- type: entity
+ id: FatExtractorMachineCircuitboard
+ parent: BaseMachineCircuitboard
+ name: lipid extractor machine board
+ components:
+ - type: Sprite
+ state: service
+ - type: MachineBoard
+ prototype: FatExtractor
+ requirements:
+ Laser: 1
+ componentRequirements:
+ Utensil:
+ Amount: 1
+ DefaultPrototype: ForkPlastic
+ ExamineName: Utensil
+
- type: entity
id: EmitterCircuitboard
parent: BaseMachineCircuitboard
diff --git a/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml b/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml
new file mode 100644
index 0000000000..3914f5e5e2
--- /dev/null
+++ b/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml
@@ -0,0 +1,113 @@
+- type: entity
+ id: FatExtractor
+ parent: BaseMachinePowered
+ name: lipid extractor
+ description: Safely and efficiently extracts excess fat from a subject.
+ components:
+ - type: FatExtractor
+ processSound:
+ path: /Audio/Machines/microwave_loop.ogg
+ params:
+ loop: true
+ maxdistance: 5
+ - type: Sprite
+ netsync: false
+ sprite: Structures/Machines/fat_sucker.rsi
+ snapCardinals: true
+ layers:
+ - state: fat
+ - state: fat_door_off
+ map: ["enum.StorageVisualLayers.Door"]
+ - state: fat_red
+ shader: unshaded
+ map: ["enum.PowerDeviceVisualLayers.Powered"]
+ - state: fat_green
+ shader: unshaded
+ visible: false
+ map: ["enum.FatExtractorVisualLayers.Light"]
+ - state: fat_panel
+ visible: false
+ map: ["enum.WiresVisualLayers.MaintenancePanel"]
+ - state: fat_stack #cash cash cash
+ visible: false
+ map: ["enum.FatExtractorVisualLayers.Stack"]
+ - state: fat_smoke
+ visible: false
+ map: ["enum.FatExtractorVisualLayers.Smoke"]
+ - type: Lock
+ breakOnEmag: false
+ - type: GenericVisualizer
+ visuals:
+ enum.StorageVisuals.Open:
+ enum.StorageVisualLayers.Door:
+ True: { visible: false }
+ False: { visible: true }
+ enum.FatExtractorVisuals.Processing:
+ enum.StorageVisualLayers.Door:
+ True: { state: fat_door_on }
+ False: { state: fat_door_off }
+ enum.FatExtractorVisualLayers.Smoke:
+ True: { visible: true }
+ False: { visible: false }
+ enum.FatExtractorVisualLayers.Stack:
+ True: { visible: true }
+ False: { visible: false }
+ enum.FatExtractorVisualLayers.Light:
+ True: { visible: true }
+ False: { visible: false }
+ enum.PowerDeviceVisuals.Powered:
+ enum.FatExtractorVisualLayers.Light:
+ False: { visible: false }
+ enum.PowerDeviceVisualLayers.Powered:
+ True: { visible: true }
+ False: { visible: false }
+ enum.StorageVisuals.HasContents:
+ enum.PowerDeviceVisualLayers.Powered:
+ True: { state: fat_yellow }
+ False: { state: fat_red }
+ enum.WiresVisuals.MaintenancePanelState:
+ enum.WiresVisualLayers.MaintenancePanel:
+ True: { visible: true }
+ False: { visible: false }
+ - type: Construction
+ graph: Machine
+ node: machine
+ containers:
+ - machine_board
+ - machine_parts
+ - entity_storage
+ - type: EmptyOnMachineDeconstruct
+ containers:
+ - entity_storage
+ - type: Damageable
+ damageContainer: Inorganic
+ damageModifierSet: StrongMetallic
+ - type: Destructible
+ thresholds:
+ - trigger:
+ !type:DamageTrigger
+ damage: 100
+ behaviors:
+ - !type:ChangeConstructionNodeBehavior
+ node: machineFrame
+ - !type:DoActsBehavior
+ acts: ["Destruction"]
+ - type: Machine
+ board: FatExtractorMachineCircuitboard
+ - type: Wires
+ BoardName: FatExtractor
+ LayoutId: FatExtractor
+ - type: Appearance
+ - type: Speech
+ - type: Advertise
+ pack: FatExtractorFacts
+ - type: StaticPrice
+ price: 1000
+ - type: ResistLocker
+ - type: EntityStorage
+ capacity: 1
+ - type: ContainerContainer
+ containers:
+ machine_board: !type:Container
+ machine_parts: !type:Container
+ entity_storage: !type:Container
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 62a89a3dda..18bae43997 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -300,6 +300,7 @@
- ReagentGrinderMachineCircuitboard
- HotplateMachineCircuitboard
- MicrowaveMachineCircuitboard
+ - FatExtractorMachineCircuitboard
- UniformPrinterMachineCircuitboard
- ShuttleConsoleCircuitboard
- RadarConsoleCircuitboard
diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml
index 468c0e5a56..5cb7cf7c5d 100644
--- a/Resources/Prototypes/Recipes/Lathes/electronics.yml
+++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml
@@ -424,6 +424,14 @@
Steel: 100
Glass: 900
+- type: latheRecipe
+ id: FatExtractorMachineCircuitboard
+ result: FatExtractorMachineCircuitboard
+ completetime: 4
+ materials:
+ Steel: 100
+ Glass: 900
+
- type: latheRecipe
id: SurveillanceCameraRouterCircuitboard
result: SurveillanceCameraRouterCircuitboard
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat.png
new file mode 100644
index 0000000000..cbd63ae3ee
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_door_off.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_door_off.png
new file mode 100644
index 0000000000..c8cfe3b0a8
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_door_off.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_door_on.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_door_on.png
new file mode 100644
index 0000000000..a47692a251
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_door_on.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_green.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_green.png
new file mode 100644
index 0000000000..d971f3d6c0
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_green.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_panel.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_panel.png
new file mode 100644
index 0000000000..7062b2646f
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_panel.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_red.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_red.png
new file mode 100644
index 0000000000..c3f17feffc
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_red.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_smoke.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_smoke.png
new file mode 100644
index 0000000000..0a5575dbbb
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_smoke.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_stack.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_stack.png
new file mode 100644
index 0000000000..64c5f5aba2
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_stack.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_yellow.png b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_yellow.png
new file mode 100644
index 0000000000..b1546fc397
Binary files /dev/null and b/Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_yellow.png differ
diff --git a/Resources/Textures/Structures/Machines/fat_sucker.rsi/meta.json b/Resources/Textures/Structures/Machines/fat_sucker.rsi/meta.json
new file mode 100644
index 0000000000..5100252ae9
--- /dev/null
+++ b/Resources/Textures/Structures/Machines/fat_sucker.rsi/meta.json
@@ -0,0 +1,47 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "taken from /tg/station at commit https://github.com/tgstation/tgstation/commit/48370e5a35a19eab427d3e403b653e65fa391ca2",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "fat"
+ },
+ {
+ "name": "fat_door_off"
+ },
+ {
+ "name": "fat_door_on"
+ },
+ {
+ "name": "fat_green"
+ },
+ {
+ "name": "fat_yellow"
+ },
+ {
+ "name": "fat_red"
+ },
+ {
+ "name": "fat_stack"
+ },
+ {
+ "name": "fat_smoke",
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.4
+ ]
+ ]
+ },
+ {
+ "name": "fat_panel"
+ }
+ ]
+}
\ No newline at end of file