Reagent dispensers (#360)
* Expose more private values of Solution and SolutionComponent Expose SolutionComponent.ContainedSolution and Solution.Contents. Both needed by ReagentDispenserComponent. * Implement IExamine for SolutionComponent Allows players to see the contents of a solution by examining the entity which contains it. * Implement ReagentDispenserComponent Adds ReagentDispenserComponent. A component which can add or remove reagents from a solution container. It's written in a general way so that it can be used for things such as the Chemical dispensers in chemistry, but also the booze and soda dispensers in the bar. The chemicals it may dispense are defined in yaml, similar to the way that vending machines define which entities they can dispense, by defining a reagent pack. * Add chemical dispenser and equipment Adds the chemical dispenser, beaker, large beaker, dropper, and a few more chemicals. * Add booze and soda dispensers. Adds the booze and soda dispensers, and a few chemicals for them to dispense. There's no drink mixing or drunkenness yet. * Update engine submodule. * Remove unneeded and commented out code Had a few WIP notes and debug code bits I forgot to remove beforehand. * Make SolutionComponent._containedSolution and it's values private again - Remove `SolutionComponent.ContainedSolution` property, replace with specific access functions to maintain safety. - Make Solution.Contents return a `ReadOnlyCollection` instead of `_contents` to prevent uncontrolled access to the Solution values. - Add `SolutionComponent.RemoveAllSolution()` * Update Content.Shared/Chemistry/Solution.cs Commits a suggestion from RemieRichards to match the coding style of the rest of the codebase. Using `IReadOnlyList` instead of `IReadOnlyCollection`. Co-Authored-By: Remie Richards <remierichards@gmail.com> * Update Content.Shared/GameObjects/Components/Chemistry/SolutionComponent.cs Commits a suggestion from RemieRichards to match the coding style of the rest of the codebase. Using `IReadOnlyList` instead of `IReadOnlyCollection`. Co-Authored-By: Remie Richards <remierichards@gmail.com> * Add import for IReadOnlyList to Shared/SolutionComponent.cs * Add documentation * Improve localization Improve use of ILocalizationManager. * Resolve ReagentDispenserWindow._localizationManager before using it Forgot to do this in the last commit, resulting in a crash. Oops. * Add SolutionCaps.FitsInDispenser. Use in ReagentDispenserComponent. Used to limit large containers like buckets or mop buckets from being placed in a dispenser. Both have large capacities (500) and weren't designed to hold certain chemicals like a beaker is, so for now they can be blocked from being put in a dispenser by giving them that flag. * Add colors to new reagents * Update engine submodule
This commit is contained in:
committed by
Pieter-Jan Briers
parent
0cc980b26a
commit
963bb28f0f
@@ -126,6 +126,8 @@ namespace Content.Client
|
||||
factory.Register<SharedVendingMachineComponent>();
|
||||
factory.Register<SharedWiresComponent>();
|
||||
|
||||
factory.Register<SharedReagentDispenserComponent>();
|
||||
|
||||
prototypes.RegisterIgnore("material");
|
||||
|
||||
IoCManager.Register<IGameHud, GameHud>();
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Robust.Client.GameObjects.Components.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using static Content.Shared.GameObjects.Components.Chemistry.SharedReagentDispenserComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Chemistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="ReagentDispenserWindow"/> and updates it when new server messages are received.
|
||||
/// </summary>
|
||||
public class ReagentDispenserBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private ReagentDispenserWindow _window;
|
||||
private ReagentDispenserBoundUserInterfaceState _lastState;
|
||||
|
||||
public ReagentDispenserBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called each time a dispenser UI instance is opened. Generates the dispenser window and fills it with
|
||||
/// relevant info. Sets the actions for static buttons.
|
||||
/// <para>Buttons which can change like reagent dispense buttons have their actions set in <see cref="UpdateReagentsList"/>.</para>
|
||||
/// </summary>
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
//Setup window layout/elements
|
||||
_window = new ReagentDispenserWindow
|
||||
{
|
||||
Title = _localizationManager.GetString("Reagent dispenser"),
|
||||
Size = (500, 600)
|
||||
};
|
||||
|
||||
_window.OpenCenteredMinSize();
|
||||
_window.OnClose += Close;
|
||||
|
||||
//Setup static button actions.
|
||||
_window.EjectButton.OnPressed += _ => ButtonPressed(UiButton.Eject);
|
||||
_window.ClearButton.OnPressed += _ => ButtonPressed(UiButton.Clear);
|
||||
_window.DispenseButton1.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount1);
|
||||
_window.DispenseButton5.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount5);
|
||||
_window.DispenseButton10.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount10);
|
||||
_window.DispenseButton25.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount25);
|
||||
_window.DispenseButton50.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount50);
|
||||
_window.DispenseButton100.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount100);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the ui each time new state data is sent from the server.
|
||||
/// </summary>
|
||||
/// <param name="state">Data of the <see cref="ReagentDispenserComponent"/> that this ui represents. Sent from the server.</param>
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
var castState = (ReagentDispenserBoundUserInterfaceState)state;
|
||||
_lastState = castState;
|
||||
|
||||
_window?.UpdateState(castState); //Update window state
|
||||
UpdateReagentsList(castState.Inventory); //Update reagents list & reagent button actions
|
||||
|
||||
_window.ForceRunLayoutUpdate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the list of reagents that this dispenser can dispense on the UI.
|
||||
/// </summary>
|
||||
/// <param name="inventory">A list of the reagents which can be dispensed.</param>
|
||||
private void UpdateReagentsList(List<ReagentDispenserInventoryEntry> inventory)
|
||||
{
|
||||
_window.UpdateReagentsList(inventory);
|
||||
for (int i = 0; i < _window.ChemicalList.Children.Count(); i++)
|
||||
{
|
||||
var button = (Button)_window.ChemicalList.Children.ElementAt(i);
|
||||
var i1 = i;
|
||||
button.OnPressed += _ => ButtonPressed(UiButton.Dispense, i1);
|
||||
button.OnMouseEntered += _ =>
|
||||
{
|
||||
if (_lastState != null)
|
||||
{
|
||||
_window.UpdateContainerInfo(_lastState, inventory[i1].ID);
|
||||
}
|
||||
};
|
||||
button.OnMouseExited += _ =>
|
||||
{
|
||||
if (_lastState != null)
|
||||
{
|
||||
_window.UpdateContainerInfo(_lastState);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void ButtonPressed(UiButton button, int dispenseIndex = -1)
|
||||
{
|
||||
SendMessage(new UiButtonPressedMessage(button, dispenseIndex));
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
_window.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Client.UserInterface;
|
||||
using Content.Shared.Chemistry;
|
||||
using Robust.Client.Graphics.Drawing;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using static Content.Shared.GameObjects.Components.Chemistry.SharedReagentDispenserComponent;
|
||||
|
||||
namespace Content.Client.GameObjects.Components.Chemistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Client-side UI used to control a <see cref="ReagentDispenserComponent"/>
|
||||
/// </summary>
|
||||
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>
|
||||
public VBoxContainer ContainerInfo;
|
||||
|
||||
/// <summary>Ejects the reagent container from the dispenser.</summary>
|
||||
public Button ClearButton;
|
||||
/// <summary>Removes all reagents from the reagent container.</summary>
|
||||
public Button EjectButton;
|
||||
|
||||
/// <summary>A grid of buttons for each reagent which can be dispensed.</summary>
|
||||
public GridContainer ChemicalList;
|
||||
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager;
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <summary>
|
||||
/// Create and initialize the dispenser UI client-side. Creates the basic layout,
|
||||
/// actual data isn't filled in until the server sends data about the dispenser.
|
||||
/// </summary>
|
||||
public ReagentDispenserWindow()
|
||||
{
|
||||
_prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
_localizationManager = IoCManager.Resolve<ILocalizationManager>();
|
||||
|
||||
Contents.AddChild(new VBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
//First, our dispense amount buttons
|
||||
new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label{Text = _localizationManager.GetString("Amount ")},
|
||||
(DispenseButton1 = new Button{Text = "1"}),
|
||||
(DispenseButton5 = new Button{Text = "5"}),
|
||||
(DispenseButton10 = new Button{Text = "10"}),
|
||||
(DispenseButton25 = new Button{Text = "25"}),
|
||||
(DispenseButton50 = new Button{Text = "50"}),
|
||||
(DispenseButton100 = new Button{Text = "100"}),
|
||||
}
|
||||
},
|
||||
new Panel{CustomMinimumSize = (0.0f, 10.0f)}, //Padding
|
||||
(ChemicalList = new GridContainer //Grid of which reagents can be dispensed.
|
||||
{
|
||||
CustomMinimumSize = (470.0f, 200.0f),
|
||||
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||
Columns = 5
|
||||
}),
|
||||
new Panel{CustomMinimumSize = (0.0f, 10.0f)}, //Padding
|
||||
new HBoxContainer
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label{Text = _localizationManager.GetString("Container: ")},
|
||||
(ClearButton = new Button{Text = _localizationManager.GetString("Clear")}),
|
||||
(EjectButton = new Button{Text = _localizationManager.GetString("Eject")})
|
||||
}
|
||||
},
|
||||
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)
|
||||
},
|
||||
Children =
|
||||
{
|
||||
(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.")}
|
||||
}
|
||||
}),
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the button grid of reagents which can be dispensed.
|
||||
/// <para>The actions for these buttons are set in <see cref="ReagentDispenserBoundUserInterface.UpdateReagentsList"/>.</para>
|
||||
/// </summary>
|
||||
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
|
||||
public void UpdateReagentsList(List<ReagentDispenserInventoryEntry> inventory)
|
||||
{
|
||||
if (ChemicalList == null) return;
|
||||
if (inventory == null) return;
|
||||
|
||||
ChemicalList.Children.Clear();
|
||||
|
||||
foreach (var entry in inventory)
|
||||
{
|
||||
if (_prototypeManager.TryIndex(entry.ID, out ReagentPrototype proto))
|
||||
{
|
||||
ChemicalList.AddChild(new Button { Text = proto.Name });
|
||||
}
|
||||
else
|
||||
{
|
||||
ChemicalList.AddChild(new Button { Text = _localizationManager.GetString("Reagent name not found") });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the UI state when new state data is received from the server.
|
||||
/// </summary>
|
||||
/// <param name="state">State data sent by the server.</param>
|
||||
public void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
var castState = (ReagentDispenserBoundUserInterfaceState)state;
|
||||
Title = castState.DispenserName;
|
||||
UpdateContainerInfo(castState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the fill state and list of reagents held by the current reagent container, if applicable.
|
||||
/// <para>Also highlights a reagent if it's dispense button is being mouse hovered.</para>
|
||||
/// </summary>
|
||||
/// <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>
|
||||
public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state, string highlightedReagentId = "InvalidReagent")
|
||||
{
|
||||
ContainerInfo.Children.Clear();
|
||||
if (state.HasBeaker) //If the dispenser doesn't have a beaker/container don't bother with this.
|
||||
{
|
||||
ContainerInfo.Children.Add(new HBoxContainer //Name of the container and it's fill status (Ex: 44/100u)
|
||||
{
|
||||
Children =
|
||||
{
|
||||
new Label{Text = $"{state.ContainerName}: "},
|
||||
new Label{Text = $"{state.BeakerCurrentVolume}/{state.BeakerMaxVolume}", 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
|
||||
{
|
||||
ContainerInfo.Children.Add(new Label{Text = _localizationManager.GetString("No container loaded.")});
|
||||
}
|
||||
ForceRunLayoutUpdate(); //Force a layout update to avoid text hanging off the window until the user manually resizes it.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Content.Client.UserInterface
|
||||
{
|
||||
public const string StyleClassLabelHeading = "LabelHeading";
|
||||
public const string StyleClassLabelSubText = "LabelSubText";
|
||||
public const string StyleClassLabelSecondaryColor = "LabelSecondaryColor";
|
||||
public const string StyleClassButtonBig = "ButtonBig";
|
||||
private static readonly Color NanoGold = Color.FromHex("#A88B5E");
|
||||
|
||||
@@ -435,6 +436,12 @@ namespace Content.Client.UserInterface
|
||||
new StyleProperty(Label.StylePropertyFontColor, Color.DarkGray),
|
||||
} ),
|
||||
|
||||
new StyleRule(new SelectorElement(typeof(Label), new []{StyleClassLabelSecondaryColor}, null, null), new []
|
||||
{
|
||||
new StyleProperty(Label.StylePropertyFont, notoSans12),
|
||||
new StyleProperty(Label.StylePropertyFontColor, Color.DarkGray),
|
||||
} ),
|
||||
|
||||
// Big Button
|
||||
new StyleRule(new SelectorElement(typeof(Button), new []{StyleClassButtonBig}, null, null), new []
|
||||
{
|
||||
|
||||
@@ -0,0 +1,268 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Server.Interfaces;
|
||||
using Content.Server.Interfaces.GameObjects;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects.Components.Chemistry;
|
||||
using Robust.Server.GameObjects.Components.Container;
|
||||
using Robust.Server.GameObjects.Components.UserInterface;
|
||||
using Robust.Server.Interfaces.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Chemistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains all the server-side logic for reagent dispensers. See also <see cref="SharedReagentDispenserComponent"/>.
|
||||
/// This includes initializing the component based on prototype data, and sending and receiving messages from the client.
|
||||
/// Messages sent to the client are used to update update the user interface for a component instance.
|
||||
/// Messages sent from the client are used to handle ui button presses.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
[ComponentReference(typeof(IAttackBy))]
|
||||
public class ReagentDispenserComponent : SharedReagentDispenserComponent, IActivate, IAttackBy
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IServerNotifyManager _notifyManager;
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
private BoundUserInterface _userInterface;
|
||||
private ContainerSlot _beakerContainer;
|
||||
private string _packPrototypeId;
|
||||
|
||||
public bool HasBeaker => _beakerContainer.ContainedEntity != null;
|
||||
public int DispenseAmount = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Shows the serializer how to save/load this components yaml prototype.
|
||||
/// </summary>
|
||||
/// <param name="serializer">Yaml serializer</param>
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _packPrototypeId, "pack", string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called once per instance of this component. Gets references to any other components needed
|
||||
/// by this component and initializes it's UI and other data.
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_userInterface = Owner.GetComponent<ServerUserInterfaceComponent>().GetBoundUserInterface(ReagentDispenserUiKey.Key);
|
||||
_userInterface.OnReceiveMessage += OnUiReceiveMessage;
|
||||
|
||||
_beakerContainer = ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
|
||||
|
||||
InitializeFromPrototype();
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if the <c>pack</c> defined in this components yaml prototype
|
||||
/// exists. If so, it fills the reagent inventory list.
|
||||
/// </summary>
|
||||
private void InitializeFromPrototype()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_packPrototypeId)) return;
|
||||
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
if (!prototypeManager.TryIndex(_packPrototypeId, out ReagentDispenserInventoryPrototype packPrototype))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var entry in packPrototype.Inventory)
|
||||
{
|
||||
Inventory.Add(new ReagentDispenserInventoryEntry(entry));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles ui messages from the client. For things such as button presses
|
||||
/// which interact with the world and require server action.
|
||||
/// </summary>
|
||||
/// <param name="obj">A user interface message from the client.</param>
|
||||
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
|
||||
{
|
||||
var msg = (UiButtonPressedMessage)obj.Message;
|
||||
switch (msg.Button)
|
||||
{
|
||||
case UiButton.Eject:
|
||||
TryEject();
|
||||
break;
|
||||
case UiButton.Clear:
|
||||
TryClear();
|
||||
break;
|
||||
case UiButton.SetDispenseAmount1:
|
||||
DispenseAmount = 1;
|
||||
break;
|
||||
case UiButton.SetDispenseAmount5:
|
||||
DispenseAmount = 5;
|
||||
break;
|
||||
case UiButton.SetDispenseAmount10:
|
||||
DispenseAmount = 10;
|
||||
break;
|
||||
case UiButton.SetDispenseAmount25:
|
||||
DispenseAmount = 25;
|
||||
break;
|
||||
case UiButton.SetDispenseAmount50:
|
||||
DispenseAmount = 50;
|
||||
break;
|
||||
case UiButton.SetDispenseAmount100:
|
||||
DispenseAmount = 100;
|
||||
break;
|
||||
case UiButton.Dispense:
|
||||
if (HasBeaker)
|
||||
{
|
||||
TryDispense(msg.DispenseIndex);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets component data to be used to update the user interface client-side.
|
||||
/// </summary>
|
||||
/// <returns>Returns a <see cref="SharedReagentDispenserComponent.ReagentDispenserBoundUserInterfaceState"/></returns>
|
||||
private ReagentDispenserBoundUserInterfaceState GetUserInterfaceState()
|
||||
{
|
||||
var beaker = _beakerContainer.ContainedEntity;
|
||||
if (beaker == null)
|
||||
{
|
||||
return new ReagentDispenserBoundUserInterfaceState(false, 0,0,
|
||||
"", Inventory, Owner.Name, null);
|
||||
}
|
||||
|
||||
var solution = beaker.GetComponent<SolutionComponent>();
|
||||
return new ReagentDispenserBoundUserInterfaceState(true, solution.CurrentVolume, solution.MaxVolume,
|
||||
beaker.Name, Inventory, Owner.Name, solution.ReagentList.ToList());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets current component data as a <see cref="SharedReagentDispenserComponent.ReagentDispenserBoundUserInterfaceState"/> and sends it to the client.
|
||||
/// </summary>
|
||||
private void UpdateUserInterface()
|
||||
{
|
||||
var state = GetUserInterfaceState();
|
||||
_userInterface.SetState(state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this component contains an entity with a <see cref="SolutionComponent"/>, eject it.
|
||||
/// </summary>
|
||||
private void TryEject()
|
||||
{
|
||||
if(!HasBeaker) return;
|
||||
_beakerContainer.Remove(_beakerContainer.ContainedEntity);
|
||||
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this component contains an entity with a <see cref="SolutionComponent"/>, remove all of it's reagents / solutions.
|
||||
/// </summary>
|
||||
private void TryClear()
|
||||
{
|
||||
if (!HasBeaker) return;
|
||||
var solution = _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>();
|
||||
solution.RemoveAllSolution();
|
||||
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this component contains an entity with a <see cref="SolutionComponent"/>, attempt to dispense the specified reagent to it.
|
||||
/// </summary>
|
||||
/// <param name="dispenseIndex">The index of the reagent in <c>Inventory</c>.</param>
|
||||
private void TryDispense(int dispenseIndex)
|
||||
{
|
||||
if (!HasBeaker) return;
|
||||
|
||||
var solution = _beakerContainer.ContainedEntity.GetComponent<SolutionComponent>();
|
||||
solution.TryAddReagent(Inventory[dispenseIndex].ID, DispenseAmount, out int acceptedQuantity);
|
||||
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when you click the owner entity with an empty hand. Opens the UI client-side if possible.
|
||||
/// </summary>
|
||||
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
|
||||
public void Activate(ActivateEventArgs args)
|
||||
{
|
||||
if (!args.User.TryGetComponent(out IActorComponent actor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!args.User.TryGetComponent(out IHandsComponent hands))
|
||||
{
|
||||
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
|
||||
_localizationManager.GetString("You have no hands."));
|
||||
return;
|
||||
}
|
||||
|
||||
var activeHandEntity = hands.GetActiveHand?.Owner;
|
||||
if (activeHandEntity == null)
|
||||
{
|
||||
_userInterface.Open(actor.playerSession);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when you click the owner entity with something in your active hand. If the entity in your hand
|
||||
/// contains a <see cref="SolutionComponent"/>, if you have hands, and if the dispenser doesn't already
|
||||
/// hold a container, it will be added to the dispenser.
|
||||
/// </summary>
|
||||
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
|
||||
/// <returns></returns>
|
||||
public bool AttackBy(AttackByEventArgs args)
|
||||
{
|
||||
if (!args.User.TryGetComponent(out IHandsComponent hands))
|
||||
{
|
||||
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
|
||||
_localizationManager.GetString("You have no hands."));
|
||||
return true;
|
||||
}
|
||||
|
||||
var activeHandEntity = hands.GetActiveHand.Owner;
|
||||
if (activeHandEntity.TryGetComponent<SolutionComponent>(out var solution))
|
||||
{
|
||||
if (HasBeaker)
|
||||
{
|
||||
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
|
||||
_localizationManager.GetString("This dispenser already has a container in it."));
|
||||
}
|
||||
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.
|
||||
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
|
||||
_localizationManager.GetString("That can't fit in the dispenser."));
|
||||
}
|
||||
else
|
||||
{
|
||||
_beakerContainer.Insert(activeHandEntity);
|
||||
UpdateUserInterface();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User,
|
||||
_localizationManager.GetString("You can't put this in the dispenser."));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
using System;
|
||||
using Content.Server.GameObjects.EntitySystems;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.GameObjects.Components.Chemistry
|
||||
{
|
||||
@@ -10,8 +15,13 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
/// Shared ECS component that manages a liquid solution of reagents.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
internal class SolutionComponent : Shared.GameObjects.Components.Chemistry.SolutionComponent
|
||||
internal class SolutionComponent : Shared.GameObjects.Components.Chemistry.SolutionComponent, IExamine
|
||||
{
|
||||
#pragma warning disable 649
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager;
|
||||
[Dependency] private readonly ILocalizationManager _localizationManager;
|
||||
#pragma warning restore 649
|
||||
|
||||
/// <summary>
|
||||
/// Transfers solution from the held container to the target container.
|
||||
/// </summary>
|
||||
@@ -76,6 +86,22 @@ namespace Content.Server.GameObjects.Components.Chemistry
|
||||
}
|
||||
}
|
||||
|
||||
void IExamine.Examine(FormattedMessage message)
|
||||
{
|
||||
message.AddText(_localizationManager.GetString("Contains:\n"));
|
||||
foreach (var reagent in ReagentList)
|
||||
{
|
||||
if (_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype proto))
|
||||
{
|
||||
message.AddText($"{proto.Name}: {reagent.Quantity}u\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
message.AddText(_localizationManager.GetString("Unknown reagent:") + $"{reagent.Quantity}u\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transfers solution from a target container to the held container.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Shared.Interfaces.Serialization;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -17,6 +18,7 @@ namespace Content.Shared.Chemistry
|
||||
// Most objects on the station hold only 1 or 2 reagents
|
||||
[ViewVariables]
|
||||
private List<ReagentQuantity> _contents = new List<ReagentQuantity>(2);
|
||||
public IReadOnlyList<ReagentQuantity> Contents => _contents;
|
||||
|
||||
/// <summary>
|
||||
/// The calculated total volume of all reagents in the solution (ex. Total volume of liquid in beaker).
|
||||
|
||||
@@ -17,5 +17,13 @@ namespace Content.Shared.Chemistry
|
||||
|
||||
Injector = 4,
|
||||
Injectable = 8,
|
||||
|
||||
/// <summary>
|
||||
/// Allows the container to be placed in a <c>ReagentDispenserComponent</c>.
|
||||
/// <para>Otherwise it's considered to be too large or the improper shape to fit.</para>
|
||||
/// <para>Allows us to have obscenely large containers that are harder to abuse in chem dispensers
|
||||
/// since they can't be placed directly in them.</para>
|
||||
/// </summary>
|
||||
FitsInDispenser = 16,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Chemistry
|
||||
{
|
||||
/// <summary>
|
||||
/// Is simply a list of reagents defined in yaml. This can then be set as a
|
||||
/// <see cref="ReagentDispenserComponent"/>s <c>pack</c> value (also in yaml),
|
||||
/// to define which reagents it's able to dispense. Based off of how vending
|
||||
/// machines define their inventory.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable, Prototype("reagentDispenserInventory")]
|
||||
public class ReagentDispenserInventoryPrototype : IPrototype, IIndexedPrototype
|
||||
{
|
||||
private string _id;
|
||||
private List<string> _inventory;
|
||||
|
||||
public string ID => _id;
|
||||
public List<string> Inventory => _inventory;
|
||||
|
||||
public void LoadFrom(YamlMappingNode mapping)
|
||||
{
|
||||
var serializer = YamlObjectSerializer.NewReader(mapping);
|
||||
|
||||
serializer.DataField(ref _id, "id", string.Empty);
|
||||
serializer.DataField(ref _inventory, "inventory", new List<string>());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Chemistry;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.GameObjects.Components.Chemistry
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Shared class for <c>ReagentDispenserComponent</c>. Provides a way for entities to dispense and remove reagents from other entities with SolutionComponents via a user interface.
|
||||
/// <para>This is useful for machines such as the chemical dispensers, booze dispensers, or soda dispensers.</para>
|
||||
/// <para>The chemicals which may be dispensed are defined by specifying a reagent pack. See <see cref="ReagentDispenserInventoryPrototype"/> for more information on that.</para>
|
||||
/// </summary>
|
||||
public class SharedReagentDispenserComponent : Component
|
||||
{
|
||||
public override string Name => "ReagentDispenser";
|
||||
|
||||
/// <summary>
|
||||
/// A list of reagents which this may dispense. Defined in yaml prototype, see <see cref="ReagentDispenserInventoryPrototype"/>.
|
||||
/// </summary>
|
||||
public List<ReagentDispenserInventoryEntry> Inventory = new List<ReagentDispenserInventoryEntry>();
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
public readonly bool HasBeaker;
|
||||
public readonly int BeakerCurrentVolume;
|
||||
public readonly int BeakerMaxVolume;
|
||||
public readonly string ContainerName;
|
||||
/// <summary>
|
||||
/// A list of the reagents which this dispenser can dispense.
|
||||
/// </summary>
|
||||
public readonly List<ReagentDispenserInventoryEntry> Inventory;
|
||||
/// <summary>
|
||||
/// A list of the reagents and their amounts within the beaker/reagent container, if applicable.
|
||||
/// </summary>
|
||||
public readonly List<Solution.ReagentQuantity> ContainerReagents;
|
||||
public readonly string DispenserName;
|
||||
|
||||
public ReagentDispenserBoundUserInterfaceState(bool hasBeaker, int beakerCurrentVolume, int beakerMaxVolume, string containerName,
|
||||
List<ReagentDispenserInventoryEntry> inventory, string dispenserName, List<Solution.ReagentQuantity> containerReagents)
|
||||
{
|
||||
HasBeaker = hasBeaker;
|
||||
BeakerCurrentVolume = beakerCurrentVolume;
|
||||
BeakerMaxVolume = beakerMaxVolume;
|
||||
ContainerName = containerName;
|
||||
Inventory = inventory;
|
||||
DispenserName = dispenserName;
|
||||
ContainerReagents = containerReagents;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Message data sent from client to server when a dispenser ui button is pressed.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public class UiButtonPressedMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly UiButton Button;
|
||||
public readonly int DispenseIndex; //Index of dispense button / reagent being pressed. Only used when a dispense button is pressed.
|
||||
|
||||
public UiButtonPressedMessage(UiButton button, int dispenseIndex)
|
||||
{
|
||||
Button = button;
|
||||
DispenseIndex = dispenseIndex;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum ReagentDispenserUiKey
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in <see cref="UiButtonPressedMessage"/> to specify which button was pressed.
|
||||
/// </summary>
|
||||
public enum UiButton
|
||||
{
|
||||
Eject,
|
||||
Clear,
|
||||
SetDispenseAmount1,
|
||||
SetDispenseAmount5,
|
||||
SetDispenseAmount10,
|
||||
SetDispenseAmount25,
|
||||
SetDispenseAmount50,
|
||||
SetDispenseAmount100,
|
||||
/// <summary>
|
||||
/// Used when any dispense button is pressed. Such as "Carbon", or "Oxygen" buttons on the chem dispenser.
|
||||
/// The index of the reagent attached to that dispense button is sent as <see cref="UiButtonPressedMessage.DispenseIndex"/>.
|
||||
/// </summary>
|
||||
Dispense
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Information about a reagent which the dispenser can dispense.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public class ReagentDispenserInventoryEntry
|
||||
{
|
||||
public string ID;
|
||||
public ReagentDispenserInventoryEntry(string id)
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Chemistry;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -52,6 +53,8 @@ namespace Content.Shared.GameObjects.Components.Chemistry
|
||||
set => _capabilities = value;
|
||||
}
|
||||
|
||||
public IReadOnlyList<Solution.ReagentQuantity> ReagentList => _containedSolution.Contents;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Solution";
|
||||
|
||||
@@ -88,9 +91,26 @@ namespace Content.Shared.GameObjects.Components.Chemistry
|
||||
_containedSolution = new Solution();
|
||||
}
|
||||
|
||||
public void RemoveAllSolution()
|
||||
{
|
||||
_containedSolution.RemoveAllSolution();
|
||||
}
|
||||
|
||||
public bool TryAddReagent(string reagentId, int quantity, out int acceptedQuantity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
if (quantity > _maxVolume - _containedSolution.TotalVolume)
|
||||
{
|
||||
acceptedQuantity = _maxVolume - _containedSolution.TotalVolume;
|
||||
if (acceptedQuantity == 0) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
acceptedQuantity = quantity;
|
||||
}
|
||||
|
||||
_containedSolution.AddReagent(reagentId, acceptedQuantity);
|
||||
RecalculateColor();
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryAddSolution(Solution solution)
|
||||
|
||||
37
Resources/Prototypes/Entities/buildings/booze_dispenser.yml
Normal file
37
Resources/Prototypes/Entities/buildings/booze_dispenser.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
- type: entity
|
||||
id: booze_dispenser
|
||||
name: Booze Dispenser
|
||||
description: A booze dispenser with a single slot for a container to be filled.
|
||||
components:
|
||||
- type: Sprite
|
||||
texture: Buildings/booze_dispenser.png
|
||||
- type: Icon
|
||||
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
|
||||
pack: BoozeDispenserInventory
|
||||
- type: PowerDevice
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.ReagentDispenserUiKey.Key
|
||||
type: ReagentDispenserBoundUserInterface
|
||||
|
||||
- type: reagentDispenserInventory
|
||||
id: BoozeDispenserInventory
|
||||
inventory:
|
||||
- chem.Whiskey
|
||||
- chem.Ale
|
||||
- chem.Wine
|
||||
- chem.Ice
|
||||
44
Resources/Prototypes/Entities/buildings/chem_dispenser.yml
Normal file
44
Resources/Prototypes/Entities/buildings/chem_dispenser.yml
Normal file
@@ -0,0 +1,44 @@
|
||||
- type: entity
|
||||
id: chem_dispenser
|
||||
name: Chemical Dispenser
|
||||
description: An industrial grade chemical dispenser with a sizeable chemical supply.
|
||||
components:
|
||||
- type: Sprite
|
||||
texture: Buildings/industrial_dispenser.png
|
||||
- type: Icon
|
||||
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
|
||||
pack: ChemDispenserStandardInventory
|
||||
- type: PowerDevice
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.ReagentDispenserUiKey.Key
|
||||
type: ReagentDispenserBoundUserInterface
|
||||
|
||||
- type: reagentDispenserInventory
|
||||
id: ChemDispenserStandardInventory
|
||||
inventory:
|
||||
- chem.H2
|
||||
- chem.O2
|
||||
- chem.S8
|
||||
- chem.C
|
||||
- chem.Cu
|
||||
- chem.N2
|
||||
- chem.Fe
|
||||
- chem.F2
|
||||
- chem.Al
|
||||
- chem.H2SO4
|
||||
- chem.H2O
|
||||
38
Resources/Prototypes/Entities/buildings/soda_dispenser.yml
Normal file
38
Resources/Prototypes/Entities/buildings/soda_dispenser.yml
Normal file
@@ -0,0 +1,38 @@
|
||||
- type: entity
|
||||
id: soda_dispenser
|
||||
name: Soda Dispenser
|
||||
description: A beverage dispenser with a selection of soda and several other common beverages. Has a single fill slot for containers.
|
||||
components:
|
||||
- type: Sprite
|
||||
texture: Buildings/soda_dispenser.png
|
||||
- type: Icon
|
||||
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
|
||||
pack: SodaDispenserInventory
|
||||
- type: PowerDevice
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.ReagentDispenserUiKey.Key
|
||||
type: ReagentDispenserBoundUserInterface
|
||||
|
||||
- type: reagentDispenserInventory
|
||||
id: SodaDispenserInventory
|
||||
inventory:
|
||||
- chem.Cola
|
||||
- chem.Coffee
|
||||
- chem.Tea
|
||||
- chem.Ice
|
||||
- chem.H2O
|
||||
0
Resources/Prototypes/Entities/items/bartending.yml
Normal file
0
Resources/Prototypes/Entities/items/bartending.yml
Normal file
41
Resources/Prototypes/Entities/items/chemistry.yml
Normal file
41
Resources/Prototypes/Entities/items/chemistry.yml
Normal file
@@ -0,0 +1,41 @@
|
||||
- type: entity
|
||||
name: Beaker
|
||||
parent: BaseItem
|
||||
description: Used to contain a moderate amount of chemicals and solutions.
|
||||
id: Beaker
|
||||
components:
|
||||
- type: Sprite
|
||||
texture: Objects/beaker.png
|
||||
- type: Icon
|
||||
texture: Objects/beaker.png
|
||||
- type: Solution
|
||||
maxVol: 50
|
||||
caps: 19
|
||||
|
||||
- type: entity
|
||||
name: Large Beaker
|
||||
parent: BaseItem
|
||||
description: Used to contain a large amount of chemicals or solutions.
|
||||
id: LargeBeaker
|
||||
components:
|
||||
- type: Sprite
|
||||
texture: Objects/beakerlarge.png
|
||||
- type: Icon
|
||||
texture: Objects/beakerlarge.png
|
||||
- type: Solution
|
||||
maxVol: 100
|
||||
caps: 19
|
||||
|
||||
- type: entity
|
||||
name: Dropper
|
||||
parent: BaseItem
|
||||
description: Used to transfer small amounts of chemical solution between containers.
|
||||
id: Dropper
|
||||
components:
|
||||
- type: Sprite
|
||||
texture: Objects/dropper.png
|
||||
- type: Icon
|
||||
texture: Objects/dropper.png
|
||||
- type: Solution
|
||||
maxVol: 5
|
||||
caps: 19
|
||||
@@ -7,3 +7,9 @@
|
||||
id: chem.H2O
|
||||
name: Water
|
||||
desc: A tasty colorless liquid.
|
||||
|
||||
- type: reagent
|
||||
id: chem.Ice
|
||||
name: Ice
|
||||
desc: Frozen water.
|
||||
color: "#bed8e6"
|
||||
29
Resources/Prototypes/Reagents/drinks.yml
Normal file
29
Resources/Prototypes/Reagents/drinks.yml
Normal file
@@ -0,0 +1,29 @@
|
||||
- type: reagent
|
||||
id: chem.Whiskey
|
||||
name: Whiskey
|
||||
desc: An alcoholic beverage made from fermented grain mash
|
||||
|
||||
- type: reagent
|
||||
id: chem.Ale
|
||||
name: Ale
|
||||
desc: A type of beer brewed using a warm fermentation method, resulting in a sweet, full-bodied and fruity taste.
|
||||
|
||||
- type: reagent
|
||||
id: chem.Wine
|
||||
name: Wine
|
||||
desc: An alcoholic drink made from fermented grapes
|
||||
|
||||
- type: reagent
|
||||
id: chem.Cola
|
||||
name: Cola
|
||||
desc: A sweet, carbonated soft drink. Caffeine free.
|
||||
|
||||
- type: reagent
|
||||
id: chem.Coffee
|
||||
name: Coffee
|
||||
desc: A drink made from brewed coffee beans. Contains a moderate amount of caffeine.
|
||||
|
||||
- type: reagent
|
||||
id: chem.Tea
|
||||
name: Tea
|
||||
desc: A made by boiling leaves of the tea tree, Camellia sinensis.
|
||||
@@ -14,3 +14,36 @@
|
||||
desc: A yellow, crystalline solid.
|
||||
color: "#FFFACD"
|
||||
|
||||
- type: reagent
|
||||
id: chem.C
|
||||
name: Carbon
|
||||
desc: A black, crystalline solid.
|
||||
color: "#22282b"
|
||||
|
||||
- type: reagent
|
||||
id: chem.Al
|
||||
name: Aluminum
|
||||
desc: A silvery-white, soft, non-magnetic, and ductile metal.
|
||||
color: "#848789"
|
||||
|
||||
- type: reagent
|
||||
id: chem.Cu
|
||||
name: Copper
|
||||
desc: A soft, malleable, and ductile metal with very high thermal and electrical conductivity.
|
||||
color: "#b05b3c"
|
||||
|
||||
- type: reagent
|
||||
id: chem.N2
|
||||
name: Nitrogen
|
||||
desc: A colorless, odorless unreactive gas. Highly stable.
|
||||
|
||||
- type: reagent
|
||||
id: chem.Fe
|
||||
name: Iron
|
||||
desc: A silvery-grey metal which forms iron oxides (rust) with contact with air. Commonly alloyed with other elements to create alloys such as steel.
|
||||
color: "#434b4d"
|
||||
|
||||
- type: reagent
|
||||
id: chem.F2
|
||||
name: Fluorine
|
||||
desc: A highly toxic pale yellow gas. Extremely reactive.
|
||||
BIN
Resources/Textures/Buildings/booze_dispenser.png
Normal file
BIN
Resources/Textures/Buildings/booze_dispenser.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 929 B |
BIN
Resources/Textures/Buildings/industrial_dispenser.png
Normal file
BIN
Resources/Textures/Buildings/industrial_dispenser.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 767 B |
BIN
Resources/Textures/Buildings/soda_dispenser.png
Normal file
BIN
Resources/Textures/Buildings/soda_dispenser.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 582 B |
BIN
Resources/Textures/Objects/beaker.png
Normal file
BIN
Resources/Textures/Objects/beaker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 237 B |
BIN
Resources/Textures/Objects/beakerlarge.png
Normal file
BIN
Resources/Textures/Objects/beakerlarge.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 239 B |
BIN
Resources/Textures/Objects/dropper.png
Normal file
BIN
Resources/Textures/Objects/dropper.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 B |
Reference in New Issue
Block a user