From 3d7908411e6edac161d3c4ea675601b61db035d7 Mon Sep 17 00:00:00 2001
From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com>
Date: Thu, 20 Apr 2023 00:55:41 -0400
Subject: [PATCH 1/7] Started work on what used to be a "SiliconFiller", but
 now is a tool to inject blood into people. Lots of work to be done.

---
 .../Components/SiliconFillerComponent.cs      |  20 +++
 .../Silicon/Systems/SiliconFillerSystem.cs    | 146 ++++++++++++++++++
 .../Chemistry/syringe.rsi/1-inhand-left.png   | Bin 316 -> 314 bytes
 .../Chemistry/syringe.rsi/1-inhand-right.png  | Bin 320 -> 316 bytes
 .../Chemistry/syringe.rsi/2-inhand-left.png   | Bin 316 -> 317 bytes
 .../Chemistry/syringe.rsi/2-inhand-right.png  | Bin 320 -> 326 bytes
 .../Chemistry/syringe.rsi/3-inhand-left.png   | Bin 322 -> 316 bytes
 .../Chemistry/syringe.rsi/3-inhand-right.png  | Bin 315 -> 318 bytes
 .../Chemistry/syringe.rsi/4-inhand-left.png   | Bin 321 -> 323 bytes
 .../Chemistry/syringe.rsi/4-inhand-right.png  | Bin 321 -> 323 bytes
 .../Chemistry/syringe.rsi/syringe1.png        | Bin 131 -> 151 bytes
 .../Chemistry/syringe.rsi/syringe2.png        | Bin 131 -> 170 bytes
 .../Chemistry/syringe.rsi/syringe3.png        | Bin 131 -> 180 bytes
 .../Chemistry/syringe.rsi/syringe4.png        | Bin 153 -> 195 bytes
 .../Chemistry/syringe.rsi/syringe_base0.png   | Bin 331 -> 264 bytes
 .../Chemistry/syringe.rsi/syringe_base1.png   | Bin 331 -> 268 bytes
 .../Chemistry/syringe.rsi/syringe_base2.png   | Bin 338 -> 275 bytes
 .../Chemistry/syringe.rsi/syringe_base3.png   | Bin 330 -> 265 bytes
 .../Chemistry/syringe.rsi/syringe_base4.png   | Bin 284 -> 254 bytes
 19 files changed, 166 insertions(+)
 create mode 100644 Content.Server/SimpleStation14/Silicon/Components/SiliconFillerComponent.cs
 create mode 100644 Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs

diff --git a/Content.Server/SimpleStation14/Silicon/Components/SiliconFillerComponent.cs b/Content.Server/SimpleStation14/Silicon/Components/SiliconFillerComponent.cs
new file mode 100644
index 0000000000..4b6415dbf4
--- /dev/null
+++ b/Content.Server/SimpleStation14/Silicon/Components/SiliconFillerComponent.cs
@@ -0,0 +1,20 @@
+namespace Content.Server.SimpleStation14.Silicon.Components;
+
+[RegisterComponent]
+public sealed class BloodstreamFillerComponent : Component
+{
+    /// <summary>
+    /// The name of the volume to refill.
+    /// </summary>
+    /// <remarks>
+    /// Should match the <see cref="SolutionContainerComponent"/> name or otherwise.
+    /// </remarks>
+    [DataField("solution"), ViewVariables(VVAccess.ReadWrite)]
+    public string Solution { get; } = "filler";
+
+    /// <summary>
+    ///     The amount of reagent that this silicon filler will fill with at most.
+    /// </summary>
+    [DataField("amount"), ViewVariables(VVAccess.ReadWrite)]
+    public float Amount = 100.0f;
+}
diff --git a/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs b/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs
new file mode 100644
index 0000000000..5287a1f7b5
--- /dev/null
+++ b/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs
@@ -0,0 +1,146 @@
+using Content.Server.Body.Components;
+using Content.Server.DoAfter;
+using Content.Server.SimpleStation14.Silicon.Components;
+using Content.Shared.DoAfter;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Content.Shared.SimpleStation14.Silicon.Components;
+
+using Content.Server.Body.Systems;
+using Content.Server.Chemistry.Components;
+using Content.Server.Chemistry.EntitySystems;
+using Content.Shared.FixedPoint;
+
+namespace Content.Server.SimpleStation14.Silicon.Systems;
+
+public sealed class BloodstreamFillerSystem : EntitySystem
+{
+    [Dependency] private readonly DoAfterSystem _doAfter = default!;
+    [Dependency] private readonly BloodstreamSystem _bloodSystem = default!;
+    [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<BloodstreamFillerComponent, AfterInteractEvent>(OnUseInWorld);
+        SubscribeLocalEvent<BloodstreamFillerComponent, UseInHandEvent>(OnUseInHand);
+
+        SubscribeLocalEvent<BloodstreamFillerComponent, DoAfterEvent>(OnDoAfter);
+    }
+
+    private void OnUseInWorld(EntityUid uid, BloodstreamFillerComponent component, AfterInteractEvent args)
+    {
+        if (!args.CanReach || args.Target == null)
+            return;
+
+        if (!EntityManager.TryGetComponent<BloodstreamComponent>(args.Target, out var bloodComp))
+        {
+            TryRefill(uid, args.Target.Value, component);
+            return;
+        }
+
+        TryFill(args.User, args.Target.Value, args.Used, component);
+    }
+
+    private void OnUseInHand(EntityUid uid, BloodstreamFillerComponent component, UseInHandEvent args)
+    {
+        if (!EntityManager.TryGetComponent<BloodstreamComponent>(args.User, out var bloodComp))
+            return;
+
+        TryFill(args.User, args.User, uid, component);
+    }
+
+    private void TryFill(EntityUid user, EntityUid target, EntityUid filler, BloodstreamFillerComponent fillComp)
+    {
+        var bloodComp = EntityManager.GetComponent<BloodstreamComponent>(target);
+
+        if (!_solutionSystem.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution) ||
+            fillerSolution.Contents.Count != 1 || // Extra dorty
+            fillerSolution.Contents[0].ReagentId != bloodComp.BloodReagent)
+            return;
+
+        var delay = 2.5f;
+        if (user == target)
+            delay *= 3.5f;
+
+        _doAfter.DoAfter(new DoAfterEventArgs(user, delay, target: target, used: filler)
+        {
+            RaiseOnTarget = true,
+            RaiseOnUser = false,
+            BreakOnUserMove = true,
+            BreakOnDamage = true,
+            BreakOnStun = true,
+            BreakOnTargetMove = true,
+            MovementThreshold = 0.2f
+        });
+    }
+
+    private void OnDoAfter(EntityUid uid, BloodstreamFillerComponent component, DoAfterEvent args)
+    {
+        if (args.Cancelled)
+        {
+            return;
+        }
+
+        if (args.Handled || args.Args.Target == null)
+            return;
+
+        Fill(args.Args.Target.Value, args.Args.Used!.Value, component);
+
+        args.Handled = true;
+    }
+
+    private void Fill(EntityUid target, EntityUid filler, BloodstreamFillerComponent fillComp)
+    {
+        if (!_solutionSystem.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution))
+            return;
+
+        var bloodComp = EntityManager.GetComponent<BloodstreamComponent>(target);
+
+        var tansfAmount = FixedPoint2.Min(bloodComp.BloodSolution.AvailableVolume, Math.Min((float) fillerSolution.Volume, fillComp.Amount));
+
+        if (tansfAmount > 0)
+        {
+            var drained = _solutionSystem.SplitSolution(filler, fillerSolution, tansfAmount);
+
+            _bloodSystem.TryModifyBloodLevel(target, drained.Volume, bloodComp);
+            // _audioSystem.PlayPvs(welder.WelderRefill, welderUid);
+            // _popupSystem.PopupCursor(Loc.GetString("welder-component-after-interact-refueled-message"), user);
+        }
+    }
+
+    private void TryRefill(EntityUid filler, EntityUid target, BloodstreamFillerComponent fillComp)
+    {
+        if (!EntityManager.TryGetComponent<ReagentTankComponent>(target, out var tankComp))
+            return;
+
+        // Check that the tank has one, and only one reagent.
+        if (!_solutionSystem.TryGetDrainableSolution(target, out var targetSolution)||
+            targetSolution.Contents.Count > 1) // Dorty
+            return;
+
+        // Check that the filler has one, and only one reagent, and that it's the same as the tank.
+        if (!_solutionSystem.TryGetSolution(filler, (string) fillComp.Solution!, out var fillerSolution) ||
+            fillerSolution.Contents.Count > 1 || // Extra dorty
+            (fillerSolution.Contents.Count > 0 && fillerSolution.Contents[0].ReagentId != targetSolution.Contents[0].ReagentId))
+            return;
+
+        var tansfAmount = FixedPoint2.Min(fillerSolution.AvailableVolume, targetSolution.Volume);
+        if (tansfAmount > 0)
+        {
+            var drained = _solutionSystem.Drain(target, targetSolution,  tansfAmount);
+            _solutionSystem.TryAddSolution(filler, fillerSolution, drained);
+            // _audioSystem.PlayPvs(welder.WelderRefill, welderUid);
+            // _popupSystem.PopupCursor(Loc.GetString("welder-component-after-interact-refueled-message"), user);
+        }
+        else if (fillerSolution.AvailableVolume <= 0)
+        {
+            // _popupSystem.PopupCursor(Loc.GetString("welder-component-already-full"), user);
+        }
+        else
+        {
+            // _popupSystem.PopupCursor(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", target)), user);
+        }
+    }
+}
diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/1-inhand-left.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/1-inhand-left.png
index 0f1f04747227f06e5c0c56f604645d6041d860c8..fc2247ba5e3be21e70713012999c0281fc6e0ac0 100644
GIT binary patch
literal 314
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1FeX
zi(^Q|oVT+K`I-#`SlBh?A3wD@+bOz8B$Ma4tK;s=0Y9He^X*QMpCQbM6D=0H@a_4h
z^sRLP{towRQXlggYBBD8d2HLkUGvs|iq)_DE&G&3=l8SoevZ{^r<?wJ*ya4emiM?y
zi2dBeb-P&m%!)lf&y8uuX*{yc#pR4o-!vF0Ed00MT-ADkK)`v{9s^Af<1CP&YrTNi
vBSXb!?MgcqQDK9v&+g_o8VNR7LXiKWP#FP^gth;G{$}uW^>bP0l+XkKw^3`!

delta 268
zcmdnRw1;VeW&Jx(7srr_Id5+{ave6{VZCVh#cl6@!6G%&xE80)o?0gb{?)Hu=VG(t
zqf(vXIYxo!3?0P`M=Tj0$uJc1HCV7a%wbjl3SSp`AS-xV;`4J23Gv@H-zr5n`$aM3
z+)w8%5`2^%w{zY812vB{=3QU(S+>CD%l_R8yQ}pgKML8D9j>2yR44M!mRBM>cF$1l
zo?pYGgxeCh-SgxWYReaBAL#0zty<1*#T0Undxui!0%eD9aR)?GH}BT>C~?u4d-Jc*
mn;VQvjpx^KErB_B2mj{HvZXaSTiO_az|+-_)n%PiLK6V+mTw3E

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/1-inhand-right.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/1-inhand-right.png
index c55b8d6fd657be61855017749620e8cdac9d6df8..c999a4c65ae3481d1445992542057403e42b6c81 100644
GIT binary patch
delta 268
zcmX@Ww1;VeW&Jx(7srr_Id5+{@--`nxL(Y@)Vs52dYfui61xKLg(u(l8oxXtl2>2a
zpnt@Y;gJkOAzy<9yTcr2g>#Go&lx(389>5OOiMl&EA~AzwP*D>GVOYNZvg*>+zsml
zUSB`|sp@j>U)QY+FKY|8^xoHf{%mz{0M`c#t45j20XO_L>ksVD`S<B7%ZUQ8K{(8Z
z3cuK6_h>h>yqoU<eZJu3HSYNh&x(KK9WUqUH%MZdb?%|HZ*_R$6W<M0eD@Py-Ov6K
ooN&x(`Mu~r5-t$;s>>&^pEQ#dlo#5Y%K!wPu70d8>zopr054v0S^xk5

delta 272
zcmdnPbbx7sW&I~l7srr_Id5+|@--`nxL$O>BwPC5JHdC$wFwphEexGs_8Grev39=n
zQAYiPmJJVN918dpEZ7C+Fms$^WO>feRLlSp&SF|p?$xEpqWj1?zw7so?Z)?6J#M?l
zq`$RquiXB#`|x!;rfkt0&wWkfby#<-{a#S{?UB_wrZxM1)Gw|vpR?|{)`9&xcG>%w
z4RDx`B3xB>r-<)=NGxO2xrgjCihA$4FZd->H{qe6+Z)Ev=O5-S`}_Tb?}iG#`-!g}
roBq-@NWQSLx;wrZ>eLU6c8z*+Wr`Q;au^sGI2k-${an^LB{Ts5S;}@k

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/2-inhand-left.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/2-inhand-left.png
index 0f1f04747227f06e5c0c56f604645d6041d860c8..54307dc06908161ac503300e2a19eced6a9c693f 100644
GIT binary patch
literal 317
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1HE{
zi(^Q|oVT+a`3@NfFslpMKl<<gz?a+6)#=eBvqIO@^Glbz+<a+Py&`{xFe6U1SSaB3
z=D#=N>{nPXkgt38pjBdOLtM$-)fHPFf306Teb3*%P0Y8-ek_g+SpRj?A^SOnocne+
z)(WNB&rLixi>bQXa_JAhV+zk)7zm@7*aIbH4w4fB{@;(DBpbjn;~Z<x1}*Ca0tU0W
zB@!dc9Hb^VC?~$0_sToqBBS^BJ-<X|s4*F+gVA%&>p6-pUB=S{fL>?tboFyt=akR{
E0N%!T1ONa4

delta 268
zcmdnXw1;VeW&Jx(7srr_Id5+{ave6{VZCVh#cl6@!6G%&xE80)o?0gb{?)Hu=VG(t
zqf(vXIYxo!3?0P`M=Tj0$uJc1HCV7a%wbjl3SSp`AS-xV;`4J23Gv@H-zr5n`$aM3
z+)w8%5`2^%w{zY812vB{=3QU(S+>CD%l_R8yQ}pgKML8D9j>2yR44M!mRBM>cF$1l
zo?pYGgxeCh-SgxWYReaBAL#0zty<1*#T0Undxui!0%eD9aR)?GH}BT>C~?u4d-Jc*
mn;VQvjpx^KErB_B2mj{HvZXaSTiO_az|+-_)n%PiLK6V<x^D{r

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/2-inhand-right.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/2-inhand-right.png
index c55b8d6fd657be61855017749620e8cdac9d6df8..afd31cbeb483b80eb36c20390bee82f4257ad198 100644
GIT binary patch
delta 278
zcmX@Wbc|_&W&ICN7srr_Id5+{@*PqTalLr^i0sb)syo!Cw5j!GYO?JUyl*Y+zO3Ny
z*5)GTIm`;@7zLg)bQCijv1E88!%)cAV8QMH6kez5pf#U+@{Z+G<WBFpbJ{eX)x&2+
zj@{|k>)lqcRZLy7^-2H9*SWtwW-)$}IJ@oR-rToWH7&RcEUoH=Z!UXSV4u$TFZJ{6
zesza7oK_%gc6k1MxwZ9&yelj<k5jWwm{u{b$&V|4&T(i;Hc!7n64SIzKTl|KSg$tt
z<iFvU+&<?QZ%uz`3T(V^q55>cBh=xa80WpIR&q7s-?Z420SG)@{an^LB{Ts5ukd+L

delta 272
zcmX@cbbx7sW&I~l7srr_Id5+|@--`nxL$O>BwPC5JHdC$wFwphEexGs_8Grev39=n
zQAYiPmJJVN918dpEZ7C+Fms$^WO>feRLlSp&SF|p?$xEpqWj1?zw7so?Z)?6J#M?l
zq`$RquiXB#`|x!;rfkt0&wWkfby#<-{a#S{?UB_wrZxM1)Gw|vpR?|{)`9&xcG>%w
z4RDx`B3xB>r-<)=NGxO2xrgjCihA$4FZd->H{qe6+Z)Ev=O5-S`}_Tb?}iG#`-!g}
roBq-@NWQSLx;wrZ>eLU6c8z*+Wr`Q;au^sGI2k-${an^LB{Ts5WNLOu

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/3-inhand-left.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/3-inhand-left.png
index 3bbc9fe6839a6bb11a5086fae0cb79bd543437f2..5fe7f1f943db2452f4f1973914461a1d503169d9 100644
GIT binary patch
literal 316
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1G3n
zi(^Q|oVT+K`3@@xu&`^|pZY(4g84*+Ko_s%-w`6&<x=5u-W`+Rde2;}#DEipF#W38
zX21Gta}K*r_4BK@GWK1nm|q&OQ0T(34_BY<zjm5O<9vhJ?ESmAf2Hqzch$d4rYX5&
zv(T#f=Mu~AGNrfQH2R}(UE!Gv17UP0*1^(x0guOu|L=8A@@cS~aOQ0ey~)_xkfry4
z<MbxxOARbioZi{1_#Kb(MMQmmx7}eT$ALKzWM20|TUd9E)dHZ;89ZJ6T-G@yGywon
CFLt>A

literal 322
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1FYV
zi(^Q|oVT+axegofupGZ2|MkEBi`iEsgfzBXST>0#vE0v+^ZkMd_SbC|VhuQvF4H@~
zj}pmseN9ChuO_b!4}9G##%TPf?uCN-Lk@rO*!>4?9A2*ZW=Vg^J;vh;|G#a@`Tplf
zmv=#%g>;(dkCUr33(U?;`XJozcw{33VYG8s!<Tms(;GzlXRGdJmSyt##<cIFkX`Bm
zXNNNV2jYveQkPXbE^>CtJp0aj!(wKy?6_L4C2)f)nV#L#a#^>xHW}!D22WQ%mvv4F
FO#oNkfnfju

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/3-inhand-right.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/3-inhand-right.png
index 71ecded6f6b4872f9268f8097ba3ffc3c1e8a308..cba15421ff0a47b0fe25f406029c8510cd9ec0ba 100644
GIT binary patch
delta 236
zcmdnZw2x_mW&H<F7srr_Id5+{@--QVusu}#=yvZv$GnwZM_9zC%(~<{_y6r3O5b`#
z#h$jsFeyxDIHAf=#Myw#ye_mLXFm7mjJVH{4MqB`$Biz($-lkpy1><=;mmK^=C3`l
ziSPcW$5)xATtB**ci;A$!{Oxz0~;={HJ(_?)pxkEkLl0p5AyaC52%K}*i(0`oPA%(
z`-W@9Ke%~*_T6JR`~1URx7K}+<Svx(-Os$Sn=AYt%j)MJWZVAjU027|6Y=80|1h~`
eh_mL{9T1*+N#}6})3b97K;Y@>=d#Wzp$Py{-*W)~

delta 239
zcmdnTw3}&yW&K-E7srr_Id5-9^EDZWusu{PbbnXRxn^Zn%Mo#nCAm!J{_pL6?z6+@
zOJfX^!gPicstiS(4XDg=6^F`chirU>%|FiDe&&ARYUArnYfcxd&##=mlY1)1RqF>C
zC%b1(d%F4?Q^@PsJ66Bn$wf21+xKVvdAZr#zjIiBOn(}_{5?bO#0%mR?{J4@{QNkx
z_{Zuju7YPW`<fO1U;M=(W7qzENp*|d`v&LdA9~wjcR%+o_%5^W;DzI>zlSFrS>SwM
g_a~1M#C5+I^py%VMHB_kMlt|_r>mdKI;Vst01r)X=l}o!

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/4-inhand-left.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/4-inhand-left.png
index 2d4447acb7207a094a364cb231fc7a5350d2f7af..2a0575895cd17f8d8042c0e68592333371885634 100644
GIT binary patch
literal 323
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1Gj#
zi(^Q|oVT+axegl$Fdx4l|MkEBi`jQ1f;gT`x}xno;n@^#vG)n<`LA&oD>2|iDopqG
ze)rFQyjgV0>uB3;Riaz{JXm_3eRnN?rt)W&d+RHXEf@d1dBp$!G>=BQ!)@{Z@AY1+
z%B@d1Dj?%~XR1MUiQeW{Vmof1ne>c(C!3)<lL0~W{3X+}&CFVi+H&UJo0z#6KLs3K
zpk=*4z+g7_4yVX62dN1T$_uwFtK!fqbI3fq{65oV7lvmLRKxh~o5`c7e_<bh0l?tt
L>gTe~DWM4fpRsXc

literal 321
zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1G*-
zi(^Q|oVT+axegofupGZ2|MkEBi`iEsggCxTx)SGnV{WjX;3b7<_SdbJf(<y45aat*
zzqVYnzui)>^=NXpx$-rBA;!HwY+ok%916723UOcX^^yBz`@j0e3-&PIn)hdaY{05*
z_M0CGy>Y!W)u5_GZ*vyc9o;m~k8^t*&vY^nMwPo79^Pe~+929LJGhKpgsF@5%q`gf
z4hx~6vV&XhGQMnLk>U(aUZwBo%I?$q^NXf|4@-g{7@ZUU-()B(bKw65p!XR(UHx3v
IIVCg!06Cm`J^%m!

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/4-inhand-right.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/4-inhand-right.png
index fa55e86eb97cf04d88a24bb2698eef0dec06b57c..92d9a14b1f979f13f15f0b6698cce7829d4683c0 100644
GIT binary patch
delta 275
zcmX@ebeL&^W&KxA7srr_Id5-y^Bq!<aDC|fsPE2yp<QY^8+~O?Xges~`+c_ek9!9D
z4~IF-3g;LFo-=e5GaRvGcqGG6$k$-O4ia9c>QHm+grHM`@bjw2ALH^$&u(S-{^5<v
z+V4^2ON16mJV^ermut>z-^1JgR4ipET%P;ibw`{2yQY|iSM}F!ddyO`_SZYGpQrxy
zJw_uWV{zDaj?vBTPBH)g)on~)?i}{t@Wk4!-{G_EpB14C(`}e%y?e;6`+NPNGwlf<
w<?0SxdTjbzcSF)b@AK2*o1rd$!n}uJf3kVw5wmu79tI%rboFyt=akR{09OHfPyhe`

delta 249
zcmX@ibdYI+W&LMQ7srr_Id5-z^Bq!<aDC|fsPE2yp<QY^8+~O?Xges~`+YX_pYj%F
zxsGCnBbE%0WEcwh8Z6iy<}fRqV-$GK021EH(s5qG(upJIQB1zgz0+&g?G$?;H*fBe
zuW_&YLX<?9Yk2mDHx}>B{4vdby@<lQEpPX8T>o%1b^>?6T>&d;&*GHlCs}_?f0%#Q
z+M#XYMd>)Gv6cr;v{%1-SbsI3VP5qQ&S`&+y%5aU*FHa`szvgA!?Nlhj;HrkKXcwt
u!Ec}N^5d+(Vi6lJEKNVX-Vy4~PmFQwKaDq4-)B!|00K`}KbLh*2~7aVL39uR

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe1.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe1.png
index 74cfa72ab4831e7514d2eeb8180dae0d69d6f858..82af39342e6ed658647dfe4105d8af9c5c9dc425 100644
GIT binary patch
delta 122
zcmZo>oX$8wrI@q8BeIx*f$s<iGfvg!lV)IG@bq+X45^s&_ToWK1_KTj$JU5G`QPgg
zP7}&e<m}k++g@Ua>RCphIw1JWICJM&pF6S941x<=cigStxj<lT!*qxo0|UF&b54n?
SpE|yR1Uy~+T-G@yGywolVkk8L

delta 102
zcmV-s0Ga=n0fPaMBwtENL_t(|obAv%3cxT71W_xe^jXJ;TX!K{R2TwbUZZC9L1Rdg
zB&i8VlANAf-QaV1Rki!xT;1SW>#o4@PqY95GUxo}07?3#4FkLz9fEf#bN~PV07*qo
IM6N<$g0p}tX#fBK

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe2.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe2.png
index 74cfa72ab4831e7514d2eeb8180dae0d69d6f858..1e952a5d308646fd936612ed734917a2218dec37 100644
GIT binary patch
delta 142
zcmZo>T*Wv+rJl3EBeIx*f$s<iGfvg!lV)IGi1BoB45^s&_ToX#0|p!pfy}W-S?|=d
ziC>7lG(#{cQ}a*##}~r-KP`Ytf#AXahMlV{!`3q^C3$U5ZrJ_)=}gU4RVB6D32BQ3
mOqT|}X1)6~_kb`XM78;^<HBo#nh&soxSs5;elF{r5}E+(Q8M2E

delta 102
zcmV-s0Ga=)0fPaMBwtENL_t(|obAv%3cxT71W_xe^jXJ;TX!K{R2TwbUZZC9L1Rdg
zB&i8VlANAf-QaV1Rki!xT;1SW>#o4@PqY95GUxo}07?3#4FkLz9fEf#bN~PV07*qo
IM6N<$g1Ztcd;kCd

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe3.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe3.png
index 9aa237b1364439229cd4fc3efad57fa474e9e433..64e3e409d5cfe86ae7a386950ceac701ea38357c 100644
GIT binary patch
delta 152
zcmZo>+`>3PrJl3EBeIx*f$s<iGfvg!lV)IGNb_`Y45^s&_WVI!21O2+K(m`+84drk
z7cjnPVv4a{!`g6h#+m&EbB=qrGXqrvLBnsxwdU_G-{v#e>~{20L;an*oil^)FK1k3
yWxu{>Ipg9E1wqZ;<&4^G-VIY3!8!_LJ}|QX5ff~6cS$q=iFmsDxvX<aXaWE+fi@oi

delta 102
zcmV-s0Ga=^0fPaMBwtENL_t(|obAxD4ZtuA13`_+S${dYGN3FVAqKB;`IM_7A|m3C
z0NeIz{926z24+Uwcz*#)ni<e9moyu%`u@OpypLFmM?^g904~FAlk(<HX8-^I07*qo
IM6N<$f{|D%)&Kwi

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe4.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe4.png
index d8b7e8a701b086365b192639d62dc4ce25b167f9..d6c2e08ff197a4172f1c484b0f6f3d9141e1b89f 100644
GIT binary patch
delta 167
zcmbQqc$jg5N<C+RM`SSr1K$x4W}K?cC(XdXQ0nR87*a9k?UjwZ2NZZ*0^Lt(#Wnm*
zPhi~K%B~O~v2<&%km6m_DgSpqTsEH_s2&8KGyl3#vwq`wMx{%dI}HvzT5Fp0?84VX
zhqa}#^E%rZ#KJ?hmM(deci{IY*+TOKH}$0OJG=%g3b}WF$_s+@JCyOO`YN^BDBfNO
O;(EIJxvX<aXaWE|v_3=t

delta 124
zcmV-?0E7R-0hs}iBz0g(L_t(|obA-X4Zt7_13;_0We3li441yBP@Y9iq{{b!pB)4M
zA|fJ(+&xL=SoqRjVh=wlalH*UGeiUcAR?aq=j!Anv+W+#aCh$y-`Ca`Fm~+A*yOdu
e=*J@>@=G^IccH;N_qR*{0000<MNUMnLSTYgp*Pb2

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base0.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base0.png
index 9cf92274d4b7ad8e567d67704611d6289cfab32f..55e8e6081d30b269ca376a88720dbc63c26122f3 100644
GIT binary patch
delta 237
zcmV<J022Sp0*C^TBYyx1a7bBm000ie000ie0hKEb8vp<Rx=BPqRCt{2)IkcuFc3!J
z1bUi+P(k!aJwtZ|PvI(O$T5^c3x!^%`h$U4xR@~$12VH|HsyUKX&P5~3}65Q{5POG
zT=r$X`zioVycmERF9MLnRRIX&DT%89Quugk-8^mL_p<<qBW8?2T>AA{0K~`Z(8m~W
zE@Qp|(0B;JOAlTaKr=1|XvbNA6nV!VnsF8&#j$?H&zf--fFkg#X~tOqdc$eQSpd2P
nB@pZ___Y2RpyU|900wvhTS16;M&o~w00000NkvXXu0mjf<7!?Z

delta 305
zcmV-10nYx20?PuBBYy!BNkl<Zc%1E(KMKMy7{#B(V@S~x)S*&vaFmW&3T`evfw+si
z)YZWoxHt;k3RM)B;sKQ6Is6=KOVEndnpCh4LXsuF_x(u%l=^p7L<2O#q<9@{SHgKu
z;c0sSP~_Q3S2gbeKbvA^+2r~g(hM^h(hTtMS7&^^2Q<T^PJdg+a4^nPlH4`pqwMz>
zy!9T(@SM3Ha%Z5S)&Kw#X9RD(N2jeP#)Q<J7qe`_EsGV+Fv*$D9-zWZ+{5GfT>~GL
zfLS&z7jq>7T!QUN-h-AFIk!e+O3dBQ0v9F@t`q`yrn98cq{0E9+3FIrY$^l}0It8G
z*hJc0&!bG=@hV{#pk7yTI)wlvf4fpsUBXLvslU_}fg6@HnMdU)00000NkvXXu0mjf
D!5@p`

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base1.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base1.png
index 2d455682f40660b7f1c31e2b33ec407c2f74203f..6cae5f27fde4fedc503ab09cd8fc747995c5491d 100644
GIT binary patch
delta 241
zcmV<N01p4l0*nHXBYyx1a7bBm000ie000ie0hKEb8vp<RzDYzuRCt{2)X@opKn#Fk
z3r<rgSdexkXYj4y6h7SyH-;i82wmrDz(9~bBwkKIav<u1{9imY&rV(jFn|HB4JaP(
zFwNcV6aXil48V;i0Z8Ji00_fb5?29W_*vewarla#j{<C7cWRJM9|eFoOuZbzIVTQB
z0U-Wq>dJfH;{BfKcL8V|CXb1W0orjE03&O>*Nn3O7>Da6{?d%I02Be=xn`UNpno{+
rI150xAO(WG1^=!O1EgFAFn|Gmu9=2%o}rGS00000NkvXXu0mjfrxsp4

delta 305
zcmV-10nYx60?PuBBYy!BNkl<Zc%1E&zY2m-7{yQGV}#ff*iZ-!jpFDcw6*vI(H`xg
zYeR3)(ipf2Dn(25073K~UqfE8QnKt`0zDvCLGJH-e}P7ISBp15(@kRU$K94YuMnR1
z4FHljJNc5UUhuamwrq#|FeXhm(?^(rEd1RaKkoreH)%NNVShTAmnuo+nq{LLk1Pby
z0q4uLbU#$iKu2i<02b~HL3F@y&`XVRse4wI?GWxkNSbbv>n&fP+)O;f+4-q~ul9gt
zJG5D^S`3iXTg+0+i<}u@|8SfA0=UGz*%;jQmT9dMxGW6LPT`RQK(}u^?D)KK<0?Ol
zDQn`F@KR%V+A1HRstN#uR8;{RK_L>F>IUAx8`V-bJv5U%WxRcf00000NkvXXu0mjf
D&2Wtb

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base2.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base2.png
index b898840c308b1475ade399d2d90ac0873d02b1f4..a81f1c6ff2b804579ebbeba8392f81531a9fd0a7 100644
GIT binary patch
delta 248
zcmV<U00;ll0+RxeBYyx1a7bBm000ie000ie0hKEb8vp<R#Ysd#RCt{2)=>(BFbsg<
z3Z6y~CJa2%&agMZQ~1;~^cVxd!C=>^=AjV!U=xxeND9L#jQ`U(v2_<O0~o*n_Xa%r
zF@Ara<`MuUUJXEvR{?P1ssISXmJ?S2r10?U+_wJNzZU_r%W)mKXD<S9XRQjz;}Q%T
z05O>N@rmC1MtUV!0EkWV`xQc1(!O*IML>$+xW<{20VxjOwc{iJM!^4EGfoEJF=)n%
yfc)`V191w#^T)@W;v(IIuHw4)E13ZdKv_GmcY<=JLlVXS0000<MNUMnLSTX)NorUC

delta 312
zcmV-80muH60@4DIBYy!INkl<Zc${Nk7zHC8Fw)ureRGfhF!sfhJ7{hnPRp_J85kHC
znCRym?0|(*0|spn2ZW~l-+lD>e|>WgIHsEekS!-<2G!GmzPZPLJ1Y~0lA=bUqJ-i&
zL-u8SL;%B~V`mudKYBuRdZ0K26y;<X7#J8Bdiv@a4jntgV1H+20(Tfq;vE?Tgr@vw
zfOvvQ-`wMWU;hjYOKIi^bjx8hsSY433Iak?{%=@4hZ$<Y--{=AFq2~rSpb{Qk=P7S
zN6{wl2ZW~l@9Uod4{oUCEHqDS=#IeUbDCO;&c~MGX$A~T-7qYoYq0M=di*~&M^FP0
zRUKbGb&)|qK{1Yjfx+#+f`S~whShWESMAa@s7EaywR{weNB{s96OGa;4pdeE0000<
KMNUMnLSTZhy@aFy

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base3.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base3.png
index 35e22c64542f76398d4c4148f9e54714b041cfa3..9a560e6d30da52962ae2b6a27ed564bb9a556a4a 100644
GIT binary patch
delta 238
zcmV<K01^Mn0*L~UBYyx1a7bBm000ie000ie0hKEb8vp<RyGcYrRCt{2)Ikb^Fc5{|
z2t7?fP!M{aoGj-N1O=hjNqvie1e6)_5}`~sW+VR>Gx%~3F9R6B0RIgb`cK^UxqAd4
ziB|(i<5d8fI2C{}o|-rXkiz5icI)z0zh4B%K6lifz6hYbYiBATkC$N70A^ebKn%ln
z1SxS5AVt#i07UP7#Kbq5ffUCc;SfT{8bA@?jKHaxaWNpj21i`t8Nj{<;u3K6Z*TSm
o&cj!8-ChCvv}!<$WdH;G09nq1RC%#!{{R3007*qoM6N<$g7W}hlmGw#

delta 304
zcmV-00nh%40?GoABYy!ANkl<Zc${Nk7zHC8Fw)ureRGfhF!sfhJ7{hnPRp_J85kHC
znCRym?0|(*0|spn2ZW~l-+lD>e|>WgIHsEekS!-<2G!GmzPZPLJ1Y~0lA=bUqJ-i&
zL-u8SL;%B~V`mudKYBuRdZ0K26y;<X7#J8Bdiv@a4jntgV1H+20(Tfq;vE?Tgr@vw
zfP^BWzPZQ$zWx~)mJ)IV*&z@Rn(`mXxBo7l+`+VP#RihiA-f#duzC(70|Uc<nC0Y}
zLvbR6g~Y-Y8{i3#?u8T06Wf3TXlkbkAS&@Zc<_i;_7ewoA3grxz|@T<p+HnNynN~+
zgMxw_0|SHGe<=k8Ian5?4;auCK5F^MvwRecNB{s@vwBhYHW6_E0000<MNUMnLSTYc
CAc3X;

diff --git a/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base4.png b/Resources/Textures/Objects/Specific/Chemistry/syringe.rsi/syringe_base4.png
index 834ae95f9f67cc4e4216a6bbb38dab01db3a127d..cce9207cc181ce87a92566829116062536d038f3 100644
GIT binary patch
delta 226
zcmV<803H9F0{#JzB!3BTNLh0L01m_e01m_fl`9S#00026Nkl<Zc%1Fk;Rb*(6o%nN
zR})c0m%HnUD5Be0Ee@HLbK19!Y-GRkKHJJ_m3b6E0TjT$0bM(qb(^Xz08Ts_fE$kj
zki?+?8@96~4gpZO9~!mHyZHSefV163y80l1^sJ!(Hy(l!16z=BF#sKB0Von9&H_-}
z{$}T6wAK|W&H@nPoGt`1&Ia6~&^QZlU$O67hzjt<lI+0Oiv<RttyT%f;}N7-{VO2V
cD1hvM0~hUoDGtb=761SM07*qoM6N<$f+9&=?EnA(

delta 256
zcmV+b0ssE~0h|JmB!A;cL_t(|oMT`Z1tT3W(%J%jbC3Tp_QjJsXl@@)%dznp7#J9s
z=;s{lfQ3>625k@rgr@x8ef0Q$eRB^urkewhEhl6K)zg5!xyOGyD-(v2qDG>kgyJ|u
z_GNrT0K=hUXBh53dO~!1pjx8Yef0SMsT1Zh*jbq{EL^bxE_qJZgxS|W10&uEr30#_
zfuh0;l6^bi1rbf+XFv<5;RymlQ>b5zLIF{U@WF#ew6dQ#u>0uo{|2URGzkTws^iP2
zE;1-6$T2W5xcyg9kYm`edJg?kHchJ0QOidy9|fZT2><}8?_osFS+RQn0000<MNUMn
GLSTZxEOOQW


From 7c849b297bf795c3889316235408f78eefcb0a8f Mon Sep 17 00:00:00 2001
From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com>
Date: Sun, 23 Apr 2023 07:40:26 -0400
Subject: [PATCH 2/7] Removed Silicon remnants

---
 .../SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs       | 1 -
 1 file changed, 1 deletion(-)

diff --git a/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs b/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs
index 5287a1f7b5..74579cabb9 100644
--- a/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs
+++ b/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs
@@ -4,7 +4,6 @@
 using Content.Shared.DoAfter;
 using Content.Shared.Interaction;
 using Content.Shared.Interaction.Events;
-using Content.Shared.SimpleStation14.Silicon.Components;
 
 using Content.Server.Body.Systems;
 using Content.Server.Chemistry.Components;

From 01c60dc311e469cbd3122b6a19f9761c9ce6c15c Mon Sep 17 00:00:00 2001
From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com>
Date: Wed, 14 Jun 2023 07:21:39 -0400
Subject: [PATCH 3/7] Big ol update to just about everything

---
 .../Components/BloodstreamFillerComponent.cs  | 167 +++++++++++
 .../Systems/BloodstreamFillerSystem.cs        | 263 ++++++++++++++++++
 .../Components/SiliconFillerComponent.cs      |  20 --
 .../Silicon/Systems/SiliconFillerSystem.cs    | 145 ----------
 .../Silicon/BloodstreamFillerEvents.cs        |  24 ++
 .../Content/BloodFiller/bloodFiller.ftl       |  13 +
 .../Objects/Specific/Medical/hypospray.yml    |  46 +++
 .../Structures/Storage/Tanks/tanks.yml        |  55 ++++
 .../Storage/tanks.rsi/bloodtankblood.png      | Bin 0 -> 3863 bytes
 .../Storage/tanks.rsi/bloodtankslime.png      | Bin 0 -> 3980 bytes
 .../Structures/Storage/tanks.rsi/meta.json    |  17 ++
 11 files changed, 585 insertions(+), 165 deletions(-)
 create mode 100644 Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
 create mode 100644 Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
 delete mode 100644 Content.Server/SimpleStation14/Silicon/Components/SiliconFillerComponent.cs
 delete mode 100644 Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs
 create mode 100644 Content.Shared/SimpleStation14/Silicon/BloodstreamFillerEvents.cs
 create mode 100644 Resources/Locale/en-US/SimpleStation14/Content/BloodFiller/bloodFiller.ftl
 create mode 100644 Resources/Prototypes/SimpleStation14/Entities/Structures/Storage/Tanks/tanks.yml
 create mode 100644 Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/bloodtankblood.png
 create mode 100644 Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/bloodtankslime.png
 create mode 100644 Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/meta.json

diff --git a/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs b/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
new file mode 100644
index 0000000000..97d8b02849
--- /dev/null
+++ b/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
@@ -0,0 +1,167 @@
+using Content.Shared.Damage;
+using Content.Shared.Damage.Prototypes;
+using Robust.Shared.Audio;
+
+namespace Content.Server.SimpleStation14.BloodstreamFiller.Components;
+
+[RegisterComponent]
+public sealed class BloodstreamFillerComponent : Component
+{
+    /// <summary>
+    ///     The duration of the fill DoAfter, in seconds.
+    /// </summary>
+    [DataField("fillTime"), ViewVariables(VVAccess.ReadWrite)]
+    public float FillTime = 1.0f;
+
+    /// <summary>
+    ///     The multiplier for the DoAfter time when attempting to fill yourself.
+    /// </summary>
+    [DataField("selfFillMutli"), ViewVariables(VVAccess.ReadWrite)]
+    public float SelfFillMutli = 3.5f;
+
+    /// <summary>
+    /// The name of the volume to refill.
+    /// </summary>
+    /// <remarks>
+    /// Should match the <see cref="SolutionContainerComponent"/> name or otherwise.
+    /// </remarks>
+    [DataField("solution"), ViewVariables(VVAccess.ReadWrite)]
+    public string Solution { get; } = "filler";
+
+    /// <summary>
+    ///     The amount of reagent that this bloodstream filler will fill with at most.
+    /// </summary>
+    [DataField("amount"), ViewVariables(VVAccess.ReadWrite)]
+    public float Amount = 100.0f;
+
+    /// <summary>
+    ///     The regent allowed to be used by this filler.
+    /// </summary>
+    /// <remarks>
+    ///     If null, any reagent will be allowed.
+    /// </remarks>
+    [DataField("reagent"), ViewVariables(VVAccess.ReadWrite)]
+    public string? Reagent = null;
+
+    /// <summary>
+    ///     Will this filler only fill Silicons?
+    /// </summary>
+    /// <remarks>
+    ///     Somewhat niche use case, but Bloodstreams are very inflexible.
+    /// </remarks>
+    [DataField("siliconOnly"), ViewVariables(VVAccess.ReadWrite)]
+    public bool SiliconOnly = true;
+
+    /// <summary>
+    ///     Can this bloodfiller be used to overfill someone?
+    /// </summary>
+    /// <remarks>
+    ///     If true, the bloodfiller will be able to fill someone already at max blood, causing damage and spilling blood.
+    /// </remarks>
+    [DataField("overfill"), ViewVariables(VVAccess.ReadWrite)]
+    public bool Overfill = true;
+
+    /// <summary>
+    ///     The multiplier for the DoAfter time when attempting to overfill someone.
+    /// </summary>
+    [DataField("overfillMutli"), ViewVariables(VVAccess.ReadWrite)]
+    public float OverfillMutli = 5.5f;
+
+    /// <summary>
+    ///     The amount of damage dealt when overfilling someone.
+    /// </summary>
+    /// <remarks>
+    ///     This must be specified in YAML.
+    /// </remarks>
+    [DataField("overfillDamage"), ViewVariables(VVAccess.ReadWrite)]
+    public DamageSpecifier OverfillDamage = default!;
+
+    #region Player Feedback
+    /// <summary>
+    ///     The sound played when the filler is used.
+    /// </summary>
+    [DataField("useSound")]
+    public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Effects/bang.ogg");
+
+    /// <summary>
+    ///     The sound played when the filler refills.
+    /// </summary>
+    [DataField("refillSound")]
+    public SoundSpecifier RefillSound = new SoundPathSpecifier("/Audio/Effects/buckle.ogg");
+
+    /// <summary>
+    ///     The sound played when overfilling someone.
+    /// </summary>
+    [DataField("overfillSound")]
+    public SoundSpecifier OverfillSound = new SoundPathSpecifier("/Audio/Effects/demon_dies.ogg");
+
+    /// <summary>
+    ///     The popup text when the filler is used.
+    /// </summary>
+    [DataField("usePopup")]
+    public string UsePopup = "bloodfiller-use-user";
+
+    /// <summary>
+    ///     The popup text when the filler is used on you.
+    /// </summary>
+    [DataField("usedOnPopup")]
+    public string UsedOnPopup = "bloodfiller-use-target";
+
+    /// <summary>
+    ///     The popup text when the bloodfiller is empty.
+    /// </summary>
+    [DataField("emptyPopup")]
+    public string EmptyPopup = "bloodfiller-use-empty";
+
+    /// <summary>
+    ///     The popup text when the bloodfiller can't be used on the target.
+    /// </summary>
+    /// <remarks>
+    ///     Due to <see cref="SiliconOnly"/> or otherwise.
+    /// </remarks>
+    [DataField("targetInvalidPopup")]
+    public string TargetInvalidPopup = "bloodfiller-use-invalid-target";
+
+    /// <summary>
+    ///     The popup text when the bloodfiller doesn't have the target's blood.
+    /// </summary>
+    [DataField("targetBloodInvalidPopup")]
+    public string TargetBloodInvalidPopup = "bloodfiller-use-invalid-blood";
+
+    /// <summary>
+    ///     The popup text when the filler is already full.
+    /// </summary>
+    [DataField("refillFullPopup")]
+    public string RefillFullPopup = "bloodfiller-refill-filler-full";
+
+    /// <summary>
+    ///     The popup text when the tank is empty.
+    /// </summary>
+    [DataField("refillTankEmptyPopup")]
+    public string RefillTankEmptyPopup = "bloodfiller-refill-tank-empty";
+
+    /// <summary>
+    ///     The popup text when trying to refill the bloodfiller from a tank with the wrong reagent.
+    /// </summary>
+    [DataField("refillReagentInvalidPopup")]
+    public string RefillReagentInvalidPopup = "bloodfiller-refill-reagent-invalid";
+
+    /// <summary>
+    ///     The popup text when either a tank or filler contains a dirty mixture.
+    /// </summary>
+    [DataField("dirtyPopup")]
+    public string DirtyPopup = "bloodfiller-reagent-dirty";
+
+    /// <summary>
+    ///     The popup text when trying to overfill someone.
+    /// </summary>
+    [DataField("targetOverfillPopup")]
+    public string TargetOverfillPopup = "bloodfiller-user-overfill";
+
+    /// <summary>
+    ///     The popup text when getting overfilled.
+    /// </summary>
+    [DataField("overfilledPopup")]
+    public string OverfilledPopup = "bloodfiller-target-overfill";
+    #endregion
+}
diff --git a/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs b/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
new file mode 100644
index 0000000000..920a35d070
--- /dev/null
+++ b/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
@@ -0,0 +1,263 @@
+using Content.Server.Body.Components;
+using Content.Server.SimpleStation14.BloodstreamFiller.Components;
+using Content.Shared.DoAfter;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Content.Server.Body.Systems;
+using Content.Server.Chemistry.Components;
+using Content.Server.Chemistry.EntitySystems;
+using Content.Shared.FixedPoint;
+using Content.Shared.SimpleStation14.BloodstreamFiller;
+using Robust.Shared.Utility;
+using Content.Server.Popups;
+using Robust.Server.GameObjects;
+using Content.Shared.Popups;
+using Content.Shared.Damage;
+using Content.Server.Fluids.EntitySystems;
+
+namespace Content.Server.SimpleStation14.BloodstreamFiller.Systems;
+
+public sealed class BloodstreamFillerSystem : EntitySystem
+{
+    [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+    [Dependency] private readonly AudioSystem _audio = default!;
+    [Dependency] private readonly BloodstreamSystem _bloodstream = default!;
+    [Dependency] private readonly DamageableSystem _damageable = default!;
+    [Dependency] private readonly PuddleSystem _puddle = default!;
+    [Dependency] private readonly SolutionContainerSystem _solution = default!;
+    [Dependency] private readonly PopupSystem _popup = default!;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+
+        SubscribeLocalEvent<BloodstreamFillerComponent, AfterInteractEvent>(OnUseInWorld);
+        SubscribeLocalEvent<BloodstreamFillerComponent, UseInHandEvent>(OnUseInHand);
+
+        SubscribeLocalEvent<BloodstreamComponent, BloodstreamFillerDoAfterEvent>(OnDoAfter);
+    }
+
+    private void OnUseInWorld(EntityUid uid, BloodstreamFillerComponent component, AfterInteractEvent args)
+    {
+        if (!args.CanReach || args.Target == null)
+            return;
+
+        if (!EntityManager.TryGetComponent<BloodstreamComponent>(args.Target, out var bloodComp))
+        {
+            TryRefill(args.User, uid, args.Target.Value, component);
+            return;
+        }
+
+        TryFill(args.User, args.Target.Value, args.Used, component);
+    }
+
+    private void OnUseInHand(EntityUid uid, BloodstreamFillerComponent component, UseInHandEvent args)
+    {
+        if (!EntityManager.TryGetComponent<BloodstreamComponent>(args.User, out var bloodComp))
+            return;
+
+        TryFill(args.User, args.User, uid, component);
+    }
+
+    private void TryFill(EntityUid user, EntityUid target, EntityUid filler, BloodstreamFillerComponent fillComp)
+    {
+        // if (fillComp.SiliconOnly && !HasComp<SiliconComponent>(target)) // To be turned on once Silicons are merged :)
+        // {
+        //     // Do failure stuff
+        //     return;
+        // }
+
+        var bloodComp = EntityManager.GetComponent<BloodstreamComponent>(target);
+
+        if (!_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution)) // No solution
+            return;
+
+        if (fillComp.Reagent != null && fillComp.Reagent != bloodComp.BloodReagent) // Wrong reagent as specified by the component
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.TargetInvalidPopup, ("filler", filler)), user);
+            return;
+        }
+
+        if (fillerSolution.Contents.Count == 0) // Empty
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.EmptyPopup, ("filler", filler)), user);
+            return;
+        }
+
+        if (fillerSolution.Contents.Count > 1) // Extra dorty
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.DirtyPopup, ("volume", filler)), user);
+            return;
+        }
+
+        if (fillerSolution.Contents[0].ReagentId != bloodComp.BloodReagent) // Wrong reagent contained
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.TargetBloodInvalidPopup, ("filler", filler), ("target", target)), user);
+            return;
+        }
+
+        var overfill = false;
+
+        var delay = fillComp.FillTime;
+        if (user == target)
+            delay *= fillComp.SelfFillMutli;
+
+        // If the bloodstream is already full, and the filler can overfill, and target is not the user, then overfill.
+        if (fillComp.Overfill && bloodComp.BloodSolution.AvailableVolume == 0 && user != target)
+        {
+            overfill = true;
+            delay *= fillComp.OverfillMutli;
+        }
+
+        _doAfter.TryStartDoAfter(new DoAfterArgs(user, delay, new BloodstreamFillerDoAfterEvent(overfill), target, target, filler)
+        {
+            BreakOnDamage = true,
+            BreakOnTargetMove = true,
+            BreakOnUserMove = true,
+            MovementThreshold = 0.2f,
+            CancelDuplicate = true
+        });
+
+        if (!overfill)
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.UsePopup, ("target", target)), user);
+            _popup.PopupEntity(Loc.GetString(fillComp.UsedOnPopup), target, target, PopupType.Medium);
+        }
+        else
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.TargetOverfillPopup, ("target", target)), user, PopupType.MediumCaution);
+            _popup.PopupEntity(Loc.GetString(fillComp.OverfilledPopup), target, target, PopupType.LargeCaution);
+        }
+    }
+
+    private void OnDoAfter(EntityUid uid, BloodstreamComponent component, BloodstreamFillerDoAfterEvent args)
+    {
+        if (args.Cancelled)
+        {
+            return;
+        }
+
+        if (args.Handled || args.Args.Target == null)
+            return;
+
+        if (!TryComp<BloodstreamFillerComponent>(args.Args.Used, out var fillComp))
+        {
+            DebugTools.Assert("Filler component not found");
+            Logger.ErrorS("silicon", $"Filler component not found on entity {ToPrettyString(args.Args.Used.Value)}");
+
+            return;
+        }
+        if (!EntityManager.TryGetComponent<BloodstreamComponent>(args.Args.Target, out var bloodComp))
+        {
+            DebugTools.Assert("Bloodstream component not found");
+            Logger.ErrorS("silicon", $"Bloodstream component not found on entity {ToPrettyString(args.Args.Target.Value)}");
+
+            return;
+        }
+
+        if (!args.Overfill)
+            Fill(args.Args.Target.Value, args.Args.Used!.Value, fillComp, bloodComp);
+        else
+            Overfill(args.Args.User, args.Args.Target.Value, args.Args.Used!.Value, fillComp, bloodComp);
+
+        args.Handled = true;
+    }
+
+    private void Fill(EntityUid target, EntityUid filler, BloodstreamFillerComponent fillComp, BloodstreamComponent bloodComp)
+    {
+        if (!_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution))
+            return;
+
+        var tansfAmount = FixedPoint2.Min(bloodComp.BloodSolution.AvailableVolume, Math.Min((float) fillerSolution.Volume, fillComp.Amount));
+
+        if (tansfAmount > 0)
+        {
+            var drained = _solution.SplitSolution(filler, fillerSolution, tansfAmount);
+
+            _bloodstream.TryModifyBloodLevel(target, drained.Volume, bloodComp);
+
+            _audio.PlayPvs(fillComp.RefillSound, filler);
+        }
+    }
+
+    private void Overfill(EntityUid user, EntityUid target, EntityUid filler, BloodstreamFillerComponent fillComp, BloodstreamComponent bloodComp)
+    {
+        if (!_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution))
+            return;
+
+        if (!TryComp<DamageableComponent>(target, out var damageableComp))
+            return;
+
+        _damageable.TryChangeDamage(target, fillComp.OverfillDamage, origin: user, damageable: damageableComp);
+
+        _puddle.TrySplashSpillAt(target, Transform(target).Coordinates, fillerSolution, out _, user: user);
+
+        Fill(target, filler, fillComp, bloodComp);
+    }
+
+    private void TryRefill(EntityUid user, EntityUid filler, EntityUid target, BloodstreamFillerComponent fillComp)
+    {
+        if (!EntityManager.TryGetComponent<ReagentTankComponent>(target, out _))
+            return;
+
+        if (!_solution.TryGetDrainableSolution(target, out var targetSolution))
+            return;
+
+        if (!_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution))
+            return;
+
+        // Check that the tank is not empty.
+        if (targetSolution.Contents.Count == 0)
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.RefillTankEmptyPopup, ("tank", target)), user);
+            return;
+        }
+
+        // Check that the tank has one, and only one reagent.
+        if (targetSolution.Contents.Count > 1)
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.DirtyPopup, ("volume", target)), user);
+            return;
+        }
+
+        // Check that the tank's solution matches the filler's listed reagent.
+        // This is seperate from checking the actual solution to prevent any funny business.
+        if (fillComp.Reagent != null && targetSolution.Contents[0].ReagentId != fillComp.Reagent)
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.RefillReagentInvalidPopup, ("tank", target)), user);
+            return;
+        }
+
+        // Check that if the filler isn't empty, that it only has one reagent.
+        if (fillerSolution.Contents.Count > 1)
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.DirtyPopup, ("volume", filler)), user);
+            return;
+        }
+
+        // Check that if the filler isn't empty, that it's reagent matches the tank's reagent.
+        if (fillerSolution.Contents.Count == 1 && fillerSolution.Contents[0].ReagentId != targetSolution.Contents[0].ReagentId)
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.RefillReagentInvalidPopup, ("filler", filler)), user);
+            return;
+        }
+
+        var tansfAmount = FixedPoint2.Min(fillerSolution.AvailableVolume, targetSolution.Volume);
+
+        if (tansfAmount > 0)
+        {
+            var drained = _solution.Drain(target, targetSolution, tansfAmount);
+            _solution.TryAddSolution(filler, fillerSolution, drained);
+
+            _audio.PlayPvs(fillComp.UseSound, filler);
+        }
+        else if (fillerSolution.AvailableVolume <= 0)
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.RefillFullPopup, ("filler", filler)), user);
+        }
+        else
+        {
+            _popup.PopupCursor(Loc.GetString(fillComp.RefillTankEmptyPopup, ("tank", target)), user);
+        }
+    }
+}
diff --git a/Content.Server/SimpleStation14/Silicon/Components/SiliconFillerComponent.cs b/Content.Server/SimpleStation14/Silicon/Components/SiliconFillerComponent.cs
deleted file mode 100644
index 4b6415dbf4..0000000000
--- a/Content.Server/SimpleStation14/Silicon/Components/SiliconFillerComponent.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-namespace Content.Server.SimpleStation14.Silicon.Components;
-
-[RegisterComponent]
-public sealed class BloodstreamFillerComponent : Component
-{
-    /// <summary>
-    /// The name of the volume to refill.
-    /// </summary>
-    /// <remarks>
-    /// Should match the <see cref="SolutionContainerComponent"/> name or otherwise.
-    /// </remarks>
-    [DataField("solution"), ViewVariables(VVAccess.ReadWrite)]
-    public string Solution { get; } = "filler";
-
-    /// <summary>
-    ///     The amount of reagent that this silicon filler will fill with at most.
-    /// </summary>
-    [DataField("amount"), ViewVariables(VVAccess.ReadWrite)]
-    public float Amount = 100.0f;
-}
diff --git a/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs b/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs
deleted file mode 100644
index 74579cabb9..0000000000
--- a/Content.Server/SimpleStation14/Silicon/Systems/SiliconFillerSystem.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-using Content.Server.Body.Components;
-using Content.Server.DoAfter;
-using Content.Server.SimpleStation14.Silicon.Components;
-using Content.Shared.DoAfter;
-using Content.Shared.Interaction;
-using Content.Shared.Interaction.Events;
-
-using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.EntitySystems;
-using Content.Shared.FixedPoint;
-
-namespace Content.Server.SimpleStation14.Silicon.Systems;
-
-public sealed class BloodstreamFillerSystem : EntitySystem
-{
-    [Dependency] private readonly DoAfterSystem _doAfter = default!;
-    [Dependency] private readonly BloodstreamSystem _bloodSystem = default!;
-    [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
-
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<BloodstreamFillerComponent, AfterInteractEvent>(OnUseInWorld);
-        SubscribeLocalEvent<BloodstreamFillerComponent, UseInHandEvent>(OnUseInHand);
-
-        SubscribeLocalEvent<BloodstreamFillerComponent, DoAfterEvent>(OnDoAfter);
-    }
-
-    private void OnUseInWorld(EntityUid uid, BloodstreamFillerComponent component, AfterInteractEvent args)
-    {
-        if (!args.CanReach || args.Target == null)
-            return;
-
-        if (!EntityManager.TryGetComponent<BloodstreamComponent>(args.Target, out var bloodComp))
-        {
-            TryRefill(uid, args.Target.Value, component);
-            return;
-        }
-
-        TryFill(args.User, args.Target.Value, args.Used, component);
-    }
-
-    private void OnUseInHand(EntityUid uid, BloodstreamFillerComponent component, UseInHandEvent args)
-    {
-        if (!EntityManager.TryGetComponent<BloodstreamComponent>(args.User, out var bloodComp))
-            return;
-
-        TryFill(args.User, args.User, uid, component);
-    }
-
-    private void TryFill(EntityUid user, EntityUid target, EntityUid filler, BloodstreamFillerComponent fillComp)
-    {
-        var bloodComp = EntityManager.GetComponent<BloodstreamComponent>(target);
-
-        if (!_solutionSystem.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution) ||
-            fillerSolution.Contents.Count != 1 || // Extra dorty
-            fillerSolution.Contents[0].ReagentId != bloodComp.BloodReagent)
-            return;
-
-        var delay = 2.5f;
-        if (user == target)
-            delay *= 3.5f;
-
-        _doAfter.DoAfter(new DoAfterEventArgs(user, delay, target: target, used: filler)
-        {
-            RaiseOnTarget = true,
-            RaiseOnUser = false,
-            BreakOnUserMove = true,
-            BreakOnDamage = true,
-            BreakOnStun = true,
-            BreakOnTargetMove = true,
-            MovementThreshold = 0.2f
-        });
-    }
-
-    private void OnDoAfter(EntityUid uid, BloodstreamFillerComponent component, DoAfterEvent args)
-    {
-        if (args.Cancelled)
-        {
-            return;
-        }
-
-        if (args.Handled || args.Args.Target == null)
-            return;
-
-        Fill(args.Args.Target.Value, args.Args.Used!.Value, component);
-
-        args.Handled = true;
-    }
-
-    private void Fill(EntityUid target, EntityUid filler, BloodstreamFillerComponent fillComp)
-    {
-        if (!_solutionSystem.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution))
-            return;
-
-        var bloodComp = EntityManager.GetComponent<BloodstreamComponent>(target);
-
-        var tansfAmount = FixedPoint2.Min(bloodComp.BloodSolution.AvailableVolume, Math.Min((float) fillerSolution.Volume, fillComp.Amount));
-
-        if (tansfAmount > 0)
-        {
-            var drained = _solutionSystem.SplitSolution(filler, fillerSolution, tansfAmount);
-
-            _bloodSystem.TryModifyBloodLevel(target, drained.Volume, bloodComp);
-            // _audioSystem.PlayPvs(welder.WelderRefill, welderUid);
-            // _popupSystem.PopupCursor(Loc.GetString("welder-component-after-interact-refueled-message"), user);
-        }
-    }
-
-    private void TryRefill(EntityUid filler, EntityUid target, BloodstreamFillerComponent fillComp)
-    {
-        if (!EntityManager.TryGetComponent<ReagentTankComponent>(target, out var tankComp))
-            return;
-
-        // Check that the tank has one, and only one reagent.
-        if (!_solutionSystem.TryGetDrainableSolution(target, out var targetSolution)||
-            targetSolution.Contents.Count > 1) // Dorty
-            return;
-
-        // Check that the filler has one, and only one reagent, and that it's the same as the tank.
-        if (!_solutionSystem.TryGetSolution(filler, (string) fillComp.Solution!, out var fillerSolution) ||
-            fillerSolution.Contents.Count > 1 || // Extra dorty
-            (fillerSolution.Contents.Count > 0 && fillerSolution.Contents[0].ReagentId != targetSolution.Contents[0].ReagentId))
-            return;
-
-        var tansfAmount = FixedPoint2.Min(fillerSolution.AvailableVolume, targetSolution.Volume);
-        if (tansfAmount > 0)
-        {
-            var drained = _solutionSystem.Drain(target, targetSolution,  tansfAmount);
-            _solutionSystem.TryAddSolution(filler, fillerSolution, drained);
-            // _audioSystem.PlayPvs(welder.WelderRefill, welderUid);
-            // _popupSystem.PopupCursor(Loc.GetString("welder-component-after-interact-refueled-message"), user);
-        }
-        else if (fillerSolution.AvailableVolume <= 0)
-        {
-            // _popupSystem.PopupCursor(Loc.GetString("welder-component-already-full"), user);
-        }
-        else
-        {
-            // _popupSystem.PopupCursor(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", target)), user);
-        }
-    }
-}
diff --git a/Content.Shared/SimpleStation14/Silicon/BloodstreamFillerEvents.cs b/Content.Shared/SimpleStation14/Silicon/BloodstreamFillerEvents.cs
new file mode 100644
index 0000000000..9dce1045c7
--- /dev/null
+++ b/Content.Shared/SimpleStation14/Silicon/BloodstreamFillerEvents.cs
@@ -0,0 +1,24 @@
+using Content.Shared.DoAfter;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.SimpleStation14.BloodstreamFiller;
+
+[Serializable, NetSerializable]
+public sealed class BloodstreamFillerDoAfterEvent : DoAfterEvent
+{
+    [DataField("overfill")]
+    public readonly bool Overfill = false;
+
+    private BloodstreamFillerDoAfterEvent()
+    {
+    }
+    public BloodstreamFillerDoAfterEvent(bool overfill)
+    {
+        Overfill = overfill;
+    }
+
+    public override DoAfterEvent Clone()
+    {
+        return this;
+    }
+}
diff --git a/Resources/Locale/en-US/SimpleStation14/Content/BloodFiller/bloodFiller.ftl b/Resources/Locale/en-US/SimpleStation14/Content/BloodFiller/bloodFiller.ftl
new file mode 100644
index 0000000000..df003261bc
--- /dev/null
+++ b/Resources/Locale/en-US/SimpleStation14/Content/BloodFiller/bloodFiller.ftl
@@ -0,0 +1,13 @@
+bloodfiller-use-user = You begin filling { THE($target) }.
+bloodfiller-use-target = You feel your bloodstream beginning to pressurize...
+bloodfiller-use-empty = { CAPITALIZE(THE($filler)) } is empty.
+bloodfiller-use-invalid-target = { CAPITALIZE(THE($filler)) } can't be used here.
+bloodfiller-use-invalid-blood = { CAPITALIZE(THE($filler)) } does not contain the blood required by { THE($target) }.
+
+bloodfiller-refill-filler-full = { CAPITALIZE(THE($filler)) } is already full.
+bloodfiller-refill-tank-empty = { CAPITALIZE(THE($tank)) } is empty.
+bloodfiller-refill-reagent-invalid = { CAPITALIZE(THE($tank)) } does not contain the correct reagent.
+bloodfiller-reagent-dirty = { CAPITALIZE(THE($volume)) } contains a dirty mixture.
+
+bloodfiller-user-overfill = You begin overpressurizing { THE($target) }...
+bloodfiller-target-overfill = You feel like your veins are bursting at the seams...
diff --git a/Resources/Prototypes/SimpleStation14/Entities/Objects/Specific/Medical/hypospray.yml b/Resources/Prototypes/SimpleStation14/Entities/Objects/Specific/Medical/hypospray.yml
index 37cc523db6..ba40e66a87 100644
--- a/Resources/Prototypes/SimpleStation14/Entities/Objects/Specific/Medical/hypospray.yml
+++ b/Resources/Prototypes/SimpleStation14/Entities/Objects/Specific/Medical/hypospray.yml
@@ -49,3 +49,49 @@
       - reagents:
         - ReagentId: CellularDivider
           Quantity: 100
+
+- type: entity
+  abstract: true
+  parent: BaseItem
+  id: BloodFillerBase
+  components:
+  - type: Sprite
+    sprite: Objects/Specific/Medical/hypospray.rsi
+    state: hypo
+  - type: Item
+    sprite: Objects/Specific/Medical/hypospray.rsi
+  - type: BloodstreamFiller
+    solution: filler
+    overfillDamage:
+      groups:
+        Brute: 18
+  - type: UseDelay
+    delay: 2
+  - type: SolutionContainerManager
+    solutions:
+      filler:
+        maxVol: 250
+  # - type: RefillableSolution
+  #   solution: filler
+  - type: ExaminableSolution
+    solution: filler
+
+- type: entity
+  parent: BloodFillerBase
+  id: BloodFillerBlood
+  name: bloodfiller
+  description: A pump to inject blood into your body.
+  components:
+  - type: BloodstreamFiller
+    reagent: Blood
+    amount: 100
+
+- type: entity
+  parent: BloodFillerBase
+  id: BloodFillerSilicon
+  name: IPC coolant injector
+  description: A pump to inject coolant into an IPC.
+  components:
+  - type: BloodstreamFiller
+    reagent: Water
+    amount: 200
diff --git a/Resources/Prototypes/SimpleStation14/Entities/Structures/Storage/Tanks/tanks.yml b/Resources/Prototypes/SimpleStation14/Entities/Structures/Storage/Tanks/tanks.yml
new file mode 100644
index 0000000000..7a808cf49a
--- /dev/null
+++ b/Resources/Prototypes/SimpleStation14/Entities/Structures/Storage/Tanks/tanks.yml
@@ -0,0 +1,55 @@
+- type: entity
+  abstract: true
+  id: BloodTankBase
+  parent: StorageTank
+  suffix: Empty
+  components:
+  - type: DynamicPrice
+    price: 2000
+  - type: Sprite
+    sprite: SimpleStation14/Structures/Storage/tanks.rsi
+    state: bloodtankblood
+  - type: ExaminableSolution
+    solution: tank
+
+- type: entity
+  id: BloodTankBlood
+  parent: BloodTankBase
+  suffix: Empty
+  components:
+  - type: Sprite
+    state: bloodtankblood
+
+- type: entity
+  parent: BloodTankBlood
+  id: BloodTankBloodFull
+  suffix: Full
+  components:
+  - type: SolutionContainerManager
+    solutions:
+      tank:
+        reagents:
+        - ReagentId: Blood
+          Quantity: 1500
+
+- type: entity
+  id: BloodTankSlime
+  parent: BloodTankBase
+  suffix: Empty
+  components:
+  - type: DynamicPrice
+    price: 2500
+  - type: Sprite
+    state: bloodtankslime
+
+- type: entity
+  parent: BloodTankSlime
+  id: BloodTankSlimeFull
+  suffix: Full
+  components:
+  - type: SolutionContainerManager
+    solutions:
+      tank:
+        reagents:
+        - ReagentId: Slime
+          Quantity: 1500
diff --git a/Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/bloodtankblood.png b/Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/bloodtankblood.png
new file mode 100644
index 0000000000000000000000000000000000000000..0745546669a81fc4a611a2e8fe3b0203d4aec997
GIT binary patch
literal 3863
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
Ze*<sc3iW6Af2RNd002ovPDHLkV1ft<YU}_2

literal 0
HcmV?d00001

diff --git a/Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/bloodtankslime.png b/Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/bloodtankslime.png
new file mode 100644
index 0000000000000000000000000000000000000000..28da368552bd15d3bfcff104763937fba72db41c
GIT binary patch
literal 3980
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

literal 0
HcmV?d00001

diff --git a/Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/meta.json b/Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/meta.json
new file mode 100644
index 0000000000..3dafefc256
--- /dev/null
+++ b/Resources/Textures/SimpleStation14/Structures/Storage/tanks.rsi/meta.json
@@ -0,0 +1,17 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Modified by Pspritechologist from tgstation at commit https://github.com/tgstation/tgstation/commit/8442af39ee82b813194f71db82edd2923d97818d",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "bloodtankblood"
+    },
+    {
+      "name": "bloodtankslime"
+    }
+  ]
+}

From f2ed9fc18e0123cc6b630587ba29ab13cd8256cb Mon Sep 17 00:00:00 2001
From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com>
Date: Wed, 14 Jun 2023 07:24:37 -0400
Subject: [PATCH 4/7] Simple Silicon stuff

---
 .../BloodstreamFiller/Systems/BloodstreamFillerSystem.cs    | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs b/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
index 920a35d070..a42a94112d 100644
--- a/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
+++ b/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
@@ -63,7 +63,7 @@ private void TryFill(EntityUid user, EntityUid target, EntityUid filler, Bloodst
     {
         // if (fillComp.SiliconOnly && !HasComp<SiliconComponent>(target)) // To be turned on once Silicons are merged :)
         // {
-        //     // Do failure stuff
+        //     _popup.PopupCursor(Loc.GetString(fillComp.TargetInvalidPopup, ("filler", filler)), user);
         //     return;
         // }
 
@@ -143,14 +143,14 @@ private void OnDoAfter(EntityUid uid, BloodstreamComponent component, Bloodstrea
         if (!TryComp<BloodstreamFillerComponent>(args.Args.Used, out var fillComp))
         {
             DebugTools.Assert("Filler component not found");
-            Logger.ErrorS("silicon", $"Filler component not found on entity {ToPrettyString(args.Args.Used.Value)}");
+            Logger.ErrorS("bloodfiller", $"Filler component not found on entity {ToPrettyString(args.Args.Used.Value)}");
 
             return;
         }
         if (!EntityManager.TryGetComponent<BloodstreamComponent>(args.Args.Target, out var bloodComp))
         {
             DebugTools.Assert("Bloodstream component not found");
-            Logger.ErrorS("silicon", $"Bloodstream component not found on entity {ToPrettyString(args.Args.Target.Value)}");
+            Logger.ErrorS("bloodfiller", $"Bloodstream component not found on entity {ToPrettyString(args.Args.Target.Value)}");
 
             return;
         }

From e070cc1e75da9619328acfb92c6a8009b274cec0 Mon Sep 17 00:00:00 2001
From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com>
Date: Sun, 18 Jun 2023 19:19:15 -0400
Subject: [PATCH 5/7] Review suggestions

---
 .../Components/BloodstreamFillerComponent.cs  | 10 +++----
 .../Systems/BloodstreamFillerSystem.cs        | 28 ++++++-------------
 .../Silicon/BloodstreamFillerEvents.cs        |  1 +
 3 files changed, 14 insertions(+), 25 deletions(-)

diff --git a/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs b/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
index 97d8b02849..0745594816 100644
--- a/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
+++ b/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
@@ -20,10 +20,10 @@ public sealed class BloodstreamFillerComponent : Component
     public float SelfFillMutli = 3.5f;
 
     /// <summary>
-    /// The name of the volume to refill.
+    ///     The name of the volume to refill.
     /// </summary>
     /// <remarks>
-    /// Should match the <see cref="SolutionContainerComponent"/> name or otherwise.
+    ///     Should match the <see cref="SolutionContainerComponent"/> name or otherwise.
     /// </remarks>
     [DataField("solution"), ViewVariables(VVAccess.ReadWrite)]
     public string Solution { get; } = "filler";
@@ -64,8 +64,8 @@ public sealed class BloodstreamFillerComponent : Component
     /// <summary>
     ///     The multiplier for the DoAfter time when attempting to overfill someone.
     /// </summary>
-    [DataField("overfillMutli"), ViewVariables(VVAccess.ReadWrite)]
-    public float OverfillMutli = 5.5f;
+    [DataField("overfillMulti"), ViewVariables(VVAccess.ReadWrite)]
+    public float OverfillMulti = 5.5f;
 
     /// <summary>
     ///     The amount of damage dealt when overfilling someone.
@@ -163,5 +163,5 @@ public sealed class BloodstreamFillerComponent : Component
     /// </summary>
     [DataField("overfilledPopup")]
     public string OverfilledPopup = "bloodfiller-target-overfill";
-    #endregion
+    #endregion Player Feedback
 }
diff --git a/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs b/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
index a42a94112d..cc9bd18852 100644
--- a/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
+++ b/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
@@ -106,7 +106,7 @@ private void TryFill(EntityUid user, EntityUid target, EntityUid filler, Bloodst
         if (fillComp.Overfill && bloodComp.BloodSolution.AvailableVolume == 0 && user != target)
         {
             overfill = true;
-            delay *= fillComp.OverfillMutli;
+            delay *= fillComp.OverfillMulti;
         }
 
         _doAfter.TryStartDoAfter(new DoAfterArgs(user, delay, new BloodstreamFillerDoAfterEvent(overfill), target, target, filler)
@@ -132,12 +132,10 @@ private void TryFill(EntityUid user, EntityUid target, EntityUid filler, Bloodst
 
     private void OnDoAfter(EntityUid uid, BloodstreamComponent component, BloodstreamFillerDoAfterEvent args)
     {
-        if (args.Cancelled)
-        {
+        if (args.Handled || args.Cancelled)
             return;
-        }
 
-        if (args.Handled || args.Args.Target == null)
+        if (args.Args.Target == null)
             return;
 
         if (!TryComp<BloodstreamFillerComponent>(args.Args.Used, out var fillComp))
@@ -182,10 +180,8 @@ private void Fill(EntityUid target, EntityUid filler, BloodstreamFillerComponent
 
     private void Overfill(EntityUid user, EntityUid target, EntityUid filler, BloodstreamFillerComponent fillComp, BloodstreamComponent bloodComp)
     {
-        if (!_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution))
-            return;
-
-        if (!TryComp<DamageableComponent>(target, out var damageableComp))
+        if (!_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution) ||
+            !TryComp<DamageableComponent>(target, out var damageableComp))
             return;
 
         _damageable.TryChangeDamage(target, fillComp.OverfillDamage, origin: user, damageable: damageableComp);
@@ -197,13 +193,9 @@ private void Overfill(EntityUid user, EntityUid target, EntityUid filler, Bloods
 
     private void TryRefill(EntityUid user, EntityUid filler, EntityUid target, BloodstreamFillerComponent fillComp)
     {
-        if (!EntityManager.TryGetComponent<ReagentTankComponent>(target, out _))
-            return;
-
-        if (!_solution.TryGetDrainableSolution(target, out var targetSolution))
-            return;
-
-        if (!_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution))
+        if (!EntityManager.TryGetComponent<ReagentTankComponent>(target, out _) ||
+            !_solution.TryGetDrainableSolution(target, out var targetSolution) ||
+            !_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution))
             return;
 
         // Check that the tank is not empty.
@@ -252,12 +244,8 @@ private void TryRefill(EntityUid user, EntityUid filler, EntityUid target, Blood
             _audio.PlayPvs(fillComp.UseSound, filler);
         }
         else if (fillerSolution.AvailableVolume <= 0)
-        {
             _popup.PopupCursor(Loc.GetString(fillComp.RefillFullPopup, ("filler", filler)), user);
-        }
         else
-        {
             _popup.PopupCursor(Loc.GetString(fillComp.RefillTankEmptyPopup, ("tank", target)), user);
-        }
     }
 }
diff --git a/Content.Shared/SimpleStation14/Silicon/BloodstreamFillerEvents.cs b/Content.Shared/SimpleStation14/Silicon/BloodstreamFillerEvents.cs
index 9dce1045c7..8ed999bdaf 100644
--- a/Content.Shared/SimpleStation14/Silicon/BloodstreamFillerEvents.cs
+++ b/Content.Shared/SimpleStation14/Silicon/BloodstreamFillerEvents.cs
@@ -11,6 +11,7 @@ public sealed class BloodstreamFillerDoAfterEvent : DoAfterEvent
 
     private BloodstreamFillerDoAfterEvent()
     {
+
     }
     public BloodstreamFillerDoAfterEvent(bool overfill)
     {

From d6f27be5fe8faab2bfa30035fbdadfaf034c0471 Mon Sep 17 00:00:00 2001
From: Pspritechologist <81725545+Pspritechologist@users.noreply.github.com>
Date: Mon, 19 Jun 2023 07:36:03 -0400
Subject: [PATCH 6/7] Allowed reagents is now a list

---
 .../Components/BloodstreamFillerComponent.cs  |  4 +--
 .../Systems/BloodstreamFillerSystem.cs        |  4 +--
 .../Objects/Specific/Medical/hypospray.yml    | 26 +++++++++++++++----
 3 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs b/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
index 0745594816..d435331d32 100644
--- a/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
+++ b/Content.Server/SimpleStation14/BloodstreamFiller/Components/BloodstreamFillerComponent.cs
@@ -40,8 +40,8 @@ public sealed class BloodstreamFillerComponent : Component
     /// <remarks>
     ///     If null, any reagent will be allowed.
     /// </remarks>
-    [DataField("reagent"), ViewVariables(VVAccess.ReadWrite)]
-    public string? Reagent = null;
+    [DataField("reagents"), ViewVariables(VVAccess.ReadWrite)]
+    public List<string> Reagents = new();
 
     /// <summary>
     ///     Will this filler only fill Silicons?
diff --git a/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs b/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
index cc9bd18852..5045f65e9c 100644
--- a/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
+++ b/Content.Server/SimpleStation14/BloodstreamFiller/Systems/BloodstreamFillerSystem.cs
@@ -72,7 +72,7 @@ private void TryFill(EntityUid user, EntityUid target, EntityUid filler, Bloodst
         if (!_solution.TryGetSolution(filler, fillComp.Solution!, out var fillerSolution)) // No solution
             return;
 
-        if (fillComp.Reagent != null && fillComp.Reagent != bloodComp.BloodReagent) // Wrong reagent as specified by the component
+        if (fillComp.Reagents.Count > 0 && !fillComp.Reagents.Contains(bloodComp.BloodReagent)) // Wrong reagent as specified by the component
         {
             _popup.PopupCursor(Loc.GetString(fillComp.TargetInvalidPopup, ("filler", filler)), user);
             return;
@@ -214,7 +214,7 @@ private void TryRefill(EntityUid user, EntityUid filler, EntityUid target, Blood
 
         // Check that the tank's solution matches the filler's listed reagent.
         // This is seperate from checking the actual solution to prevent any funny business.
-        if (fillComp.Reagent != null && targetSolution.Contents[0].ReagentId != fillComp.Reagent)
+        if (fillComp.Reagents.Count > 0 && !fillComp.Reagents.Contains(targetSolution.Contents[0].ReagentId))
         {
             _popup.PopupCursor(Loc.GetString(fillComp.RefillReagentInvalidPopup, ("tank", target)), user);
             return;
diff --git a/Resources/Prototypes/SimpleStation14/Entities/Objects/Specific/Medical/hypospray.yml b/Resources/Prototypes/SimpleStation14/Entities/Objects/Specific/Medical/hypospray.yml
index ba40e66a87..2fe77c73a9 100644
--- a/Resources/Prototypes/SimpleStation14/Entities/Objects/Specific/Medical/hypospray.yml
+++ b/Resources/Prototypes/SimpleStation14/Entities/Objects/Specific/Medical/hypospray.yml
@@ -80,11 +80,21 @@
   parent: BloodFillerBase
   id: BloodFillerBlood
   name: bloodfiller
-  description: A pump to inject blood into your body.
+  description: A pump to inject blood into your body. Also accepts Slime.
   components:
+  - type: UseDelay
+    delay: 6
   - type: BloodstreamFiller
-    reagent: Blood
-    amount: 100
+    amount: 60
+    fillTime: 1.3
+    reagents:
+      - Blood
+      - Slime
+	  - Water
+  - type: SolutionContainerManager
+    solutions:
+      filler:
+        maxVol: 120
 
 - type: entity
   parent: BloodFillerBase
@@ -93,5 +103,11 @@
   description: A pump to inject coolant into an IPC.
   components:
   - type: BloodstreamFiller
-    reagent: Water
-    amount: 200
+    reagents: [ Water ]
+    amount: 150
+    fillTime: 0.85
+    siliconOnly: true
+  - type: SolutionContainerManager
+    solutions:
+      filler:
+        maxVol: 250

From f1b3725eba8b3becb30f99eec6d4760c1049f163 Mon Sep 17 00:00:00 2001
From: Cabbage <130223709+SomeCabbage@users.noreply.github.com>
Date: Fri, 30 Jun 2023 02:25:45 -0400
Subject: [PATCH 7/7] blood filler cargo orders (#173)

# Description
Adds the slime tank and blood tank orders to cargo for 2.5k each
---
 .../Catalog/Cargo/cargo_medical.yml           | 23 +++++++++++++++++++
 .../Catalog/Fills/Crates/medical.yml          | 21 +++++++++++++++++
 2 files changed, 44 insertions(+)
 create mode 100644 Resources/Prototypes/SimpleStation14/Catalog/Cargo/cargo_medical.yml
 create mode 100644 Resources/Prototypes/SimpleStation14/Catalog/Fills/Crates/medical.yml

diff --git a/Resources/Prototypes/SimpleStation14/Catalog/Cargo/cargo_medical.yml b/Resources/Prototypes/SimpleStation14/Catalog/Cargo/cargo_medical.yml
new file mode 100644
index 0000000000..b2bec36ff7
--- /dev/null
+++ b/Resources/Prototypes/SimpleStation14/Catalog/Cargo/cargo_medical.yml
@@ -0,0 +1,23 @@
+- type: cargoProduct
+  id: MedicalBloodTank
+  name: Blood tank crate
+  description: "Contains a tank of blood."
+  icon:
+    sprite: SimpleStation14/Structures/Storage/tanks.rsi
+    state: bloodtankblood
+  product: CrateMedicalBloodTank
+  cost: 2500
+  category: Medical
+  group: market
+
+- type: cargoProduct
+  id: MedicalSlimeTank
+  name: slime tank crate
+  description: "Contains a tank of slime."
+  icon:
+    sprite: SimpleStation14/Structures/Storage/tanks.rsi
+    state: bloodtankblood
+  product: CrateMedicalSlimeTank
+  cost: 2500
+  category: Medical
+  group: market
diff --git a/Resources/Prototypes/SimpleStation14/Catalog/Fills/Crates/medical.yml b/Resources/Prototypes/SimpleStation14/Catalog/Fills/Crates/medical.yml
new file mode 100644
index 0000000000..d77447d901
--- /dev/null
+++ b/Resources/Prototypes/SimpleStation14/Catalog/Fills/Crates/medical.yml
@@ -0,0 +1,21 @@
+- type: entity
+  id: CrateMedicalBloodTank
+  name: blood tank crate
+  description: "Contains a tank of blood."
+  parent: CrateMedicalSecure
+  components:
+  - type: StorageFill
+    contents:
+      - id: BloodTankBloodFull
+        amount: 1
+
+- type: entity
+  id: CrateMedicalSlimeTank
+  name: slime tank crate
+  description: "Contains a tank of slime."
+  parent: CrateMedicalSecure
+  components:
+  - type: StorageFill
+    contents:
+      - id: BloodTankSlimeFull
+        amount: 1