diff --git a/Content.Client/_NF/Chemistry/UI/ChemPrenticeBoundUserInterface.cs b/Content.Client/_NF/Chemistry/UI/ChemPrenticeBoundUserInterface.cs
new file mode 100644
index 00000000000..d10d645c17d
--- /dev/null
+++ b/Content.Client/_NF/Chemistry/UI/ChemPrenticeBoundUserInterface.cs
@@ -0,0 +1,63 @@
+using Content.Client.Chemistry.UI;
+using Content.Shared._NF.Chemistry;
+using Content.Shared.Chemistry;
+using Content.Shared.Containers.ItemSlots;
+using JetBrains.Annotations;
+using Robust.Client.GameObjects;
+using Robust.Client.UserInterface;
+
+namespace Content.Client._NF.Chemistry.UI
+{
+ ///
+ /// Initializes a and updates it when new server messages are received.
+ ///
+ [UsedImplicitly]
+ public sealed class ChemPrenticeBoundUserInterface : BoundUserInterface
+ {
+ [ViewVariables]
+ private ChemPrenticeWindow? _window;
+
+ public ChemPrenticeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+ {
+ }
+
+ ///
+ /// Called each time a chem master UI instance is opened. Generates the window and fills it with
+ /// relevant info. Sets the actions for static buttons.
+ ///
+ protected override void Open()
+ {
+ base.Open();
+
+ // Setup window layout/elements
+ _window = this.CreateWindow();
+ _window.Title = EntMan.GetComponent(Owner).EntityName;
+
+ // Setup static button actions.
+ _window.InputEjectButton.OnPressed += _ => SendMessage(
+ new ItemSlotButtonPressedEvent(SharedChemMaster.InputSlotName));
+ _window.BufferTransferButton.OnPressed += _ => SendMessage(
+ new ChemMasterSetModeMessage(ChemMasterMode.Transfer));
+ _window.BufferDiscardButton.OnPressed += _ => SendMessage(
+ new ChemMasterSetModeMessage(ChemMasterMode.Discard));
+
+ _window.OnReagentButtonPressed += (_, button) => SendMessage(new ChemMasterReagentAmountButtonMessage(button.Id, button.Amount, button.IsBuffer));
+ }
+
+ ///
+ /// Update the ui each time new state data is sent from the server.
+ ///
+ ///
+ /// Data of the that this ui represents.
+ /// Sent from the server.
+ ///
+ protected override void UpdateState(BoundUserInterfaceState state)
+ {
+ base.UpdateState(state);
+
+ var castState = (ChemPrenticeBoundUserInterfaceState)state;
+
+ _window?.UpdateState(castState); // Update window state
+ }
+ }
+}
diff --git a/Content.Client/_NF/Chemistry/UI/ChemPrenticeWindow.xaml b/Content.Client/_NF/Chemistry/UI/ChemPrenticeWindow.xaml
new file mode 100644
index 00000000000..370d200348f
--- /dev/null
+++ b/Content.Client/_NF/Chemistry/UI/ChemPrenticeWindow.xaml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/_NF/Chemistry/UI/ChemPrenticeWindow.xaml.cs b/Content.Client/_NF/Chemistry/UI/ChemPrenticeWindow.xaml.cs
new file mode 100644
index 00000000000..f8f3e5fc21b
--- /dev/null
+++ b/Content.Client/_NF/Chemistry/UI/ChemPrenticeWindow.xaml.cs
@@ -0,0 +1,247 @@
+using Content.Client.Stylesheets;
+using Content.Client.UserInterface.Controls;
+using Content.Shared.Chemistry;
+using Content.Shared._NF.Chemistry;
+using Content.Shared.Chemistry.Reagent;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Client.Utility;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+using System.Linq;
+using System.Numerics;
+using Content.Shared.FixedPoint;
+using static Robust.Client.UserInterface.Controls.BoxContainer;
+using Content.Client.Chemistry.UI;
+using Content.Client.Info;
+
+namespace Content.Client._NF.Chemistry.UI
+{
+ ///
+ /// Client-side UI used to control a
+ ///
+ [GenerateTypedNameReferences]
+ public sealed partial class ChemPrenticeWindow : FancyWindow
+ {
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ public event Action? OnReagentButtonPressed;
+
+ ///
+ /// Create and initialize the chem master UI client-side. Creates the basic layout,
+ /// actual data isn't filled in until the server sends data about the chem master.
+ ///
+ public ChemPrenticeWindow()
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+ }
+
+ private ReagentButton MakeReagentButton(string text, ChemMasterReagentAmount amount, ReagentId id, bool isBuffer, string styleClass)
+ {
+ var button = new ReagentButton(text, amount, id, isBuffer, styleClass);
+ button.OnPressed += args
+ => OnReagentButtonPressed?.Invoke(args, button);
+ return button;
+ }
+
+ ///
+ /// Update the UI state when new state data is received from the server.
+ ///
+ /// State data sent by the server.
+ public void UpdateState(BoundUserInterfaceState state)
+ {
+ var castState = (ChemPrenticeBoundUserInterfaceState)state;
+ UpdatePanelInfo(castState);
+
+ //BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u";
+
+ InputEjectButton.Disabled = castState.InputContainerInfo is null;
+
+ }
+
+ ///
+ /// Generate a product label based on reagents in the buffer.
+ ///
+ /// State data sent by the server.
+ private string GenerateLabel(ChemPrenticeBoundUserInterfaceState state)
+ {
+ if (state.BufferCurrentVolume == 0)
+ return "";
+
+ var reagent = state.BufferReagents.OrderBy(r => r.Quantity).First().Reagent;
+ _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
+ return proto?.LocalizedName ?? "";
+ }
+
+ ///
+ /// Update the container, buffer, and packaging panels.
+ ///
+ /// State data for the dispenser.
+ private void UpdatePanelInfo(ChemPrenticeBoundUserInterfaceState state)
+ {
+ BufferTransferButton.Pressed = state.Mode == ChemMasterMode.Transfer;
+ BufferDiscardButton.Pressed = state.Mode == ChemMasterMode.Discard;
+
+ BuildContainerUI(InputContainerInfo, state.InputContainerInfo, true);
+
+ BufferInfo.Children.Clear();
+
+ if (!state.BufferReagents.Any())
+ {
+ BufferInfo.Children.Add(new Label { Text = Loc.GetString("chem-master-window-buffer-empty-text") });
+
+ return;
+ }
+
+ var bufferHBox = new BoxContainer
+ {
+ Orientation = LayoutOrientation.Horizontal
+ };
+ BufferInfo.AddChild(bufferHBox);
+
+ var bufferLabel = new Label { Text = $"{Loc.GetString("chem-master-window-buffer-label")} " };
+ bufferHBox.AddChild(bufferLabel);
+ var bufferVol = new Label
+ {
+ Text = $"{state.BufferCurrentVolume}/{state.BufferMaxVolume}",
+ StyleClasses = { StyleNano.StyleClassLabelSecondaryColor }
+ };
+ bufferHBox.AddChild(bufferVol);
+
+ foreach (var (reagent, quantity) in state.BufferReagents.OrderBy(x => x.Reagent.Prototype)) // Frontier: add OrderBy
+ {
+ // Try to get the prototype for the given reagent. This gives us its name.
+ _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
+ var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
+
+ if (proto != null)
+ {
+ BufferInfo.Children.Add(new BoxContainer
+ {
+ Orientation = LayoutOrientation.Horizontal,
+ Children =
+ {
+ new Label {Text = $"{name}: "},
+ new Label
+ {
+ Text = $"{quantity}u",
+ StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
+ },
+
+ // Padding
+ new Control {HorizontalExpand = true},
+
+ MakeReagentButton("1", ChemMasterReagentAmount.U1, reagent, true, StyleBase.ButtonOpenRight),
+ MakeReagentButton("5", ChemMasterReagentAmount.U5, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton("10", ChemMasterReagentAmount.U10, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton("25", ChemMasterReagentAmount.U25, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton("50", ChemMasterReagentAmount.U50, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton("100", ChemMasterReagentAmount.U100, reagent, true, StyleBase.ButtonOpenBoth),
+ MakeReagentButton(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, reagent, true, StyleBase.ButtonOpenLeft),
+ }
+ });
+ }
+ }
+ }
+
+ private void BuildContainerUI(Control control, ContainerInfo? info, bool addReagentButtons)
+ {
+ control.Children.Clear();
+
+ if (info is null)
+ {
+ control.Children.Add(new Label
+ {
+ Text = Loc.GetString("chem-master-window-no-container-loaded-text")
+ });
+ }
+ else
+ {
+ // Name of the container and its fill status (Ex: 44/100u)
+ control.Children.Add(new BoxContainer
+ {
+ Orientation = LayoutOrientation.Horizontal,
+ Children =
+ {
+ new Label {Text = $"{info.DisplayName}: "},
+ new Label
+ {
+ Text = $"{info.CurrentVolume}/{info.MaxVolume}",
+ StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
+ }
+ }
+ });
+
+ IEnumerable<(string Name, ReagentId Id, FixedPoint2 Quantity)> contents;
+
+ if (info.Entities != null)
+ {
+ contents = info.Entities.Select(x => (x.Id, default(ReagentId), x.Quantity));
+ }
+ else if (info.Reagents != null)
+ {
+ contents = info.Reagents.Select(x =>
+ {
+ _prototypeManager.TryIndex(x.Reagent.Prototype, out ReagentPrototype? proto);
+ var name = proto?.LocalizedName
+ ?? Loc.GetString("chem-master-window-unknown-reagent-text");
+
+ return (name, Id: x.Reagent, x.Quantity);
+ })
+ .OrderBy(r => r.Item1);
+ }
+ else
+ {
+ return;
+ }
+
+
+ foreach (var (name, id, quantity) in contents)
+ {
+ var inner = new BoxContainer
+ {
+ Orientation = LayoutOrientation.Horizontal,
+ Children =
+ {
+ new Label { Text = $"{name}: " },
+ new Label
+ {
+ Text = $"{quantity}u",
+ StyleClasses = { StyleNano.StyleClassLabelSecondaryColor },
+ }
+ }
+ };
+
+ if (addReagentButtons)
+ {
+ var cs = inner.Children;
+
+ // Padding
+ cs.Add(new Control { HorizontalExpand = true });
+
+ cs.Add(MakeReagentButton(
+ "1", ChemMasterReagentAmount.U1, id, false, StyleBase.ButtonOpenRight));
+ cs.Add(MakeReagentButton(
+ "5", ChemMasterReagentAmount.U5, id, false, StyleBase.ButtonOpenBoth));
+ cs.Add(MakeReagentButton(
+ "10", ChemMasterReagentAmount.U10, id, false, StyleBase.ButtonOpenBoth));
+ cs.Add(MakeReagentButton(
+ "25", ChemMasterReagentAmount.U25, id, false, StyleBase.ButtonOpenBoth));
+ cs.Add(MakeReagentButton(
+ "50", ChemMasterReagentAmount.U50, id, false, StyleBase.ButtonOpenBoth));
+ cs.Add(MakeReagentButton(
+ "100", ChemMasterReagentAmount.U100, id, false, StyleBase.ButtonOpenBoth));
+ cs.Add(MakeReagentButton(
+ Loc.GetString("chem-master-window-buffer-all-amount"),
+ ChemMasterReagentAmount.All, id, false, StyleBase.ButtonOpenLeft));
+ }
+
+ control.Children.Add(inner);
+ }
+
+ }
+ }
+ }
+}
diff --git a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs
index c733c7215ee..82396864ce1 100644
--- a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs
@@ -32,6 +32,7 @@ public sealed class ChemMasterSystem : EntitySystem
{
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly AudioSystem _audioSystem = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; //Frontier
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
@@ -70,6 +71,7 @@ private void UpdateUiState(Entity ent, bool updateLabel = f
if (!_solutionContainerSystem.TryGetSolution(owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution))
return;
var inputContainer = _itemSlotsSystem.GetItemOrNull(owner, SharedChemMaster.InputSlotName);
+ _appearanceSystem.SetData(owner, ChemMasterVisualState.BeakerInserted, inputContainer.HasValue); //Frontier
var outputContainer = _itemSlotsSystem.GetItemOrNull(owner, SharedChemMaster.OutputSlotName);
var bufferReagents = bufferSolution.Contents;
diff --git a/Content.Server/_NF/Chemistry/Components/ChemPrenticeComponent.cs b/Content.Server/_NF/Chemistry/Components/ChemPrenticeComponent.cs
new file mode 100644
index 00000000000..924c51d8154
--- /dev/null
+++ b/Content.Server/_NF/Chemistry/Components/ChemPrenticeComponent.cs
@@ -0,0 +1,22 @@
+using Content.Server._NF.Chemistry.EntitySystems;
+using Content.Shared._NF.Chemistry;
+using Content.Shared.Chemistry;
+using Robust.Shared.Audio;
+
+namespace Content.Server.Chemistry.Components
+{
+ ///
+ /// An industrial grade chemical manipulator with pill and bottle production included.
+ ///
+ ///
+ [RegisterComponent]
+ [Access(typeof(ChemPrenticeSystem))]
+ public sealed partial class ChemPrenticeComponent : Component
+ {
+ [DataField("mode"), ViewVariables(VVAccess.ReadWrite)]
+ public ChemMasterMode Mode = ChemMasterMode.Transfer;
+
+ [DataField("clickSound"), ViewVariables(VVAccess.ReadWrite)]
+ public SoundSpecifier ClickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
+ }
+}
diff --git a/Content.Server/_NF/Chemistry/EntitySystems/ChemPrenticeSystem.cs b/Content.Server/_NF/Chemistry/EntitySystems/ChemPrenticeSystem.cs
new file mode 100644
index 00000000000..609e743be2e
--- /dev/null
+++ b/Content.Server/_NF/Chemistry/EntitySystems/ChemPrenticeSystem.cs
@@ -0,0 +1,194 @@
+using Content.Server.Chemistry.Components;
+using Content.Server.Labels;
+using Content.Server.Popups;
+using Content.Server.Storage.EntitySystems;
+using Content.Shared._NF.Chemistry;
+using Content.Shared.Administration.Logs;
+using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Containers.ItemSlots;
+using Content.Shared.Database;
+using Content.Shared.FixedPoint;
+using Content.Shared.Kitchen;
+using Content.Shared.Storage;
+using JetBrains.Annotations;
+using Robust.Server.Audio;
+using Robust.Server.GameObjects;
+using Robust.Shared.Audio;
+using Robust.Shared.Containers;
+using Robust.Shared.Prototypes;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+
+namespace Content.Server._NF.Chemistry.EntitySystems
+{
+
+ ///
+ /// Contains all the server-side logic for ChemPrentices.
+ ///
+ ///
+ [UsedImplicitly]
+ public sealed class ChemPrenticeSystem : EntitySystem
+ {
+ [Dependency] private readonly PopupSystem _popupSystem = default!;
+ [Dependency] private readonly AudioSystem _audioSystem = default!;
+ [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
+ [Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
+ [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
+ [Dependency] private readonly StorageSystem _storageSystem = default!;
+ [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(SubscribeUpdateUiState);
+ SubscribeLocalEvent(SubscribeUpdateUiState);
+ SubscribeLocalEvent(SubscribeUpdateUiState);
+ SubscribeLocalEvent(SubscribeUpdateUiState);
+ SubscribeLocalEvent(SubscribeUpdateUiState);
+ SubscribeLocalEvent(OnSetModeMessage);
+ SubscribeLocalEvent(OnReagentButtonMessage);
+ }
+
+ private void SubscribeUpdateUiState(Entity ent, ref T ev)
+ {
+ UpdateUiState(ent);
+ }
+
+ private void UpdateUiState(Entity ent, bool updateLabel = false)
+ {
+ var (owner, chemPrentice) = ent;
+ if (!_solutionContainerSystem.TryGetSolution(owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution))
+ {
+ return;
+ }
+ var inputContainer = _itemSlotsSystem.GetItemOrNull(owner, SharedChemMaster.InputSlotName);
+ _appearanceSystem.SetData(owner, ChemMasterVisualState.BeakerInserted, inputContainer.HasValue);
+
+ var bufferReagents = bufferSolution.Contents;
+ var bufferCurrentVolume = bufferSolution.Volume;
+ var bufferMaxVolume = bufferSolution.MaxVolume;
+
+ var state = new ChemPrenticeBoundUserInterfaceState(
+ chemPrentice.Mode, BuildInputContainerInfo(inputContainer),
+ bufferReagents, bufferCurrentVolume, bufferMaxVolume);
+
+ _userInterfaceSystem.SetUiState(owner, ChemPrenticeUiKey.Key, state);
+ }
+
+ private void OnSetModeMessage(Entity ChemPrentice, ref ChemMasterSetModeMessage message)
+ {
+ // Ensure the mode is valid, either Transfer or Discard.
+ if (!Enum.IsDefined(typeof(ChemMasterMode), message.ChemMasterMode))
+ return;
+
+ ChemPrentice.Comp.Mode = message.ChemMasterMode;
+ UpdateUiState(ChemPrentice);
+ ClickSound(ChemPrentice);
+ }
+
+ private void OnReagentButtonMessage(Entity ChemPrentice, ref ChemMasterReagentAmountButtonMessage message)
+ {
+ // Ensure the amount corresponds to one of the reagent amount buttons.
+ if (!Enum.IsDefined(typeof(ChemMasterReagentAmount), message.Amount))
+ return;
+
+ switch (ChemPrentice.Comp.Mode)
+ {
+ case ChemMasterMode.Transfer:
+ TransferReagents(ChemPrentice, message.ReagentId, message.Amount.GetFixedPoint(), message.FromBuffer);
+ break;
+ case ChemMasterMode.Discard:
+ DiscardReagents(ChemPrentice, message.ReagentId, message.Amount.GetFixedPoint(), message.FromBuffer);
+ break;
+ default:
+ // Invalid mode.
+ return;
+ }
+
+ ClickSound(ChemPrentice);
+ }
+
+ private void TransferReagents(Entity ChemPrentice, ReagentId id, FixedPoint2 amount, bool fromBuffer)
+ {
+ var container = _itemSlotsSystem.GetItemOrNull(ChemPrentice, SharedChemMaster.InputSlotName);
+ if (container is null ||
+ !_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSoln, out var containerSolution) ||
+ !_solutionContainerSystem.TryGetSolution(ChemPrentice.Owner, SharedChemMaster.BufferSolutionName, out var bufferSolutionComponent, out var bufferSolution))
+ {
+ return;
+ }
+
+ if (fromBuffer) // Buffer to container
+ {
+ amount = FixedPoint2.Min(amount, containerSolution.AvailableVolume);
+ amount = bufferSolution.RemoveReagent(id, amount, preserveOrder: true);
+ _solutionContainerSystem.TryAddReagent(containerSoln.Value, id, amount, out var _);
+ }
+ else // Container to buffer
+ {
+ amount = FixedPoint2.Min(amount, containerSolution.GetReagentQuantity(id), bufferSolution.AvailableVolume);
+ _solutionContainerSystem.RemoveReagent(containerSoln.Value, id, amount);
+ _solutionContainerSystem.TryAddReagent(bufferSolutionComponent.Value, id, amount, out var _);
+ //bufferSolution.AddReagent(id, amount);
+ }
+
+ UpdateUiState(ChemPrentice, updateLabel: true);
+ }
+
+ private void DiscardReagents(Entity ChemPrentice, ReagentId id, FixedPoint2 amount, bool fromBuffer)
+ {
+ if (fromBuffer)
+ {
+ if (_solutionContainerSystem.TryGetSolution(ChemPrentice.Owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution))
+ bufferSolution.RemoveReagent(id, amount, preserveOrder: true);
+ else
+ return;
+ }
+ else
+ {
+ var container = _itemSlotsSystem.GetItemOrNull(ChemPrentice, SharedChemMaster.InputSlotName);
+ if (container is not null &&
+ _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution, out _))
+ {
+ _solutionContainerSystem.RemoveReagent(containerSolution.Value, id, amount);
+ }
+ else
+ return;
+ }
+
+ UpdateUiState(ChemPrentice, updateLabel: fromBuffer);
+ }
+
+ private void ClickSound(Entity ChemPrentice)
+ {
+ _audioSystem.PlayPvs(ChemPrentice.Comp.ClickSound, ChemPrentice, AudioParams.Default.WithVolume(-2f));
+ }
+
+ private ContainerInfo? BuildInputContainerInfo(EntityUid? container)
+ {
+ if (container is not { Valid: true })
+ return null;
+
+ if (!TryComp(container, out FitsInDispenserComponent? fits)
+ || !_solutionContainerSystem.TryGetSolution(container.Value, fits.Solution, out _, out var solution))
+ {
+ return null;
+ }
+
+ return BuildContainerInfo(Name(container.Value), solution);
+ }
+
+ private static ContainerInfo BuildContainerInfo(string name, Solution solution)
+ {
+ return new ContainerInfo(name, solution.Volume, solution.MaxVolume)
+ {
+ Reagents = solution.Contents
+ };
+ }
+ }
+}
diff --git a/Content.Shared/Chemistry/SharedChemMaster.cs b/Content.Shared/Chemistry/SharedChemMaster.cs
index 762131d7612..c895b87d0e6 100644
--- a/Content.Shared/Chemistry/SharedChemMaster.cs
+++ b/Content.Shared/Chemistry/SharedChemMaster.cs
@@ -89,6 +89,12 @@ public enum ChemMasterMode
Discard,
}
+ [Serializable, NetSerializable]
+ public enum ChemMasterVisualState : byte //Frontier
+ {
+ BeakerInserted
+ }
+
public enum ChemMasterReagentAmount
{
U1 = 1,
diff --git a/Content.Shared/_NF/Chemistry/SharedChemPrentice.cs b/Content.Shared/_NF/Chemistry/SharedChemPrentice.cs
new file mode 100644
index 00000000000..bf07d475d43
--- /dev/null
+++ b/Content.Shared/_NF/Chemistry/SharedChemPrentice.cs
@@ -0,0 +1,45 @@
+using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared._NF.Chemistry
+{
+ ///
+ /// This class holds constants that are shared between client and server.
+ ///
+
+ [Serializable, NetSerializable]
+ public sealed class ChemPrenticeBoundUserInterfaceState : BoundUserInterfaceState
+ {
+ public readonly ContainerInfo? InputContainerInfo;
+
+ ///
+ /// A list of the reagents and their amounts within the buffer, if applicable.
+ ///
+ public readonly IReadOnlyList BufferReagents;
+
+ public readonly ChemMasterMode Mode;
+
+ public readonly FixedPoint2? BufferCurrentVolume;
+
+ public readonly FixedPoint2? BufferMaxVolume;
+
+ public ChemPrenticeBoundUserInterfaceState(
+ ChemMasterMode mode, ContainerInfo? inputContainerInfo,
+ IReadOnlyList bufferReagents, FixedPoint2 bufferCurrentVolume, FixedPoint2? bufferMaxVolume)
+ {
+ InputContainerInfo = inputContainerInfo;
+ BufferReagents = bufferReagents;
+ Mode = mode;
+ BufferCurrentVolume = bufferCurrentVolume;
+ BufferMaxVolume = bufferMaxVolume;
+ }
+ }
+
+ [Serializable, NetSerializable]
+ public enum ChemPrenticeUiKey
+ {
+ Key
+ }
+}
diff --git a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml
index d78ed1182cd..e3b18dbafbc 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml
@@ -11,6 +11,7 @@
snapCardinals: true
layers:
- state: mixer_empty
+ map: ["BeakerInserted"] #Frontier
- state: mixer_screens
shader: unshaded
map: ["enum.PowerDeviceVisualLayers.Powered"]
@@ -61,6 +62,10 @@
enum.PowerDeviceVisualLayers.Powered:
True: { visible: true }
False: { visible: false }
+ enum.ChemMasterVisualState.BeakerInserted: #Frontier
+ BeakerInserted: #Frontier
+ True: {state: "mixer_loaded"} #Frontier
+ False: {state: "mixer_empty"} #Frontier
# Machine / Construction stuff
- type: WiresPanel
- type: Machine
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index d58917ff8a2..076054ad3d3 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -530,6 +530,7 @@
- VaccinatorMachineCircuitboard
- DiagnoserMachineCircuitboard
- ChemMasterMachineCircuitboard
+ - ChemPrenticeMachineCircuitboard #Frontier
- ChemDispenserMachineCircuitboard
- BiomassReclaimerMachineCircuitboard
- BiogeneratorMachineCircuitboard # Frontier BiofabricatorMachineCircuitboard