diff --git a/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerComponent.cs b/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerComponent.cs
new file mode 100644
index 0000000000..680b8905f2
--- /dev/null
+++ b/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerComponent.cs
@@ -0,0 +1,40 @@
+
+using Content.Shared.FixedPoint;
+using Robust.Shared.Audio;
+
+namespace Content.Server._CP14.Alchemy;
+
+///
+/// gradually rounds down all reagents in the specified solution
+///
+[RegisterComponent, Access(typeof(CP14SolutionNormalizerSystem))]
+public sealed partial class CP14SolutionNormalizerComponent : Component
+{
+ [DataField(required: true)]
+ public string Solution = string.Empty;
+
+ ///
+ /// will round down any reagent in solution until it is divisible by this value
+ ///
+ [DataField]
+ public float Factor = 0.25f;
+
+ ///
+ /// the reagent will flow gradually by the specified number until it becomes normalized
+ ///
+ [DataField]
+ public FixedPoint2 LeakageQuantity = 0.05f;
+
+ [DataField]
+ public TimeSpan UpdateFrequency = TimeSpan.FromSeconds(4f);
+
+ [DataField]
+ public TimeSpan NextUpdateTime = TimeSpan.Zero;
+
+ [DataField]
+ public SoundSpecifier NormalizeSound = new SoundPathSpecifier("/Audio/Ambience/Objects/drain.ogg")
+ {
+ Params = AudioParams.Default.WithVariation(0.03f)
+ };
+}
+
diff --git a/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerSystem.cs b/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerSystem.cs
new file mode 100644
index 0000000000..b8c4305a2c
--- /dev/null
+++ b/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerSystem.cs
@@ -0,0 +1,67 @@
+using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Audio.Systems;
+using Robust.Shared.Timing;
+
+namespace Content.Server._CP14.Alchemy;
+
+public sealed partial class CP14SolutionNormalizerSystem : EntitySystem
+{
+ [Dependency] private readonly SharedAudioSystem _audio = default!;
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+
+ while (query.MoveNext(out var uid, out var normalizer, out var containerManager))
+ {
+ if (_timing.CurTime <= normalizer.NextUpdateTime)
+ continue;
+
+ normalizer.NextUpdateTime = _timing.CurTime + normalizer.UpdateFrequency;
+
+ var solutionManager = new Entity(uid, containerManager);
+
+ if (!_solutionContainer.TryGetSolution(solutionManager,
+ normalizer.Solution,
+ out var solutionEnt,
+ out var solution))
+ continue;
+
+ if (solution.Volume == 0)
+ continue;
+
+ Dictionary affect = new();
+ foreach (var (id, quantity) in solution.Contents)
+ {
+ FixedPoint2 roundedQuantity = Math.Floor((float) quantity / normalizer.Factor) * normalizer.Factor;
+
+ var leakQuantity = quantity - roundedQuantity;
+
+ if (leakQuantity == 0) continue;
+
+ if (quantity - normalizer.LeakageQuantity < roundedQuantity)
+ affect.Add(id, leakQuantity);
+ else
+ affect.Add(id, normalizer.LeakageQuantity);
+ }
+
+ if (affect.Count > 0)
+ {
+ //Telegraphy
+ _audio.PlayPvs(normalizer.NormalizeSound, uid);
+
+ foreach (var (id, count) in affect)
+ {
+ _solutionContainer.RemoveReagent(solutionEnt.Value, id, count);
+ }
+ }
+ }
+ }
+}
diff --git a/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs b/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs
index 1620344652..e282d8c375 100644
--- a/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs
+++ b/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs
@@ -16,7 +16,7 @@ public abstract class SharedInjectorSystem : EntitySystem
///
/// Default transfer amounts for the set-transfer verb.
///
- public static readonly FixedPoint2[] TransferAmounts = { 1, 5, 10, 15 };
+ public static readonly FixedPoint2[] TransferAmounts = {0.25f, 1, 5, 10, 15};//{ 1, 5, 10, 15 }; // CP14 0.25 needed
[Dependency] protected readonly SharedPopupSystem Popup = default!;
[Dependency] protected readonly SharedSolutionContainerSystem SolutionContainers = default!;
diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml
index dd15a90baa..9a41b21d13 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml
@@ -264,6 +264,7 @@
name: dropper
parent: BaseItem
description: Used to transfer small amounts of chemical solution between containers.
+ noSpawn: true
id: Dropper
components:
- type: Sprite
@@ -307,6 +308,7 @@
name: borgdropper
parent: Dropper
description: Used to transfer small amounts of chemical solution between containers. Extended for use by medical borgs.
+ noSpawn: true
id: BorgDropper
components:
- type: Sprite
diff --git a/Resources/Prototypes/_CP14/Entities/Objects/Specific/Alchemy/tools.yml b/Resources/Prototypes/_CP14/Entities/Objects/Specific/Alchemy/tools.yml
index 2f52f61057..084713d834 100644
--- a/Resources/Prototypes/_CP14/Entities/Objects/Specific/Alchemy/tools.yml
+++ b/Resources/Prototypes/_CP14/Entities/Objects/Specific/Alchemy/tools.yml
@@ -46,7 +46,7 @@
ignoreMobs: true
minTransferAmount: 10
maxTransferAmount: 100
- transferAmount: 50
+ transferAmount: 15
toggleState: 1 # draw
- type: UserInterface
interfaces:
@@ -153,4 +153,54 @@
- 0,0,1,1
- type: CP14Mortar
solution: mortar
- containerId: storagebase
\ No newline at end of file
+ containerId: storagebase
+
+- type: entity
+ parent: BaseItem
+ id: CP14Dropper
+ name: dropper
+ description: Small dropper for managing very small values of liquids
+ components:
+ - type: MixableSolution
+ solution: vial
+ - type: FitsInDispenser
+ solution: vial
+ - type: RefillableSolution
+ solution: vial
+ - type: DrainableSolution
+ solution: vial
+ - type: ExaminableSolution
+ solution: vial
+ - type: DrawableSolution
+ solution: vial
+ - type: InjectableSolution
+ solution: vial
+ - type: SolutionItemStatus
+ solution: vial
+ - type: SolutionContainerManager
+ solutions:
+ vial:
+ maxVol: 2
+ - type: UserInterface
+ interfaces:
+ enum.TransferAmountUiKey.Key:
+ type: TransferAmountBoundUserInterface
+ - type: Appearance
+ - type: Injector
+ solutionName: vial
+ injectOnly: false
+ ignoreMobs: true
+ minTransferAmount: 0.25
+ maxTransferAmount: 1
+ transferAmount: 0.25
+ toggleState: 1 # draw
+ - type: Sprite
+ sprite: _CP14/Objects/Specific/Alchemy/dropper.rsi
+ layers:
+ - state: dropper
+ - state: liq-1
+ map: ["enum.SolutionContainerLayers.Fill"]
+ visible: false
+ - type: SolutionContainerVisuals
+ maxFillLevels: 2
+ fillBaseName: liq-
\ No newline at end of file
diff --git a/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/heater.yml b/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/heater.yml
index 6f6b2bbfa1..2a8544e3a9 100644
--- a/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/heater.yml
+++ b/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/heater.yml
@@ -3,6 +3,7 @@
parent: BaseStructure
abstract: true
components:
+ - type: InteractionOutline
- type: Fixtures
fixtures:
fix1:
diff --git a/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/normalizer.yml b/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/normalizer.yml
new file mode 100644
index 0000000000..a2e6ef6983
--- /dev/null
+++ b/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/normalizer.yml
@@ -0,0 +1,54 @@
+- type: entity
+ id: CP14AlchemyNormalizer
+ parent: BaseStructureDynamic
+ name: solution stabilizer
+ description: An alchemical device that removes fine precipitates from solutions, and stabilizes it for further work
+ placement:
+ mode: PlaceFree
+ components:
+ # TODO: energy consuming (magic or fireplace)
+ - type: InteractionOutline
+ - type: Sprite
+ drawdepth: Items
+ noRot: true
+ offset: 0, 0.2
+ sprite: _CP14/Structures/Specific/Alchemy/normalizer.rsi
+ layers:
+ - state: rotate_back
+ - state: liq-1
+ map: ["enum.SolutionContainerLayers.Fill"]
+ visible: false
+ - state: base
+ - state: rotate_front
+ state: base
+ - type: Fixtures
+ fixtures:
+ fix1:
+ shape:
+ !type:PhysShapeAabb
+ bounds: "-0.25,-0.25,0.25,0.25"
+ density: 125
+ mask:
+ - TabletopMachineMask
+ - type: SolutionContainerManager
+ solutions:
+ normalizer:
+ maxVol: 50
+ - type: DrainableSolution
+ solution: normalizer
+ - type: ExaminableSolution
+ solution: normalizer
+ - type: MixableSolution
+ solution: normalizer
+ - type: RefillableSolution
+ solution: normalizer
+ - type: DrawableSolution
+ solution: normalizer
+ - type: DumpableSolution
+ solution: normalizer
+ - type: CP14SolutionNormalizer
+ solution: normalizer
+ - type: Appearance
+ - type: SolutionContainerVisuals
+ maxFillLevels: 5
+ fillBaseName: liq-
\ No newline at end of file
diff --git a/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/dropper.png b/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/dropper.png
new file mode 100644
index 0000000000..e1026b1205
Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/dropper.png differ
diff --git a/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/liq-1.png b/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/liq-1.png
new file mode 100644
index 0000000000..f146b89eb5
Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/liq-1.png differ
diff --git a/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/liq-2.png b/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/liq-2.png
new file mode 100644
index 0000000000..929d6b17eb
Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/liq-2.png differ
diff --git a/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/meta.json b/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/meta.json
new file mode 100644
index 0000000000..7e21d2df46
--- /dev/null
+++ b/Resources/Textures/_CP14/Objects/Specific/Alchemy/dropper.rsi/meta.json
@@ -0,0 +1,20 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "All rights reserved for the CrystallPunk14 project only",
+ "copyright": "Created by TheShuEd (Github) for CrystallPunk14",
+ "states": [
+ {
+ "name": "dropper"
+ },
+ {
+ "name": "liq-1"
+ },
+ {
+ "name": "liq-2"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/base.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/base.png
new file mode 100644
index 0000000000..425e9e3efd
Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/base.png differ
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-1.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-1.png
new file mode 100644
index 0000000000..05fb50034c
Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-1.png differ
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-2.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-2.png
new file mode 100644
index 0000000000..dd49dc62e4
Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-2.png differ
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-3.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-3.png
new file mode 100644
index 0000000000..661bc9c6d6
Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-3.png differ
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-4.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-4.png
new file mode 100644
index 0000000000..d5ae12df7a
Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-4.png differ
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-5.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-5.png
new file mode 100644
index 0000000000..020c8d59a0
Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/liq-5.png differ
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/meta.json b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/meta.json
new file mode 100644
index 0000000000..d45fe7fd2e
--- /dev/null
+++ b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/meta.json
@@ -0,0 +1,51 @@
+{
+ "version": 1,
+ "license": "All rights reserved for the CrystallPunk14 project only",
+ "copyright": "Created by TheShuEd for CrystallPunk14",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "base"
+ },
+ {
+ "name": "liq-1"
+ },
+ {
+ "name": "liq-2"
+ },
+ {
+ "name": "liq-3"
+ },
+ {
+ "name": "liq-4"
+ },
+ {
+ "name": "liq-5"
+ },
+ {
+ "name": "rotate_back",
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "rotate_front",
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_back.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_back.png
new file mode 100644
index 0000000000..8db7051576
Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_back.png differ
diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_front.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_front.png
new file mode 100644
index 0000000000..48b27ceeb5
Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_front.png differ