Clean up reagent dispenser and make it slightly better.

This commit is contained in:
Pieter-Jan Briers
2019-10-20 01:30:38 +02:00
parent 9c60d4936d
commit 6630e454c6
8 changed files with 247 additions and 219 deletions

View File

@@ -1,6 +1,7 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Shared.GameObjects.Components.Chemistry;
using JetBrains.Annotations;
using Robust.Client.GameObjects.Components.UserInterface; using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects.Components.UserInterface; using Robust.Shared.GameObjects.Components.UserInterface;
@@ -13,6 +14,7 @@ namespace Content.Client.GameObjects.Components.Chemistry
/// <summary> /// <summary>
/// Initializes a <see cref="ReagentDispenserWindow"/> and updates it when new server messages are received. /// Initializes a <see cref="ReagentDispenserWindow"/> and updates it when new server messages are received.
/// </summary> /// </summary>
[UsedImplicitly]
public class ReagentDispenserBoundUserInterface : BoundUserInterface public class ReagentDispenserBoundUserInterface : BoundUserInterface
{ {
#pragma warning disable 649 #pragma warning disable 649
@@ -42,7 +44,7 @@ namespace Content.Client.GameObjects.Components.Chemistry
Title = _localizationManager.GetString("Reagent dispenser"), Title = _localizationManager.GetString("Reagent dispenser"),
Size = (500, 600) Size = (500, 600)
}; };
_window.OpenCenteredMinSize(); _window.OpenCenteredMinSize();
_window.OnClose += Close; _window.OnClose += Close;
@@ -60,7 +62,10 @@ namespace Content.Client.GameObjects.Components.Chemistry
/// <summary> /// <summary>
/// Update the ui each time new state data is sent from the server. /// Update the ui each time new state data is sent from the server.
/// </summary> /// </summary>
/// <param name="state">Data of the <see cref="ReagentDispenserComponent"/> that this ui represents. Sent from the server.</param> /// <param name="state">
/// Data of the <see cref="SharedReagentDispenserComponent"/> that this ui represents.
/// Sent from the server.
/// </param>
protected override void UpdateState(BoundUserInterfaceState state) protected override void UpdateState(BoundUserInterfaceState state)
{ {
base.UpdateState(state); base.UpdateState(state);
@@ -70,8 +75,6 @@ namespace Content.Client.GameObjects.Components.Chemistry
_window?.UpdateState(castState); //Update window state _window?.UpdateState(castState); //Update window state
UpdateReagentsList(castState.Inventory); //Update reagents list & reagent button actions UpdateReagentsList(castState.Inventory); //Update reagents list & reagent button actions
_window.ForceRunLayoutUpdate();
} }
/// <summary> /// <summary>
@@ -103,7 +106,7 @@ namespace Content.Client.GameObjects.Components.Chemistry
} }
} }
public void ButtonPressed(UiButton button, int dispenseIndex = -1) private void ButtonPressed(UiButton button, int dispenseIndex = -1)
{ {
SendMessage(new UiButtonPressedMessage(button, dispenseIndex)); SendMessage(new UiButtonPressedMessage(button, dispenseIndex));
} }

View File

@@ -1,8 +1,9 @@
using System; using System.Collections.Generic;
using System.Collections.Generic;
using Content.Client.UserInterface; using Content.Client.UserInterface;
using Content.Shared.Chemistry; using Content.Shared.Chemistry;
using Content.Shared.GameObjects.Components.Chemistry;
using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Drawing;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects.Components.UserInterface; using Robust.Shared.GameObjects.Components.UserInterface;
@@ -15,33 +16,39 @@ using static Content.Shared.GameObjects.Components.Chemistry.SharedReagentDispen
namespace Content.Client.GameObjects.Components.Chemistry namespace Content.Client.GameObjects.Components.Chemistry
{ {
/// <summary> /// <summary>
/// Client-side UI used to control a <see cref="ReagentDispenserComponent"/> /// Client-side UI used to control a <see cref="SharedReagentDispenserComponent"/>
/// </summary> /// </summary>
public class ReagentDispenserWindow : SS14Window public class ReagentDispenserWindow : SS14Window
{ {
/// <summary>Sets the dispense amount to 1 when pressed.</summary>
public Button DispenseButton1;
/// <summary>Sets the dispense amount to 5 when pressed.</summary>
public Button DispenseButton5;
/// <summary>Sets the dispense amount to 10 when pressed.</summary>
public Button DispenseButton10;
/// <summary>Sets the dispense amount to 25 when pressed.</summary>
public Button DispenseButton25;
/// <summary>Sets the dispense amount to 50 when pressed.</summary>
public Button DispenseButton50;
/// <summary>Sets the dispense amount to 100 when pressed.</summary>
public Button DispenseButton100;
/// <summary>Contains info about the reagent container such as it's contents, if one is loaded into the dispenser.</summary> /// <summary>Contains info about the reagent container such as it's contents, if one is loaded into the dispenser.</summary>
public VBoxContainer ContainerInfo; private readonly VBoxContainer ContainerInfo;
/// <summary>Sets the dispense amount to 1 when pressed.</summary>
public Button DispenseButton1 { get; }
/// <summary>Sets the dispense amount to 5 when pressed.</summary>
public Button DispenseButton5 { get; }
/// <summary>Sets the dispense amount to 10 when pressed.</summary>
public Button DispenseButton10 { get; }
/// <summary>Sets the dispense amount to 25 when pressed.</summary>
public Button DispenseButton25 { get; }
/// <summary>Sets the dispense amount to 50 when pressed.</summary>
public Button DispenseButton50 { get; }
/// <summary>Sets the dispense amount to 100 when pressed.</summary>
public Button DispenseButton100 { get; }
/// <summary>Ejects the reagent container from the dispenser.</summary> /// <summary>Ejects the reagent container from the dispenser.</summary>
public Button ClearButton; public Button ClearButton { get; }
/// <summary>Removes all reagents from the reagent container.</summary> /// <summary>Removes all reagents from the reagent container.</summary>
public Button EjectButton; public Button EjectButton { get; }
/// <summary>A grid of buttons for each reagent which can be dispensed.</summary> /// <summary>A grid of buttons for each reagent which can be dispensed.</summary>
public GridContainer ChemicalList; public GridContainer ChemicalList { get; }
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IPrototypeManager _prototypeManager; [Dependency] private readonly IPrototypeManager _prototypeManager;
@@ -54,8 +61,9 @@ namespace Content.Client.GameObjects.Components.Chemistry
/// </summary> /// </summary>
public ReagentDispenserWindow() public ReagentDispenserWindow()
{ {
_prototypeManager = IoCManager.Resolve<IPrototypeManager>(); IoCManager.InjectDependencies(this);
_localizationManager = IoCManager.Resolve<ILocalizationManager>();
var dispenseAmountGroup = new ButtonGroup();
Contents.AddChild(new VBoxContainer Contents.AddChild(new VBoxContainer
{ {
@@ -66,16 +74,17 @@ namespace Content.Client.GameObjects.Components.Chemistry
{ {
Children = Children =
{ {
new Label{Text = _localizationManager.GetString("Amount ")}, new Label {Text = _localizationManager.GetString("Amount")},
(DispenseButton1 = new Button{Text = "1"}), new Control {CustomMinimumSize = (20, 0)}, //Padding
(DispenseButton5 = new Button{Text = "5"}), (DispenseButton1 = new Button {Text = "1", Group = dispenseAmountGroup}),
(DispenseButton10 = new Button{Text = "10"}), (DispenseButton5 = new Button {Text = "5", Group = dispenseAmountGroup}),
(DispenseButton25 = new Button{Text = "25"}), (DispenseButton10 = new Button {Text = "10", Group = dispenseAmountGroup}),
(DispenseButton50 = new Button{Text = "50"}), (DispenseButton25 = new Button {Text = "25", Group = dispenseAmountGroup}),
(DispenseButton100 = new Button{Text = "100"}), (DispenseButton50 = new Button {Text = "50", Group = dispenseAmountGroup}),
(DispenseButton100 = new Button {Text = "100", Group = dispenseAmountGroup}),
} }
}, },
new Panel{CustomMinimumSize = (0.0f, 10.0f)}, //Padding new Control {CustomMinimumSize = (0.0f, 10.0f)}, //Padding
(ChemicalList = new GridContainer //Grid of which reagents can be dispensed. (ChemicalList = new GridContainer //Grid of which reagents can be dispensed.
{ {
CustomMinimumSize = (470.0f, 200.0f), CustomMinimumSize = (470.0f, 200.0f),
@@ -83,37 +92,43 @@ namespace Content.Client.GameObjects.Components.Chemistry
SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsHorizontal = SizeFlags.FillExpand,
Columns = 5 Columns = 5
}), }),
new Panel{CustomMinimumSize = (0.0f, 10.0f)}, //Padding new Control {CustomMinimumSize = (0.0f, 10.0f)}, //Padding
new HBoxContainer new HBoxContainer
{ {
Children = Children =
{ {
new Label{Text = _localizationManager.GetString("Container: ")}, new Label {Text = _localizationManager.GetString("Container: ")},
(ClearButton = new Button{Text = _localizationManager.GetString("Clear")}), (ClearButton = new Button {Text = _localizationManager.GetString("Clear")}),
(EjectButton = new Button{Text = _localizationManager.GetString("Eject")}) (EjectButton = new Button {Text = _localizationManager.GetString("Eject")})
} }
}, },
new PanelContainer //Wrap the container info in a PanelContainer so we can color it's background differently. new
{ PanelContainer //Wrap the container info in a PanelContainer so we can color it's background differently.
SizeFlagsVertical = SizeFlags.FillExpand,
SizeFlagsStretchRatio = 6,
PanelOverride = new StyleBoxFlat
{ {
BackgroundColor = new Color(27, 27, 30) SizeFlagsVertical = SizeFlags.FillExpand,
}, SizeFlagsStretchRatio = 6,
Children = PanelOverride = new StyleBoxFlat
{
(ContainerInfo = new VBoxContainer //Currently empty, when server sends state data this will have container contents and fill volume.
{ {
MarginLeft = 5.0f, BackgroundColor = new Color(27, 27, 30)
SizeFlagsHorizontal = SizeFlags.FillExpand, },
Children = Children =
{ {
new Label{Text = _localizationManager.GetString("No container loaded.")} (ContainerInfo =
} new
}), VBoxContainer //Currently empty, when server sends state data this will have container contents and fill volume.
} {
}, MarginLeft = 5.0f,
SizeFlagsHorizontal = SizeFlags.FillExpand,
Children =
{
new Label
{
Text = _localizationManager.GetString("No container loaded.")
}
}
}),
}
},
} }
}); });
} }
@@ -134,13 +149,12 @@ namespace Content.Client.GameObjects.Components.Chemistry
{ {
if (_prototypeManager.TryIndex(entry.ID, out ReagentPrototype proto)) if (_prototypeManager.TryIndex(entry.ID, out ReagentPrototype proto))
{ {
ChemicalList.AddChild(new Button { Text = proto.Name }); ChemicalList.AddChild(new Button {Text = proto.Name});
} }
else else
{ {
ChemicalList.AddChild(new Button { Text = _localizationManager.GetString("Reagent name not found") }); ChemicalList.AddChild(new Button {Text = _localizationManager.GetString("Reagent name not found")});
} }
} }
} }
@@ -150,9 +164,31 @@ namespace Content.Client.GameObjects.Components.Chemistry
/// <param name="state">State data sent by the server.</param> /// <param name="state">State data sent by the server.</param>
public void UpdateState(BoundUserInterfaceState state) public void UpdateState(BoundUserInterfaceState state)
{ {
var castState = (ReagentDispenserBoundUserInterfaceState)state; var castState = (ReagentDispenserBoundUserInterfaceState) state;
Title = castState.DispenserName; Title = castState.DispenserName;
UpdateContainerInfo(castState); UpdateContainerInfo(castState);
switch (castState.SelectedDispenseAmount)
{
case 1:
DispenseButton1.Pressed = true;
break;
case 5:
DispenseButton5.Pressed = true;
break;
case 10:
DispenseButton10.Pressed = true;
break;
case 25:
DispenseButton25.Pressed = true;
break;
case 50:
DispenseButton50.Pressed = true;
break;
case 100:
DispenseButton100.Pressed = true;
break;
}
} }
/// <summary> /// <summary>
@@ -161,83 +197,80 @@ namespace Content.Client.GameObjects.Components.Chemistry
/// </summary> /// </summary>
/// <param name="state">State data for the dispenser.</param> /// <param name="state">State data for the dispenser.</param>
/// <param name="highlightedReagentId">Prototype id of the reagent whose dispense button is currently being mouse hovered.</param> /// <param name="highlightedReagentId">Prototype id of the reagent whose dispense button is currently being mouse hovered.</param>
public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state, string highlightedReagentId = "InvalidReagent") public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state,
string highlightedReagentId = null)
{ {
ContainerInfo.Children.Clear(); ContainerInfo.Children.Clear();
if (state.HasBeaker) //If the dispenser doesn't have a beaker/container don't bother with this.
if (!state.HasBeaker)
{ {
ContainerInfo.Children.Add(new HBoxContainer //Name of the container and it's fill status (Ex: 44/100u) ContainerInfo.Children.Add(new Label {Text = _localizationManager.GetString("No container loaded.")});
return;
}
ContainerInfo.Children.Add(new HBoxContainer // Name of the container and its fill status (Ex: 44/100u)
{
Children =
{ {
Children = new Label {Text = $"{state.ContainerName}: "},
new Label
{ {
new Label{Text = $"{state.ContainerName}: "}, Text = $"{state.BeakerCurrentVolume}/{state.BeakerMaxVolume}",
new Label{Text = $"{state.BeakerCurrentVolume}/{state.BeakerMaxVolume}", StyleClasses = { NanoStyle.StyleClassLabelSecondaryColor }} StyleClasses = {NanoStyle.StyleClassLabelSecondaryColor}
}
});
//List the reagents in the container if it has any at all.
if (state.ContainerReagents != null)
{
//Loop through the reagents in the container.
foreach (var reagent in state.ContainerReagents)
{
//Try to the prototype for the given reagent. This gives us it's name.
if (_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype proto))
{
//Check if the reagent is being moused over. If so, color it green.
if (proto.ID == highlightedReagentId)
{
ContainerInfo.Children.Add(new HBoxContainer
{
Children =
{
new Label {Text = $"{proto.Name}: ", StyleClasses = {NanoStyle.StyleClassPowerStateGood}},
new Label
{
Text = $"{reagent.Quantity}u",
StyleClasses = {NanoStyle.StyleClassPowerStateGood}
}
}
});
}
else //Otherwise, color it the normal colors.
{
ContainerInfo.Children.Add(new HBoxContainer
{
Children =
{
new Label {Text = $"{proto.Name}: "},
new Label
{
Text = $"{reagent.Quantity}u",
StyleClasses = {NanoStyle.StyleClassLabelSecondaryColor}
}
}
});
}
}
else //If you fail to get the reagents name, just call it "Unknown reagent".
{
ContainerInfo.Children.Add(new HBoxContainer
{
Children =
{
new Label {Text = _localizationManager.GetString("Unknown reagent: ")},
new Label
{
Text = $"{reagent.Quantity}u",
StyleClasses = {NanoStyle.StyleClassLabelSecondaryColor}
}
}
});
}
} }
} }
} });
else
if (state.ContainerReagents == null)
{ {
ContainerInfo.Children.Add(new Label{Text = _localizationManager.GetString("No container loaded.")}); return;
}
foreach (var reagent in state.ContainerReagents)
{
var name = _localizationManager.GetString("Unknown reagent");
//Try to the prototype for the given reagent. This gives us it's name.
if (_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype proto))
{
name = proto.Name;
}
//Check if the reagent is being moused over. If so, color it green.
if (proto.ID == highlightedReagentId)
{
ContainerInfo.Children.Add(new HBoxContainer
{
Children =
{
new Label
{
Text = $"{name}: ",
StyleClasses = {NanoStyle.StyleClassPowerStateGood}
},
new Label
{
Text = $"{reagent.Quantity}u",
StyleClasses = {NanoStyle.StyleClassPowerStateGood}
}
}
});
}
else //Otherwise, color it the normal colors.
{
ContainerInfo.Children.Add(new HBoxContainer
{
Children =
{
new Label {Text = $"{name}: "},
new Label
{
Text = $"{reagent.Quantity}u",
StyleClasses = {NanoStyle.StyleClassLabelSecondaryColor}
}
}
});
}
} }
ForceRunLayoutUpdate(); //Force a layout update to avoid text hanging off the window until the user manually resizes it.
} }
} }
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using Content.Server.GameObjects.Components.Sound;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects; using Content.Server.Interfaces.GameObjects;
@@ -8,11 +9,13 @@ using Content.Shared.GameObjects.Components.Chemistry;
using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.Components.Container;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components.Chemistry namespace Content.Server.GameObjects.Components.Chemistry
{ {
@@ -32,14 +35,15 @@ namespace Content.Server.GameObjects.Components.Chemistry
[Dependency] private readonly ILocalizationManager _localizationManager; [Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649 #pragma warning restore 649
private BoundUserInterface _userInterface; [ViewVariables] private BoundUserInterface _userInterface;
private ContainerSlot _beakerContainer; [ViewVariables] private ContainerSlot _beakerContainer;
private string _packPrototypeId; [ViewVariables] private string _packPrototypeId;
public bool HasBeaker => _beakerContainer.ContainedEntity != null; [ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
public int DispenseAmount = 10; [ViewVariables] private int DispenseAmount = 10;
private SolutionComponent _solution => _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>(); [ViewVariables]
private SolutionComponent Solution => _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>();
/// <summary> /// <summary>
/// Shows the serializer how to save/load this components yaml prototype. /// Shows the serializer how to save/load this components yaml prototype.
@@ -59,10 +63,12 @@ namespace Content.Server.GameObjects.Components.Chemistry
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ReagentDispenserUiKey.Key); _userInterface = Owner.GetComponent<ServerUserInterfaceComponent>()
.GetBoundUserInterface(ReagentDispenserUiKey.Key);
_userInterface.OnReceiveMessage += OnUiReceiveMessage; _userInterface.OnReceiveMessage += OnUiReceiveMessage;
_beakerContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner); _beakerContainer =
ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
InitializeFromPrototype(); InitializeFromPrototype();
UpdateUserInterface(); UpdateUserInterface();
@@ -95,7 +101,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <param name="obj">A user interface message from the client.</param> /// <param name="obj">A user interface message from the client.</param>
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
{ {
var msg = (UiButtonPressedMessage)obj.Message; var msg = (UiButtonPressedMessage) obj.Message;
switch (msg.Button) switch (msg.Button)
{ {
case UiButton.Eject: case UiButton.Eject:
@@ -127,14 +133,17 @@ namespace Content.Server.GameObjects.Components.Chemistry
{ {
TryDispense(msg.DispenseIndex); TryDispense(msg.DispenseIndex);
} }
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
ClickSound();
} }
/// <summary> /// <summary>
/// Gets component data to be used to update the user interface client-side. /// Gets component data to be used to update the user interface client-side.
/// </summary> /// </summary>
/// <returns>Returns a <see cref="SharedReagentDispenserComponent.ReagentDispenserBoundUserInterfaceState"/></returns> /// <returns>Returns a <see cref="SharedReagentDispenserComponent.ReagentDispenserBoundUserInterfaceState"/></returns>
private ReagentDispenserBoundUserInterfaceState GetUserInterfaceState() private ReagentDispenserBoundUserInterfaceState GetUserInterfaceState()
@@ -142,19 +151,16 @@ namespace Content.Server.GameObjects.Components.Chemistry
var beaker = _beakerContainer.ContainedEntity; var beaker = _beakerContainer.ContainedEntity;
if (beaker == null) if (beaker == null)
{ {
return new ReagentDispenserBoundUserInterfaceState(false, 0,0, return new ReagentDispenserBoundUserInterfaceState(false, 0, 0,
"", Inventory, Owner.Name, null); "", Inventory, Owner.Name, null, DispenseAmount);
} }
var solution = beaker.GetComponent<SolutionComponent>(); var solution = beaker.GetComponent<SolutionComponent>();
return new ReagentDispenserBoundUserInterfaceState(true, solution.CurrentVolume, solution.MaxVolume, return new ReagentDispenserBoundUserInterfaceState(true, solution.CurrentVolume, solution.MaxVolume,
beaker.Name, Inventory, Owner.Name, solution.ReagentList.ToList()); beaker.Name, Inventory, Owner.Name, solution.ReagentList.ToList(), DispenseAmount);
} }
/// <summary> private void UpdateUserInterface()
/// Gets current component data as a <see cref="SharedReagentDispenserComponent.ReagentDispenserBoundUserInterfaceState"/> and sends it to the client.
/// </summary>
public void UpdateUserInterface()
{ {
var state = GetUserInterfaceState(); var state = GetUserInterfaceState();
_userInterface.SetState(state); _userInterface.SetState(state);
@@ -163,10 +169,10 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// <summary> /// <summary>
/// If this component contains an entity with a <see cref="SolutionComponent"/>, eject it. /// If this component contains an entity with a <see cref="SolutionComponent"/>, eject it.
/// </summary> /// </summary>
public void TryEject() private void TryEject()
{ {
if(!HasBeaker) return; if (!HasBeaker) return;
_solution.SolutionChanged -= HandleSolutionChangedEvent; Solution.SolutionChanged -= HandleSolutionChangedEvent;
_beakerContainer.Remove(_beakerContainer.ContainedEntity); _beakerContainer.Remove(_beakerContainer.ContainedEntity);
UpdateUserInterface(); UpdateUserInterface();
@@ -193,7 +199,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
if (!HasBeaker) return; if (!HasBeaker) return;
var solution = _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>(); var solution = _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>();
solution.TryAddReagent(Inventory[dispenseIndex].ID, DispenseAmount, out int acceptedQuantity); solution.TryAddReagent(Inventory[dispenseIndex].ID, DispenseAmount, out _);
UpdateUserInterface(); UpdateUserInterface();
} }
@@ -202,12 +208,13 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// Called when you click the owner entity with an empty hand. Opens the UI client-side if possible. /// Called when you click the owner entity with an empty hand. Opens the UI client-side if possible.
/// </summary> /// </summary>
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param> /// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
public void Activate(ActivateEventArgs args) void IActivate.Activate(ActivateEventArgs args)
{ {
if (!args.User.TryGetComponent(out IActorComponent actor)) if (!args.User.TryGetComponent(out IActorComponent actor))
{ {
return; return;
} }
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent hands))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
@@ -229,7 +236,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
/// </summary> /// </summary>
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param> /// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
/// <returns></returns> /// <returns></returns>
public bool AttackBy(AttackByEventArgs args) bool IAttackBy.AttackBy(AttackByEventArgs args)
{ {
if (!args.User.TryGetComponent(out IHandsComponent hands)) if (!args.User.TryGetComponent(out IHandsComponent hands))
{ {
@@ -246,7 +253,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
_localizationManager.GetString("This dispenser already has a container in it.")); _localizationManager.GetString("This dispenser already has a container in it."));
} }
else if ((solution.Capabilities & SolutionCaps.FitsInDispenser) == 0) else if ((solution.Capabilities & SolutionCaps.FitsInDispenser) == 0)
{ {
//If it can't fit in the dispenser, don't put it in. For example, buckets and mop buckets can't fit. //If it can't fit in the dispenser, don't put it in. For example, buckets and mop buckets can't fit.
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
@@ -255,7 +262,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
else else
{ {
_beakerContainer.Insert(activeHandEntity); _beakerContainer.Insert(activeHandEntity);
_solution.SolutionChanged += HandleSolutionChangedEvent; Solution.SolutionChanged += HandleSolutionChangedEvent;
UpdateUserInterface(); UpdateUserInterface();
} }
} }
@@ -268,9 +275,17 @@ namespace Content.Server.GameObjects.Components.Chemistry
return true; return true;
} }
void HandleSolutionChangedEvent() private void HandleSolutionChangedEvent()
{ {
UpdateUserInterface(); UpdateUserInterface();
} }
private void ClickSound()
{
if (Owner.TryGetComponent(out SoundComponent sound))
{
sound.Play("/Audio/machines/machine_switch.ogg", AudioParams.Default.WithVolume(-2f));
}
}
} }
} }

View File

@@ -20,12 +20,12 @@ namespace Content.Shared.GameObjects.Components.Chemistry
/// <summary> /// <summary>
/// A list of reagents which this may dispense. Defined in yaml prototype, see <see cref="ReagentDispenserInventoryPrototype"/>. /// A list of reagents which this may dispense. Defined in yaml prototype, see <see cref="ReagentDispenserInventoryPrototype"/>.
/// </summary> /// </summary>
public List<ReagentDispenserInventoryEntry> Inventory = new List<ReagentDispenserInventoryEntry>(); protected readonly List<ReagentDispenserInventoryEntry> Inventory = new List<ReagentDispenserInventoryEntry>();
[Serializable, NetSerializable] [Serializable, NetSerializable]
public class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState public class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState
{ {
public readonly bool HasBeaker; public readonly bool HasBeaker;
public readonly int BeakerCurrentVolume; public readonly int BeakerCurrentVolume;
public readonly int BeakerMaxVolume; public readonly int BeakerMaxVolume;
public readonly string ContainerName; public readonly string ContainerName;
@@ -38,9 +38,10 @@ namespace Content.Shared.GameObjects.Components.Chemistry
/// </summary> /// </summary>
public readonly List<Solution.ReagentQuantity> ContainerReagents; public readonly List<Solution.ReagentQuantity> ContainerReagents;
public readonly string DispenserName; public readonly string DispenserName;
public readonly int SelectedDispenseAmount;
public ReagentDispenserBoundUserInterfaceState(bool hasBeaker, int beakerCurrentVolume, int beakerMaxVolume, string containerName, public ReagentDispenserBoundUserInterfaceState(bool hasBeaker, int beakerCurrentVolume, int beakerMaxVolume, string containerName,
List<ReagentDispenserInventoryEntry> inventory, string dispenserName, List<Solution.ReagentQuantity> containerReagents) List<ReagentDispenserInventoryEntry> inventory, string dispenserName, List<Solution.ReagentQuantity> containerReagents, int selectedDispenseAmount)
{ {
HasBeaker = hasBeaker; HasBeaker = hasBeaker;
BeakerCurrentVolume = beakerCurrentVolume; BeakerCurrentVolume = beakerCurrentVolume;
@@ -49,6 +50,7 @@ namespace Content.Shared.GameObjects.Components.Chemistry
Inventory = inventory; Inventory = inventory;
DispenserName = dispenserName; DispenserName = dispenserName;
ContainerReagents = containerReagents; ContainerReagents = containerReagents;
SelectedDispenseAmount = selectedDispenseAmount;
} }
} }
@@ -98,9 +100,10 @@ namespace Content.Shared.GameObjects.Components.Chemistry
/// Information about a reagent which the dispenser can dispense. /// Information about a reagent which the dispenser can dispense.
/// </summary> /// </summary>
[Serializable, NetSerializable] [Serializable, NetSerializable]
public class ReagentDispenserInventoryEntry public struct ReagentDispenserInventoryEntry
{ {
public string ID; public readonly string ID;
public ReagentDispenserInventoryEntry(string id) public ReagentDispenserInventoryEntry(string id)
{ {
ID = id; ID = id;

View File

@@ -2,31 +2,14 @@
id: booze_dispenser id: booze_dispenser
name: Booze Dispenser name: Booze Dispenser
description: A booze dispenser with a single slot for a container to be filled. description: A booze dispenser with a single slot for a container to be filled.
parent: reagent_dispenser_base
components: components:
- type: Sprite - type: Sprite
texture: Buildings/booze_dispenser.png texture: Buildings/booze_dispenser.png
- type: Icon - type: Icon
texture: Buildings/booze_dispenser.png texture: Buildings/booze_dispenser.png
- type: Clickable
- type: Collidable
shapes:
- !type:PhysShapeAabb
bounds: "-0.4,-0.25,0.4,0.25"
mask: 19
layer: 16
IsScrapingFloor: true
- type: Physics
mass: 25
Anchored: true
- type: SnapGrid
offset: Center
- type: ReagentDispenser - type: ReagentDispenser
pack: BoozeDispenserInventory pack: BoozeDispenserInventory
- type: PowerDevice
- type: UserInterface
interfaces:
- key: enum.ReagentDispenserUiKey.Key
type: ReagentDispenserBoundUserInterface
- type: reagentDispenserInventory - type: reagentDispenserInventory
id: BoozeDispenserInventory id: BoozeDispenserInventory
@@ -34,4 +17,4 @@
- chem.Whiskey - chem.Whiskey
- chem.Ale - chem.Ale
- chem.Wine - chem.Wine
- chem.Ice - chem.Ice

View File

@@ -1,32 +1,15 @@
- type: entity - type: entity
id: chem_dispenser id: chem_dispenser
name: Chemical Dispenser name: Chemical Dispenser
parent: reagent_dispenser_base
description: An industrial grade chemical dispenser with a sizeable chemical supply. description: An industrial grade chemical dispenser with a sizeable chemical supply.
components: components:
- type: Sprite - type: Sprite
texture: Buildings/industrial_dispenser.png texture: Buildings/industrial_dispenser.png
- type: Icon - type: Icon
texture: Buildings/industrial_dispenser.png texture: Buildings/industrial_dispenser.png
- type: Clickable
- type: Collidable
shapes:
- !type:PhysShapeAabb
bounds: "-0.4,-0.25,0.4,0.25"
mask: 19
layer: 16
IsScrapingFloor: true
- type: Physics
mass: 25
Anchored: true
- type: SnapGrid
offset: Center
- type: ReagentDispenser - type: ReagentDispenser
pack: ChemDispenserStandardInventory pack: ChemDispenserStandardInventory
- type: PowerDevice
- type: UserInterface
interfaces:
- key: enum.ReagentDispenserUiKey.Key
type: ReagentDispenserBoundUserInterface
- type: reagentDispenserInventory - type: reagentDispenserInventory
id: ChemDispenserStandardInventory id: ChemDispenserStandardInventory

View File

@@ -0,0 +1,25 @@
- type: entity
abstract: true
id: reagent_dispenser_base
components:
- type: Clickable
- type: Collidable
shapes:
- !type:PhysShapeAabb
bounds: "-0.4,-0.25,0.4,0.25"
mask: 19
layer: 16
IsScrapingFloor: true
- type: Physics
mass: 25
Anchored: true
- type: SnapGrid
offset: Center
- type: ReagentDispenser
- type: PowerDevice
- type: UserInterface
interfaces:
- key: enum.ReagentDispenserUiKey.Key
type: ReagentDispenserBoundUserInterface
- type: Sound

View File

@@ -1,32 +1,15 @@
- type: entity - type: entity
id: soda_dispenser id: soda_dispenser
name: Soda Dispenser name: Soda Dispenser
parent: reagent_dispenser_base
description: A beverage dispenser with a selection of soda and several other common beverages. Has a single fill slot for containers. description: A beverage dispenser with a selection of soda and several other common beverages. Has a single fill slot for containers.
components: components:
- type: Sprite - type: Sprite
texture: Buildings/soda_dispenser.png texture: Buildings/soda_dispenser.png
- type: Icon - type: Icon
texture: Buildings/soda_dispenser.png texture: Buildings/soda_dispenser.png
- type: Clickable
- type: Collidable
shapes:
- !type:PhysShapeAabb
bounds: "-0.4,-0.25,0.4,0.25"
mask: 19
layer: 16
IsScrapingFloor: true
- type: Physics
mass: 25
Anchored: true
- type: SnapGrid
offset: Center
- type: ReagentDispenser - type: ReagentDispenser
pack: SodaDispenserInventory pack: SodaDispenserInventory
- type: PowerDevice
- type: UserInterface
interfaces:
- key: enum.ReagentDispenserUiKey.Key
type: ReagentDispenserBoundUserInterface
- type: reagentDispenserInventory - type: reagentDispenserInventory
id: SodaDispenserInventory id: SodaDispenserInventory
@@ -35,4 +18,4 @@
- chem.Coffee - chem.Coffee
- chem.Tea - chem.Tea
- chem.Ice - chem.Ice
- chem.H2O - chem.H2O