(uint) _window.BottleDosage.Value, _window.LabelLine));
_window.BufferSortButton.OnPressed += _ => SendMessage(
new ChemMasterSortingTypeCycleMessage());
+ _window.OutputBufferDraw.OnPressed += _ => SendMessage(
+ new ChemMasterOutputDrawSourceMessage(ChemMasterDrawSource.Internal));
+ _window.OutputBeakerDraw.OnPressed += _ => SendMessage(
+ new ChemMasterOutputDrawSourceMessage(ChemMasterDrawSource.External));
for (uint i = 0; i < _window.PillTypeButtons.Length; i++)
{
<!-- Packaging -->
<BoxContainer Orientation="Horizontal">
- <Label Text="{Loc 'chem-master-window-packaging-text'}" />
+ <Label Text="{Loc 'chem-master-output-source'}" StyleClasses="LabelSecondaryColor" Margin="0 0 5 0"/>
+ <Button MinSize="80 0" Name="OutputBufferDraw" Access="Public" Text="{Loc 'chem-master-output-buffer-draw'}" ToggleMode="True" StyleClasses="OpenRight" />
+ <Button MinSize="80 0" Name="OutputBeakerDraw" Access="Public" Text="{Loc 'chem-master-output-beaker-draw'}" ToggleMode="True" StyleClasses="OpenLeft" />
<Control HorizontalExpand="True"/>
- <Label Text="{Loc 'chem-master-window-buffer-label'}" />
- <Label Name="BufferCurrentVolume" StyleClasses="LabelWeak" />
+ <!-- Output Draw Source -->
+ <Label Name="DrawSource"/>
+ <Label Name="BufferCurrentVolume" StyleClasses="LabelSecondaryColor" />
</BoxContainer>
<!-- Wrap the packaging info-->
// Ensure the Panel Info is updated, including UI elements for Buffer Volume, Output Container and so on
UpdatePanelInfo(castState);
- BufferCurrentVolume.Text = $" {castState.BufferCurrentVolume?.Int() ?? 0}u";
+ switch (castState.DrawSource)
+ {
+ case ChemMasterDrawSource.Internal:
+ SetBufferText(castState.BufferCurrentVolume, "chem-master-output-buffer-draw");
+ break;
+ case ChemMasterDrawSource.External:
+ SetBufferText(castState.InputContainerInfo?.CurrentVolume, "chem-master-output-beaker-draw");
+ break;
+ default:
+ throw new($"Chemmaster {castState.OutputContainerInfo} draw source is not set");
+ }
InputEjectButton.Disabled = castState.InputContainerInfo is null;
OutputEjectButton.Disabled = castState.OutputContainerInfo is null;
var holdsReagents = output?.Reagents != null;
var pillNumberMax = holdsReagents ? 0 : remainingCapacity;
var bottleAmountMax = holdsReagents ? remainingCapacity : 0;
- var bufferVolume = castState.BufferCurrentVolume?.Int() ?? 0;
+ var outputVolume = castState.DrawSource switch
+ {
+ ChemMasterDrawSource.Internal => castState.BufferCurrentVolume?.Int() ?? 0,
+ ChemMasterDrawSource.External => castState.InputContainerInfo?.CurrentVolume.Int() ?? 0,
+ _ => 0,
+ };
- PillDosage.Value = (int)Math.Min(bufferVolume, castState.PillDosageLimit);
+ PillDosage.Value = (int)Math.Min(outputVolume, castState.PillDosageLimit);
PillTypeButtons[castState.SelectedPillType].Pressed = true;
// Avoid division by zero
if (PillDosage.Value > 0)
{
- PillNumber.Value = Math.Min(bufferVolume / PillDosage.Value, pillNumberMax);
+ PillNumber.Value = Math.Min(outputVolume / PillDosage.Value, pillNumberMax);
}
else
{
PillNumber.Value = 0;
}
- BottleDosage.Value = Math.Min(bottleAmountMax, bufferVolume);
+ BottleDosage.Value = Math.Min(bottleAmountMax, outputVolume);
}
/// <summary>
- /// Generate a product label based on reagents in the buffer.
+ /// Generate a product label based on reagents in the buffer or beaker.
/// </summary>
/// <param name="state">State data sent by the server.</param>
private string GenerateLabel(ChemMasterBoundUserInterfaceState state)
{
- if (state.BufferCurrentVolume == 0)
+ if (
+ state.BufferCurrentVolume == 0 && state.DrawSource == ChemMasterDrawSource.Internal ||
+ state.InputContainerInfo?.CurrentVolume == 0 && state.DrawSource == ChemMasterDrawSource.External ||
+ state.InputContainerInfo?.Reagents == null
+ )
return "";
- var reagent = state.BufferReagents.OrderBy(r => r.Quantity).First().Reagent;
+ var reagent = (state.DrawSource switch
+ {
+ ChemMasterDrawSource.Internal => state.BufferReagents,
+ ChemMasterDrawSource.External => state.InputContainerInfo.Reagents ?? [],
+ _ => throw new($"Chemmaster {state.OutputContainerInfo} draw source is not set"),
+ }).MinBy(r => r.Quantity)
+ .Reagent;
_prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
return proto?.LocalizedName ?? "";
}
_ => Loc.GetString("chem-master-window-sort-type-none")
};
+ OutputBufferDraw.Pressed = state.DrawSource == ChemMasterDrawSource.Internal;
+ OutputBeakerDraw.Pressed = state.DrawSource == ChemMasterDrawSource.External;
if (!state.BufferReagents.Any())
{
get => LabelLineEdit.Text;
set => LabelLineEdit.Text = value;
}
+
+ private void SetBufferText(FixedPoint2? volume, string text)
+ {
+ BufferCurrentVolume.Text = $" {volume ?? FixedPoint2.Zero}u";
+ DrawSource.Text = Loc.GetString(text);
+ }
}
public sealed class ReagentButton : Button
[DataField("clickSound"), ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier ClickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
+
+ /// <summary>
+ /// Which source the chem master should draw from when making pills/bottles.
+ /// </summary>
+ [DataField]
+ public ChemMasterDrawSource DrawSource = ChemMasterDrawSource.Internal;
}
}
SubscribeLocalEvent<ChemMasterComponent, ChemMasterReagentAmountButtonMessage>(OnReagentButtonMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterCreatePillsMessage>(OnCreatePillsMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterOutputToBottleMessage>(OnOutputToBottleMessage);
+ SubscribeLocalEvent<ChemMasterComponent, ChemMasterOutputDrawSourceMessage>(OnSetDrawSourceMessage);
}
private void SubscribeUpdateUiState<T>(Entity<ChemMasterComponent> ent, ref T ev)
var state = new ChemMasterBoundUserInterfaceState(
chemMaster.Mode, chemMaster.SortingType, BuildInputContainerInfo(inputContainer), BuildOutputContainerInfo(outputContainer),
- bufferReagents, bufferCurrentVolume, chemMaster.PillType, chemMaster.PillDosageLimit, updateLabel);
+ bufferReagents, bufferCurrentVolume, chemMaster.PillType, chemMaster.PillDosageLimit, updateLabel, chemMaster.DrawSource);
_userInterfaceSystem.SetUiState(owner, ChemMasterUiKey.Key, state);
}
ClickSound(chemMaster);
}
+ private void OnSetDrawSourceMessage(Entity<ChemMasterComponent> chemMaster, ref ChemMasterOutputDrawSourceMessage message)
+ {
+ //Ensure draw source is valid, either from the internal buffer or the inserted beaker
+ if (!Enum.IsDefined(message.DrawSource))
+ return;
+
+ chemMaster.Comp.DrawSource = message.DrawSource;
+ UpdateUiState(chemMaster);
+ ClickSound(chemMaster);
+ }
+
private void TransferReagents(Entity<ChemMasterComponent> chemMaster, ReagentId id, FixedPoint2 amount, bool fromBuffer)
{
var container = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.InputSlotName);
return;
var needed = message.Dosage * message.Number;
- if (!WithdrawFromBuffer(chemMaster, needed, user, out var withdrawal))
- return;
+ if (!WithdrawFromSource(chemMaster, needed, user, out var withdrawal))
+ return;
_labelSystem.Label(container, message.Label);
for (var i = 0; i < message.Number; i++)
_storageSystem.Insert(container, item, out _, user: user, storage);
_labelSystem.Label(item, message.Label);
- _solutionContainerSystem.EnsureSolutionEntity(item, SharedChemMaster.PillSolutionName,out var itemSolution ,message.Dosage);
+ _solutionContainerSystem.EnsureSolutionEntity(item,
+ SharedChemMaster.PillSolutionName,
+ out var itemSolution,
+ message.Dosage);
if (!itemSolution.HasValue)
return;
if (message.Label.Length > SharedChemMaster.LabelMaxLength)
return;
- if (!WithdrawFromBuffer(chemMaster, message.Dosage, user, out var withdrawal))
+ if (!WithdrawFromSource(chemMaster, message.Dosage, user, out var withdrawal))
return;
_labelSystem.Label(container, message.Label);
ClickSound(chemMaster);
}
- private bool WithdrawFromBuffer(
+ private bool WithdrawFromSource(
Entity<ChemMasterComponent> chemMaster,
- FixedPoint2 neededVolume, EntityUid? user,
+ FixedPoint2 neededVolume,
+ EntityUid? user,
[NotNullWhen(returnValue: true)] out Solution? outputSolution)
{
outputSolution = null;
- if (!_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out var solution))
- {
- return false;
- }
+ Solution? solution;
+ Entity<SolutionComponent>? soln = null;
- if (solution.Volume == 0)
+ switch (chemMaster.Comp.DrawSource)
{
- if (user.HasValue)
- _popupSystem.PopupCursor(Loc.GetString("chem-master-window-buffer-empty-text"), user.Value);
- return false;
- }
+ case ChemMasterDrawSource.Internal:
+ if (!_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out solution))
+ return false;
- // ReSharper disable once InvertIf
- if (neededVolume > solution.Volume)
- {
- if (user.HasValue)
- _popupSystem.PopupCursor(Loc.GetString("chem-master-window-buffer-low-text"), user.Value);
- return false;
+ if (solution.Volume == 0)
+ {
+ if (user is { } uid)
+ _popupSystem.PopupCursor(Loc.GetString("chem-master-window-buffer-empty-text"), uid);
+
+ return false;
+ }
+ if (neededVolume > solution.Volume)
+ {
+ if (user is { } uid)
+ _popupSystem.PopupCursor(Loc.GetString("chem-master-window-buffer-low-text"), uid);
+
+ return false;
+ }
+
+ break;
+
+ case ChemMasterDrawSource.External:
+ if (_itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.InputSlotName) is not {} container)
+ {
+ if (user.HasValue)
+ _popupSystem.PopupCursor(Loc.GetString("chem-master-window-no-beaker-text"), user.Value);
+ return false;
+ }
+
+ if (!_solutionContainerSystem.TryGetFitsInDispenser(container, out soln, out solution))
+ return false;
+
+ if (solution.Volume == 0)
+ {
+ if (user is { } uid)
+ _popupSystem.PopupCursor(Loc.GetString("chem-master-window-beaker-empty-text"), uid);
+
+ return false;
+ }
+ if (neededVolume > solution.Volume)
+ {
+ if (user is { } uid)
+ _popupSystem.PopupCursor(Loc.GetString("chem-master-window-beaker-low-text"), uid);
+
+ return false;
+ }
+
+ break;
+
+ default:
+ return false;
}
outputSolution = solution.SplitSolution(neededVolume);
+
+ if (soln.HasValue)
+ _solutionContainerSystem.UpdateChemicals(soln.Value);
+
return true;
}
}
}
+ [Serializable, NetSerializable]
+ public sealed class ChemMasterOutputDrawSourceMessage(ChemMasterDrawSource drawSource) : BoundUserInterfaceMessage
+ {
+ public readonly ChemMasterDrawSource DrawSource = drawSource;
+ }
+
public enum ChemMasterMode
{
Transfer,
All,
}
+ public enum ChemMasterDrawSource
+ {
+ Internal,
+ External,
+ }
+
public static class ChemMasterReagentAmountToFixedPoint
{
public static FixedPoint2 GetFixedPoint(this ChemMasterReagentAmount amount)
public readonly bool UpdateLabel;
+ public readonly ChemMasterDrawSource DrawSource;
+
public ChemMasterBoundUserInterfaceState(
ChemMasterMode mode, ChemMasterSortingType sortingType, ContainerInfo? inputContainerInfo, ContainerInfo? outputContainerInfo,
IReadOnlyList<ReagentQuantity> bufferReagents, FixedPoint2 bufferCurrentVolume,
- uint selectedPillType, uint pillDosageLimit, bool updateLabel)
+ uint selectedPillType, uint pillDosageLimit, bool updateLabel, ChemMasterDrawSource drawSource)
{
InputContainerInfo = inputContainerInfo;
OutputContainerInfo = outputContainerInfo;
SelectedPillType = selectedPillType;
PillDosageLimit = pillDosageLimit;
UpdateLabel = updateLabel;
+ DrawSource = drawSource;
}
}
chem-master-window-sort-type-alphabetical = Sort by: Alphabetical
chem-master-window-sort-type-quantity = Sort by: Quantity
chem-master-window-sort-type-latest = Sort by: Recent First
+chem-master-output-buffer-draw = Buffer
+chem-master-output-beaker-draw = Beaker
+chem-master-window-no-beaker-text = No beaker loaded
+chem-master-window-beaker-empty-text = Beaker Empty
+chem-master-window-beaker-low-text = Not enough solution in beaker
+chem-master-output-source = Packaging source:
+chem-master-no-source = No Source