From 4f9ae1116e9319c06f725b306ea0dae82c1529df Mon Sep 17 00:00:00 2001
From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Date: Sat, 22 Apr 2023 03:03:50 -0400
Subject: [PATCH] Lipid Extractor (#15597)
---
.../Components/FatExtractorComponent.cs | 94 ++++++++++
.../EntitySystems/FatExtractorSystem.cs | 164 ++++++++++++++++++
Content.Shared/Lock/LockComponent.cs | 6 +
Content.Shared/Lock/LockSystem.cs | 4 +-
.../Components/SharedFatExtractor.cs | 16 ++
.../nutrition/components/fat-extractor.ftl | 8 +
.../Catalog/Research/technologies.yml | 1 +
.../Advertisements/fatextractor.yml | 9 +
.../Circuitboards/Machine/production.yml | 17 ++
.../Structures/Machines/fatextractor.yml | 113 ++++++++++++
.../Entities/Structures/Machines/lathe.yml | 1 +
.../Prototypes/Recipes/Lathes/electronics.yml | 8 +
.../Machines/fat_sucker.rsi/fat.png | Bin 0 -> 804 bytes
.../Machines/fat_sucker.rsi/fat_door_off.png | Bin 0 -> 407 bytes
.../Machines/fat_sucker.rsi/fat_door_on.png | Bin 0 -> 462 bytes
.../Machines/fat_sucker.rsi/fat_green.png | Bin 0 -> 191 bytes
.../Machines/fat_sucker.rsi/fat_panel.png | Bin 0 -> 195 bytes
.../Machines/fat_sucker.rsi/fat_red.png | Bin 0 -> 188 bytes
.../Machines/fat_sucker.rsi/fat_smoke.png | Bin 0 -> 534 bytes
.../Machines/fat_sucker.rsi/fat_stack.png | Bin 0 -> 224 bytes
.../Machines/fat_sucker.rsi/fat_yellow.png | Bin 0 -> 190 bytes
.../Machines/fat_sucker.rsi/meta.json | 47 +++++
22 files changed, 486 insertions(+), 2 deletions(-)
create mode 100644 Content.Server/Nutrition/Components/FatExtractorComponent.cs
create mode 100644 Content.Server/Nutrition/EntitySystems/FatExtractorSystem.cs
create mode 100644 Content.Shared/Nutrition/Components/SharedFatExtractor.cs
create mode 100644 Resources/Locale/en-US/nutrition/components/fat-extractor.ftl
create mode 100644 Resources/Prototypes/Catalog/VendingMachines/Advertisements/fatextractor.yml
create mode 100644 Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_door_off.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_door_on.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_green.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_panel.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_red.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_smoke.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_stack.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/fat_yellow.png
create mode 100644 Resources/Textures/Structures/Machines/fat_sucker.rsi/meta.json
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 0000000000000000000000000000000000000000..cbd63ae3eeca4685ae30d26740ab87c205a6c40b
GIT binary patch
literal 804
zcmV+<1Ka$GP)ovdj-rdt9&tsLS
zf?9Sy|MK;FCkW>Xa1yN6G=l)bV>X8v81t7FYN5PV0A78PxcsWIDpUa=$YWN)s|n53
ztL8~kZ<{G+0NiI20Oq_pHp2fXW3x}Z0l48<+!N;N;!Mr?8i2X0C2btD(@$EXGofqd
zDmiv!G#sk|K*x@ch~vzwS+c3KD?=aNJa>v)Ut3L#alQpE&DPF*0f5z?I65p(PEtC0
zboWj)!2NpFi~A!s04ud=gK^7*>)&3fVJhf!Ea0ju<|s`p{2#(Wz=~v8sI>_*&wdHV0*qH
z>;tO)1m^IWDntPIG$G7?H-3U6k1Awj(1nZVoVI3PA#Wf7Apu|xh-$qm%(*AhQZxVfW^4sm+#69JqdvlS
z0`5QZ@rw_NtN^42VUq2$%%+9KWv$VXAO9mOfb!t|0AY+k(EkqvcfXli0yMk7S$-I@
zu{wsf@9Y=H?<-%drX0(qSM%^#0DP^LY4r4%xG?>+AYL4}*y>h6tWJh@^!8f;zSTEc
z$A9K(PDoYw>nD1BrbAlNbWR{o@2lQXgYB=Xu&bFjp)@egm2yTmf|@NirevU&%=l
iz$SB&3f0CuO@9G-`H058j|@@(0000VQ!Pj5=V{0VFw~pk?8I7<)oZJR>#KlN>BaP{_MB!}Pzr!U-KFg4J?tA^|}0CEH}`1bWHS>}-K0Bu!S
z6i0Azb7RPZLV#ut09k(Y@JWUTx9>41s48L5!~%-4Auh{7w6(1{Z5)6c?6@pP4gvJE
zLa_s2aSx(F0OnJ48kPn?^zD0(sOJEfj|k-gSOTPa2v8f)+yR8j2eKT19H**Ea$x%D
z%eM^D;=*t?48X*w>HuVmVGaUW1aky3n-Cz|0U%3}9f9m?QUFy#00dyZri%m6EeG*I
zi48f(i3xs^9RO-nOkK7gYdZi`8R1It_!=)HhX5=GpoaoBKuna7>;RZ=qB1+cAt5F$
z36BDprLUeo2eX$=uOQfLBRdfiV>mHj_!q^5008xhqF#b?bf*9S002ovPDHLkV1n2a
BmyQ4c
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..a47692a251e973c81a1f5a30894646403bd369b1
GIT binary patch
literal 462
zcmV;<0WtoGP)VQ!Pj5=V{0VFw~pk?8I7<)oZJR>#KlN>BaP{_MB!}Pzr!U-KFg4J?tA^|}0CEH}`1bWHS>}-K0Bu!S
zh6l&4!TH>1@(Na3;1Hmh13;F`KUl-y@ZX-{0OLUhhv)=`14|dc=?4rU3=CXMv~vIm
zIP?WF94K0kVL8ZA3yCy?WCtL}J&NU^kU(+-11JO-Fw+Xf4gkeH$WTxmgMxYC(J#OV
z4}tm^!3W8|2Bra!`rG#&QO^M|AAxC6Ubr}VE_e-1fK(3wY6F@(fKd5BmIILER8>h1
zOh0}3mO)xv7|w5+ZfNU|$K_H7@jzDG;0%SV?WGS*EkbO-Gph^gU0L<5PaR9pI
zAU-IuAqP1z!B4USK#hv2%l2b!2XJw7<4p1R8ZRV=04xWfhXOW0Oq7u90GMy0GCRN_
zAto&ej{=ybubw^!vzJY;AlPgpI}s9NI5A-O7sZ4C0Bwh=JhkU{iU0rr07*qoM6N<$
Ef;3>O>Hq)$
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..d971f3d6c092d2a27872e0a8f45d174fad4fbbe1
GIT binary patch
literal 191
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C|Ky}
z;uumf=k4W%f(-^dtq;HOxg~P=m?vA|o&7H^RpIoC{l^gTb3%1s=jqqHH=ayu>>UG>FVdQ&MBb@0Ct2y(f|Me
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..7062b2646fde72065f511a60d3b551a9ed5eef57
GIT binary patch
literal 195
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C|K(0
z;uumf=k1k^yax<8SR5v7npppzGeM21v)kpR;!)+u6IbVNeCpiR&A`N=&;TYH>KS~(
zLgIIZ#6&ZS_VM(-x%*I@!CK^*X=8!MdzN{#-+d525H>g7>1w)Kz(KL^$uf)~iOLr&
lTF=`ztkj;N#dM5O-MK?H^6f5$nLr0Hc)I$ztaD0e0sxBnKp_AC
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..c3f17feffc6d990835f56932a68114ad8d2d5259
GIT binary patch
literal 188
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D46Hz
z;uumf=k4XQybTHhE)NwqN_cNzn7vV6ShJ038_Vv-H-ei#vdPsHw;ZlHeST3tGf)o*
z%-~vaD?7+j@ql@MZs<1S%z$}MWe=Rz-#yh-Z@v11$^AOte@xhPX{~Q9^Tn_KUW-T
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..0a5575dbbbaf59bda743c3ad74c688675874484d
GIT binary patch
literal 534
zcmeAS@N?(olHy`uVBq!ia0vp^4nUm1!3HGP9xZtRq&N#aB8wRq_>O=u<5X=vX$A(y
z6P_-PAr*7p&N}FK*g(LAePy`7eNOSbj_CZ3X#Ed!IqVi>Obpw!#^T;Bzo_hIb8j7s
zynX)LvY>AaMYCA;?2|n&|Ni*yz_;r>CpX-m|NhmJH@mh-T+*n2xI_F}
z{t~_g>hBaU-MGK~YeQ@P=QE|1QJtqu_yWE!y<>7$SRm
zeZ|>Nta|a6-%sP1K>Y3n(;t4E>+NFMro`T$v$G`Y{r}t7^$b>INg5o;NYY(?gHd5a
z{$(Y%70D74GIv=v1R1<)2xRZEO1Q$fm`|egzzSwJS%eVtI|hc(-P&Ag^D7&Hu4C|Y
L^>bP0l+XkKXp&Hs
literal 0
HcmV?d00001
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 0000000000000000000000000000000000000000..b1546fc397ed4a911488a1f9391836f85044590c
GIT binary patch
literal 190
zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C|Ka>
z;uumf=k4W