Add limited-reagent dispensers (#23907)
* Add limited-reagent dispensers * Add empty versions for all dispensers * Fix lint * Set initial window size so all buttons are visible * Simplify logic, add parenthesis * Use localized name for initial labels * Adjust button style * Avoid touching items before MapInit * Remove pre-labeling * Reduce diff * Clean up YAML * Fix test * Really fix test * Document * Adjust based on review * Add labels for obnoxiously long bottles --------- Co-authored-by: AWF <you@example.com>
This commit is contained in:
@@ -57,13 +57,23 @@ namespace Content.Client.Chemistry.UI
|
|||||||
_window.OnDispenseReagentButtonMouseEntered += (args, button) =>
|
_window.OnDispenseReagentButtonMouseEntered += (args, button) =>
|
||||||
{
|
{
|
||||||
if (_lastState is not null)
|
if (_lastState is not null)
|
||||||
_window.UpdateContainerInfo(_lastState, button.ReagentId);
|
_window.UpdateContainerInfo(_lastState);
|
||||||
};
|
};
|
||||||
_window.OnDispenseReagentButtonMouseExited += (args, button) =>
|
_window.OnDispenseReagentButtonMouseExited += (args, button) =>
|
||||||
{
|
{
|
||||||
if (_lastState is not null)
|
if (_lastState is not null)
|
||||||
_window.UpdateContainerInfo(_lastState);
|
_window.UpdateContainerInfo(_lastState);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_window.OnEjectJugButtonPressed += (args, button) => SendMessage(new ItemSlotButtonPressedEvent(button.ReagentId));
|
||||||
|
_window.OnEjectJugButtonMouseEntered += (args, button) => {
|
||||||
|
if (_lastState is not null)
|
||||||
|
_window.UpdateContainerInfo(_lastState);
|
||||||
|
};
|
||||||
|
_window.OnEjectJugButtonMouseExited += (args, button) => {
|
||||||
|
if (_lastState is not null)
|
||||||
|
_window.UpdateContainerInfo(_lastState);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
Title="{Loc 'reagent-dispenser-bound-user-interface-title'}"
|
Title="{Loc 'reagent-dispenser-bound-user-interface-title'}"
|
||||||
SetSize="620 450"
|
MinSize="680 450">
|
||||||
MinSize="620 450">
|
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Text="{Loc 'reagent-dispenser-window-amount-to-dispense-label'}"/>
|
<Label Text="{Loc 'reagent-dispenser-window-amount-to-dispense-label'}"/>
|
||||||
@@ -18,10 +17,8 @@
|
|||||||
<Button Name="DispenseButton100" Access="Public" Text="100" StyleClasses="OpenLeft"/>
|
<Button Name="DispenseButton100" Access="Public" Text="100" StyleClasses="OpenLeft"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<Control MinSize="0 10"/>
|
<Control MinSize="0 10"/>
|
||||||
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" MinSize="0 170">
|
<GridContainer Name="ChemicalList" HorizontalExpand="True" VerticalExpand="True" Access="Public" Columns="6">
|
||||||
<GridContainer Name="ChemicalList" Access="Public" Columns="4">
|
|
||||||
</GridContainer>
|
</GridContainer>
|
||||||
</ScrollContainer>
|
|
||||||
<Control MinSize="0 10"/>
|
<Control MinSize="0 10"/>
|
||||||
<BoxContainer Orientation="Horizontal">
|
<BoxContainer Orientation="Horizontal">
|
||||||
<Label Text="{Loc 'reagent-dispenser-window-container-label'}"/>
|
<Label Text="{Loc 'reagent-dispenser-window-container-label'}"/>
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ namespace Content.Client.Chemistry.UI
|
|||||||
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseEntered;
|
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseEntered;
|
||||||
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseExited;
|
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseExited;
|
||||||
|
|
||||||
|
public event Action<BaseButton.ButtonEventArgs, EjectJugButton>? OnEjectJugButtonPressed;
|
||||||
|
public event Action<GUIMouseHoverEventArgs, EjectJugButton>? OnEjectJugButtonMouseEntered;
|
||||||
|
public event Action<GUIMouseHoverEventArgs, EjectJugButton>? OnEjectJugButtonMouseExited;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create and initialize the dispenser UI client-side. Creates the basic layout,
|
/// 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.
|
/// actual data isn't filled in until the server sends data about the dispenser.
|
||||||
@@ -48,25 +52,25 @@ namespace Content.Client.Chemistry.UI
|
|||||||
/// Update the button grid of reagents which can be dispensed.
|
/// Update the button grid of reagents which can be dispensed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
|
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
|
||||||
public void UpdateReagentsList(List<ReagentId> inventory)
|
public void UpdateReagentsList(List<KeyValuePair<string, KeyValuePair<string,string>>> inventory)
|
||||||
{
|
{
|
||||||
if (ChemicalList == null)
|
if (ChemicalList == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ChemicalList.Children.Clear();
|
ChemicalList.Children.Clear();
|
||||||
|
|
||||||
foreach (var entry in inventory
|
foreach (KeyValuePair<string, KeyValuePair<string, string>> entry in inventory)
|
||||||
.OrderBy(r => {_prototypeManager.TryIndex(r.Prototype, out ReagentPrototype? p); return p?.LocalizedName;}))
|
|
||||||
{
|
{
|
||||||
var localizedName = _prototypeManager.TryIndex(entry.Prototype, out ReagentPrototype? p)
|
var button = new DispenseReagentButton(entry.Key, entry.Value.Key, entry.Value.Value);
|
||||||
? p.LocalizedName
|
|
||||||
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
|
|
||||||
|
|
||||||
var button = new DispenseReagentButton(entry, localizedName);
|
|
||||||
button.OnPressed += args => OnDispenseReagentButtonPressed?.Invoke(args, button);
|
button.OnPressed += args => OnDispenseReagentButtonPressed?.Invoke(args, button);
|
||||||
button.OnMouseEntered += args => OnDispenseReagentButtonMouseEntered?.Invoke(args, button);
|
button.OnMouseEntered += args => OnDispenseReagentButtonMouseEntered?.Invoke(args, button);
|
||||||
button.OnMouseExited += args => OnDispenseReagentButtonMouseExited?.Invoke(args, button);
|
button.OnMouseExited += args => OnDispenseReagentButtonMouseExited?.Invoke(args, button);
|
||||||
ChemicalList.AddChild(button);
|
ChemicalList.AddChild(button);
|
||||||
|
var ejectButton = new EjectJugButton(entry.Key);
|
||||||
|
ejectButton.OnPressed += args => OnEjectJugButtonPressed?.Invoke(args, ejectButton);
|
||||||
|
ejectButton.OnMouseEntered += args => OnEjectJugButtonMouseEntered?.Invoke(args, ejectButton);
|
||||||
|
ejectButton.OnMouseExited += args => OnEjectJugButtonMouseExited?.Invoke(args, ejectButton);
|
||||||
|
ChemicalList.AddChild(ejectButton);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,9 +125,8 @@ namespace Content.Client.Chemistry.UI
|
|||||||
/// <para>Also highlights a reagent if it's dispense button is being mouse hovered.</para>
|
/// <para>Also highlights a reagent if it's dispense button is being mouse hovered.</para>
|
||||||
/// </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,
|
|
||||||
/// or null if no button is being hovered.</param>
|
/// or null if no button is being hovered.</param>
|
||||||
public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state, ReagentId? highlightedReagentId = null)
|
public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state)
|
||||||
{
|
{
|
||||||
ContainerInfo.Children.Clear();
|
ContainerInfo.Children.Clear();
|
||||||
|
|
||||||
@@ -161,12 +164,6 @@ namespace Content.Client.Chemistry.UI
|
|||||||
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor},
|
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the reagent is being moused over. If so, color it green.
|
|
||||||
if (reagent == highlightedReagentId) {
|
|
||||||
nameLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
|
|
||||||
quantityLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
|
|
||||||
}
|
|
||||||
|
|
||||||
ContainerInfo.Children.Add(new BoxContainer
|
ContainerInfo.Children.Add(new BoxContainer
|
||||||
{
|
{
|
||||||
Orientation = LayoutOrientation.Horizontal,
|
Orientation = LayoutOrientation.Horizontal,
|
||||||
@@ -180,13 +177,27 @@ namespace Content.Client.Chemistry.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class DispenseReagentButton : Button {
|
public sealed class DispenseReagentButton : Button
|
||||||
public ReagentId ReagentId { get; }
|
|
||||||
|
|
||||||
public DispenseReagentButton(ReagentId reagentId, string text)
|
|
||||||
{
|
{
|
||||||
|
public string ReagentId { get; }
|
||||||
|
|
||||||
|
public DispenseReagentButton(string reagentId, string text, string amount)
|
||||||
|
{
|
||||||
|
AddStyleClass("OpenRight");
|
||||||
ReagentId = reagentId;
|
ReagentId = reagentId;
|
||||||
Text = text;
|
Text = text + " " + amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class EjectJugButton : Button
|
||||||
|
{
|
||||||
|
public string ReagentId { get; }
|
||||||
|
|
||||||
|
public EjectJugButton(string reagentId)
|
||||||
|
{
|
||||||
|
AddStyleClass("OpenLeft");
|
||||||
|
ReagentId = reagentId;
|
||||||
|
Text = "⏏";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using Content.Client.Chemistry.UI;
|
using Content.Client.Chemistry.UI;
|
||||||
using Content.IntegrationTests.Tests.Interaction;
|
using Content.IntegrationTests.Tests.Interaction;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
|
using Content.Server.Chemistry.Components;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
|
|
||||||
namespace Content.IntegrationTests.Tests.Chemistry;
|
namespace Content.IntegrationTests.Tests.Chemistry;
|
||||||
@@ -24,7 +25,7 @@ public sealed class DispenserTest : InteractionTest
|
|||||||
await Interact();
|
await Interact();
|
||||||
|
|
||||||
// Eject beaker via BUI.
|
// Eject beaker via BUI.
|
||||||
var ev = new ItemSlotButtonPressedEvent(SharedChemMaster.InputSlotName);
|
var ev = new ItemSlotButtonPressedEvent(ReagentDispenserComponent.BeakerSlotId);
|
||||||
await SendBui(ReagentDispenserUiKey.Key, ev);
|
await SendBui(ReagentDispenserUiKey.Key, ev);
|
||||||
|
|
||||||
// Beaker is back in the player's hands
|
// Beaker is back in the player's hands
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using Content.Shared.Whitelist;
|
||||||
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Server.Chemistry.EntitySystems;
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.Chemistry.Dispenser;
|
using Content.Shared.Chemistry.Dispenser;
|
||||||
@@ -7,20 +9,57 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
|
|||||||
namespace Content.Server.Chemistry.Components
|
namespace Content.Server.Chemistry.Components
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A machine that dispenses reagents into a solution container.
|
/// A machine that dispenses reagents into a solution container from containers in its storage slots.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[Access(typeof(ReagentDispenserSystem))]
|
[Access(typeof(ReagentDispenserSystem))]
|
||||||
public sealed partial class ReagentDispenserComponent : Component
|
public sealed partial class ReagentDispenserComponent : Component
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// String with the pack name that stores the initial fill of the dispenser. The initial
|
||||||
|
/// fill is added to the dispenser on MapInit. Note that we don't use ContainerFill because
|
||||||
|
/// we have to generate the storage slots at MapInit first, then fill them.
|
||||||
|
/// </summary>
|
||||||
[DataField("pack", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentDispenserInventoryPrototype>))]
|
[DataField("pack", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentDispenserInventoryPrototype>))]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public string? PackPrototypeId = default!;
|
public string? PackPrototypeId = default!;
|
||||||
|
|
||||||
[DataField("emagPack", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentDispenserInventoryPrototype>))]
|
/// <summary>
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
/// Maximum number of internal storage slots. Dispenser can't store (or dispense) more than
|
||||||
public string? EmagPackPrototypeId = default!;
|
/// this many chemicals (without unloading and reloading).
|
||||||
|
/// </summary>
|
||||||
|
[DataField("numStorageSlots")]
|
||||||
|
public int NumSlots = 25;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For each created storage slot for the reagent containers being dispensed, apply this
|
||||||
|
/// entity whitelist. Makes sure weird containers don't fit in the dispenser and that beakers
|
||||||
|
/// don't accidentally get slotted into the source slots.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public EntityWhitelist? StorageWhitelist;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Slot for container to dispense into.
|
||||||
|
/// </summary>
|
||||||
|
public static string BeakerSlotId = "ReagentDispenser-beakerSlot";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public ItemSlot BeakerSlot = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prefix for automatically-generated slot name for storage, up to NumSlots.
|
||||||
|
/// </summary>
|
||||||
|
public static string BaseStorageSlotId = "ReagentDispenser-storageSlot";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of storage slots that were created at MapInit.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public List<string> StorageSlotIds = new List<string>();
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public List<ItemSlot> StorageSlots = new List<ItemSlot>();
|
||||||
|
|
||||||
[DataField("clickSound"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("clickSound"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public SoundSpecifier ClickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
|
public SoundSpecifier ClickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.Chemistry.Components;
|
using Content.Server.Chemistry.Components;
|
||||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||||
|
using Content.Server.Nutrition.Components;
|
||||||
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
|
using Content.Server.Labels.Components;
|
||||||
|
using Content.Server.Chemistry;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
|
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||||
using Content.Shared.Chemistry.Dispenser;
|
using Content.Shared.Chemistry.Dispenser;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Emag.Components;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Emag.Systems;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Server.Audio;
|
using Robust.Server.Audio;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.GameObjects;
|
||||||
@@ -28,10 +32,13 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
|
[Dependency] private readonly SolutionTransferSystem _solutionTransferSystem = default!;
|
||||||
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||||
|
[Dependency] private readonly OpenableSystem _openable = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -41,11 +48,12 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
SubscribeLocalEvent<ReagentDispenserComponent, EntInsertedIntoContainerMessage>(SubscribeUpdateUiState);
|
SubscribeLocalEvent<ReagentDispenserComponent, EntInsertedIntoContainerMessage>(SubscribeUpdateUiState);
|
||||||
SubscribeLocalEvent<ReagentDispenserComponent, EntRemovedFromContainerMessage>(SubscribeUpdateUiState);
|
SubscribeLocalEvent<ReagentDispenserComponent, EntRemovedFromContainerMessage>(SubscribeUpdateUiState);
|
||||||
SubscribeLocalEvent<ReagentDispenserComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
|
SubscribeLocalEvent<ReagentDispenserComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
|
||||||
SubscribeLocalEvent<ReagentDispenserComponent, GotEmaggedEvent>(OnEmagged);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserSetDispenseAmountMessage>(OnSetDispenseAmountMessage);
|
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserSetDispenseAmountMessage>(OnSetDispenseAmountMessage);
|
||||||
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserDispenseReagentMessage>(OnDispenseReagentMessage);
|
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserDispenseReagentMessage>(OnDispenseReagentMessage);
|
||||||
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserClearContainerSolutionMessage>(OnClearContainerSolutionMessage);
|
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserClearContainerSolutionMessage>(OnClearContainerSolutionMessage);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<ReagentDispenserComponent, MapInitEvent>(OnMapInit, before: new []{typeof(ItemSlotsSystem)});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SubscribeUpdateUiState<T>(Entity<ReagentDispenserComponent> ent, ref T ev)
|
private void SubscribeUpdateUiState<T>(Entity<ReagentDispenserComponent> ent, ref T ev)
|
||||||
@@ -80,35 +88,38 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ReagentId> GetInventory(Entity<ReagentDispenserComponent> ent)
|
private List<KeyValuePair<string, KeyValuePair<string, string>>> GetInventory(ReagentDispenserComponent reagentDispenser)
|
||||||
{
|
{
|
||||||
var reagentDispenser = ent.Comp;
|
var inventory = new List<KeyValuePair<string, KeyValuePair<string, string>>>();
|
||||||
var inventory = new List<ReagentId>();
|
|
||||||
|
|
||||||
if (reagentDispenser.PackPrototypeId is not null
|
for (var i = 0; i < reagentDispenser.NumSlots; i++)
|
||||||
&& _prototypeManager.TryIndex(reagentDispenser.PackPrototypeId, out ReagentDispenserInventoryPrototype? packPrototype))
|
|
||||||
{
|
{
|
||||||
inventory.AddRange(packPrototype.Inventory.Select(x => new ReagentId(x, null)));
|
var storageSlotId = ReagentDispenserComponent.BaseStorageSlotId + i;
|
||||||
|
var storedContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser.Owner, storageSlotId);
|
||||||
|
|
||||||
|
// Set label from manually-applied label, or metadata if unavailable
|
||||||
|
string reagentLabel;
|
||||||
|
if (TryComp<LabelComponent>(storedContainer, out var label) && !string.IsNullOrEmpty(label.CurrentLabel))
|
||||||
|
reagentLabel = label.CurrentLabel;
|
||||||
|
else if (storedContainer != null)
|
||||||
|
reagentLabel = Name(storedContainer.Value);
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Add volume remaining label
|
||||||
|
FixedPoint2 quantity = 0f;
|
||||||
|
if (storedContainer != null && _solutionContainerSystem.TryGetDrainableSolution(storedContainer.Value, out _, out var sol))
|
||||||
|
{
|
||||||
|
quantity = sol.Volume;
|
||||||
}
|
}
|
||||||
|
var storedAmount = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity));
|
||||||
|
|
||||||
if (HasComp<EmaggedComponent>(ent)
|
inventory.Add(new KeyValuePair<string, KeyValuePair<string, string>>(storageSlotId, new KeyValuePair<string, string>(reagentLabel, storedAmount)));
|
||||||
&& reagentDispenser.EmagPackPrototypeId is not null
|
|
||||||
&& _prototypeManager.TryIndex(reagentDispenser.EmagPackPrototypeId, out ReagentDispenserInventoryPrototype? emagPackPrototype))
|
|
||||||
{
|
|
||||||
inventory.AddRange(emagPackPrototype.Inventory.Select(x => new ReagentId(x, null)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return inventory;
|
return inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEmagged(Entity<ReagentDispenserComponent> reagentDispenser, ref GotEmaggedEvent args)
|
|
||||||
{
|
|
||||||
// adding component manually to have correct state
|
|
||||||
EntityManager.AddComponent<EmaggedComponent>(reagentDispenser);
|
|
||||||
UpdateUiState(reagentDispenser);
|
|
||||||
args.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSetDispenseAmountMessage(Entity<ReagentDispenserComponent> reagentDispenser, ref ReagentDispenserSetDispenseAmountMessage message)
|
private void OnSetDispenseAmountMessage(Entity<ReagentDispenserComponent> reagentDispenser, ref ReagentDispenserSetDispenseAmountMessage message)
|
||||||
{
|
{
|
||||||
reagentDispenser.Comp.DispenseAmount = message.ReagentDispenserDispenseAmount;
|
reagentDispenser.Comp.DispenseAmount = message.ReagentDispenserDispenseAmount;
|
||||||
@@ -119,18 +130,23 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
private void OnDispenseReagentMessage(Entity<ReagentDispenserComponent> reagentDispenser, ref ReagentDispenserDispenseReagentMessage message)
|
private void OnDispenseReagentMessage(Entity<ReagentDispenserComponent> reagentDispenser, ref ReagentDispenserDispenseReagentMessage message)
|
||||||
{
|
{
|
||||||
// Ensure that the reagent is something this reagent dispenser can dispense.
|
// Ensure that the reagent is something this reagent dispenser can dispense.
|
||||||
if (!GetInventory(reagentDispenser).Contains(message.ReagentId))
|
var storedContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, message.SlotId);
|
||||||
|
if (storedContainer == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName);
|
var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName);
|
||||||
if (outputContainer is not { Valid: true } || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution, out _))
|
if (outputContainer is not { Valid: true } || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution, out _))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_solutionContainerSystem.TryAddReagent(solution.Value, message.ReagentId, (int) reagentDispenser.Comp.DispenseAmount, out var dispensedAmount)
|
if (_solutionContainerSystem.TryGetDrainableSolution(storedContainer.Value, out var src, out _) &&
|
||||||
&& message.Session.AttachedEntity is not null)
|
_solutionContainerSystem.TryGetRefillableSolution(outputContainer.Value, out var dst, out _))
|
||||||
{
|
{
|
||||||
_adminLogger.Add(LogType.ChemicalReaction, LogImpact.Medium,
|
// force open container, if applicable, to avoid confusing people on why it doesn't dispense
|
||||||
$"{ToPrettyString(message.Session.AttachedEntity.Value):player} dispensed {dispensedAmount}u of {message.ReagentId} into {ToPrettyString(outputContainer.Value):entity}");
|
_openable.SetOpen(storedContainer.Value, true);
|
||||||
|
_solutionTransferSystem.Transfer(reagentDispenser,
|
||||||
|
storedContainer.Value, src.Value,
|
||||||
|
outputContainer.Value, dst.Value,
|
||||||
|
(int)reagentDispenser.Comp.DispenseAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateUiState(reagentDispenser);
|
UpdateUiState(reagentDispenser);
|
||||||
@@ -152,5 +168,41 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
{
|
{
|
||||||
_audioSystem.PlayPvs(reagentDispenser.Comp.ClickSound, reagentDispenser, AudioParams.Default.WithVolume(-2f));
|
_audioSystem.PlayPvs(reagentDispenser.Comp.ClickSound, reagentDispenser, AudioParams.Default.WithVolume(-2f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Automatically generate storage slots for all NumSlots, and fill them with their initial chemicals.
|
||||||
|
/// The actual spawning of entities happens in ItemSlotsSystem's MapInit.
|
||||||
|
/// </summary>
|
||||||
|
private void OnMapInit(EntityUid uid, ReagentDispenserComponent component, MapInitEvent args)
|
||||||
|
{
|
||||||
|
// Get list of pre-loaded containers
|
||||||
|
List<string> preLoad = new List<string>();
|
||||||
|
if (component.PackPrototypeId is not null
|
||||||
|
&& _prototypeManager.TryIndex(component.PackPrototypeId, out ReagentDispenserInventoryPrototype? packPrototype))
|
||||||
|
{
|
||||||
|
preLoad.AddRange(packPrototype.Inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate storage slots with base storage slot whitelist
|
||||||
|
for (var i = 0; i < component.NumSlots; i++)
|
||||||
|
{
|
||||||
|
var storageSlotId = ReagentDispenserComponent.BaseStorageSlotId + i;
|
||||||
|
ItemSlot storageComponent = new();
|
||||||
|
storageComponent.Whitelist = component.StorageWhitelist;
|
||||||
|
storageComponent.Swap = false;
|
||||||
|
storageComponent.EjectOnBreak = true;
|
||||||
|
|
||||||
|
// Check corresponding index in pre-loaded container (if exists) and set starting item
|
||||||
|
if (i < preLoad.Count)
|
||||||
|
storageComponent.StartingItem = preLoad[i];
|
||||||
|
|
||||||
|
component.StorageSlotIds.Add(storageSlotId);
|
||||||
|
component.StorageSlots.Add(storageComponent);
|
||||||
|
component.StorageSlots[i].Name = "Storage Slot " + (i+1);
|
||||||
|
_itemSlotsSystem.AddItemSlot(uid, component.StorageSlotIds[i], component.StorageSlots[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_itemSlotsSystem.AddItemSlot(uid, ReagentDispenserComponent.BeakerSlotId, component.BeakerSlot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||||
@@ -14,8 +14,7 @@ namespace Content.Shared.Chemistry.Dispenser
|
|||||||
[Serializable, NetSerializable, Prototype("reagentDispenserInventory")]
|
[Serializable, NetSerializable, Prototype("reagentDispenserInventory")]
|
||||||
public sealed partial class ReagentDispenserInventoryPrototype : IPrototype
|
public sealed partial class ReagentDispenserInventoryPrototype : IPrototype
|
||||||
{
|
{
|
||||||
// TODO use ReagentId
|
[DataField("inventory", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
|
||||||
[DataField("inventory", customTypeSerializer: typeof(PrototypeIdListSerializer<ReagentPrototype>))]
|
|
||||||
public List<string> Inventory = new();
|
public List<string> Inventory = new();
|
||||||
|
|
||||||
[ViewVariables, IdDataField]
|
[ViewVariables, IdDataField]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Content.Shared.Chemistry
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class SharedReagentDispenser
|
public sealed class SharedReagentDispenser
|
||||||
{
|
{
|
||||||
public const string OutputSlotName = "beakerSlot";
|
public const string OutputSlotName = "ReagentDispenser-beakerSlot";
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
@@ -25,11 +25,11 @@ namespace Content.Shared.Chemistry
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class ReagentDispenserDispenseReagentMessage : BoundUserInterfaceMessage
|
public sealed class ReagentDispenserDispenseReagentMessage : BoundUserInterfaceMessage
|
||||||
{
|
{
|
||||||
public readonly ReagentId ReagentId;
|
public readonly string SlotId;
|
||||||
|
|
||||||
public ReagentDispenserDispenseReagentMessage(ReagentId reagentId)
|
public ReagentDispenserDispenseReagentMessage(string slotId)
|
||||||
{
|
{
|
||||||
ReagentId = reagentId;
|
SlotId = slotId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,11 +59,11 @@ namespace Content.Shared.Chemistry
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of the reagents which this dispenser can dispense.
|
/// A list of the reagents which this dispenser can dispense.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly List<ReagentId> Inventory;
|
public readonly List<KeyValuePair<string, KeyValuePair<string, string>>> Inventory;
|
||||||
|
|
||||||
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
|
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
|
||||||
|
|
||||||
public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, List<ReagentId> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
|
public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, List<KeyValuePair<string, KeyValuePair<string, string>>> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
|
||||||
{
|
{
|
||||||
OutputContainer = outputContainer;
|
OutputContainer = outputContainer;
|
||||||
Inventory = inventory;
|
Inventory = inventory;
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
CopyFrom(other);
|
CopyFrom(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[DataField("whitelist")]
|
[DataField("whitelist")]
|
||||||
|
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
|
||||||
public EntityWhitelist? Whitelist;
|
public EntityWhitelist? Whitelist;
|
||||||
|
|
||||||
[DataField("blacklist")]
|
[DataField("blacklist")]
|
||||||
@@ -179,6 +179,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
/// The actual deconstruction logic is handled by the server-side EmptyOnMachineDeconstructSystem.
|
/// The actual deconstruction logic is handled by the server-side EmptyOnMachineDeconstructSystem.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[DataField("ejectOnDeconstruct")]
|
[DataField("ejectOnDeconstruct")]
|
||||||
|
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public bool EjectOnDeconstruct = true;
|
public bool EjectOnDeconstruct = true;
|
||||||
|
|
||||||
@@ -187,6 +188,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
/// ejected when it is broken or destroyed?
|
/// ejected when it is broken or destroyed?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("ejectOnBreak")]
|
[DataField("ejectOnBreak")]
|
||||||
|
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public bool EjectOnBreak = false;
|
public bool EjectOnBreak = false;
|
||||||
|
|
||||||
@@ -205,6 +207,7 @@ namespace Content.Shared.Containers.ItemSlots
|
|||||||
/// want to insert more than one item that matches the same whitelist.
|
/// want to insert more than one item that matches the same whitelist.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[DataField("swap")]
|
[DataField("swap")]
|
||||||
|
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
|
||||||
public bool Swap = true;
|
public bool Swap = true;
|
||||||
|
|
||||||
public string? ID => ContainerSlot?.ID;
|
public string? ID => ContainerSlot?.ID;
|
||||||
|
|||||||
@@ -1,61 +1,43 @@
|
|||||||
- type: reagentDispenserInventory
|
- type: reagentDispenserInventory
|
||||||
id: SodaDispenserInventory
|
id: SodaDispenserInventory
|
||||||
inventory:
|
inventory:
|
||||||
- Ice
|
- DrinkIceJug
|
||||||
- Coffee
|
- DrinkCoffeeJug
|
||||||
- Cream
|
- DrinkCreamCartonXL
|
||||||
- Tea
|
- DrinkTeaJug
|
||||||
- GreenTea
|
- DrinkGreenTeaJug
|
||||||
- IcedTea
|
- DrinkIcedTeaJug
|
||||||
- IcedGreenTea
|
- DrinkColaBottleFull
|
||||||
- Cola
|
- DrinkSpaceMountainWindBottleFull
|
||||||
- SpaceMountainWind
|
- DrinkDrGibbJug
|
||||||
- DrGibb
|
- DrinkRootBeerJug
|
||||||
- RootBeer
|
- DrinkSpaceUpBottleFull
|
||||||
- SpaceUp
|
- DrinkTonicWaterBottleFull
|
||||||
- TonicWater
|
- DrinkSodaWaterBottleFull
|
||||||
- SodaWater
|
- DrinkLemonLimeJug
|
||||||
- LemonLime
|
- DrinkSugarJug
|
||||||
- Sugar
|
- DrinkJuiceOrangeCartonXL
|
||||||
- JuiceOrange
|
- DrinkJuiceLimeCartonXL
|
||||||
- JuiceLime
|
- DrinkWaterMelonJuiceJug
|
||||||
- JuiceWatermelon
|
|
||||||
###Hacked
|
|
||||||
#- Fourteen Loko
|
|
||||||
#- GrapeSoda
|
|
||||||
|
|
||||||
- type: reagentDispenserInventory
|
- type: reagentDispenserInventory
|
||||||
id: BoozeDispenserInventory
|
id: BoozeDispenserInventory
|
||||||
inventory:
|
inventory:
|
||||||
- Beer
|
- DrinkLemonLimeJug
|
||||||
- CoffeeLiqueur
|
- DrinkSugarJug
|
||||||
- Whiskey
|
- DrinkJuiceOrangeCartonXL
|
||||||
- Wine
|
- DrinkJuiceLimeCartonXL
|
||||||
- Vodka
|
- DrinkTonicWaterBottleFull
|
||||||
- Gin
|
- DrinkSodaWaterBottleFull
|
||||||
- Rum
|
- DrinkBeerGrowler
|
||||||
- Tequila
|
- DrinkCoffeeLiqueurBottleFull
|
||||||
- Vermouth
|
- DrinkWhiskeyBottleFull
|
||||||
- Cognac
|
- DrinkWineBottleFull
|
||||||
- Ale
|
- DrinkVodkaBottleFull
|
||||||
- Mead
|
- DrinkGinBottleFull
|
||||||
###Hacked
|
- DrinkRumBottleFull
|
||||||
#- Goldschlager
|
- DrinkTequilaBottleFull
|
||||||
#- Patron
|
- DrinkVermouthBottleFull
|
||||||
#- JuiceWatermelon
|
- DrinkCognacBottleFull
|
||||||
#- JuiceBerry
|
- DrinkAleBottleFullGrowler
|
||||||
|
- DrinkMeadJug
|
||||||
|
|
||||||
- type: reagentDispenserInventory
|
|
||||||
id: SodaDispenserEmagInventory
|
|
||||||
inventory:
|
|
||||||
- FourteenLoko
|
|
||||||
- Ephedrine
|
|
||||||
- Histamine
|
|
||||||
|
|
||||||
- type: reagentDispenserInventory
|
|
||||||
id: BoozeDispenserEmagInventory
|
|
||||||
inventory:
|
|
||||||
- AtomicBomb
|
|
||||||
- Ethanol
|
|
||||||
- Iron
|
|
||||||
|
|||||||
@@ -1,31 +1,26 @@
|
|||||||
- type: reagentDispenserInventory
|
- type: reagentDispenserInventory
|
||||||
id: ChemDispenserStandardInventory
|
id: ChemDispenserStandardInventory
|
||||||
inventory:
|
inventory:
|
||||||
- Aluminium
|
- JugAluminium
|
||||||
- Carbon
|
- JugCarbon
|
||||||
- Chlorine
|
- JugChlorine
|
||||||
- Copper
|
- JugCopper
|
||||||
- Ethanol
|
- JugEthanol
|
||||||
- Fluorine
|
- JugFluorine
|
||||||
- Sugar
|
- JugSugar
|
||||||
- Hydrogen
|
- JugHydrogen
|
||||||
- Iodine
|
- JugIodine
|
||||||
- Iron
|
- JugIron
|
||||||
- Lithium
|
- JugLithium
|
||||||
- Mercury
|
- JugMercury
|
||||||
- Nitrogen
|
- JugNitrogen
|
||||||
- Oxygen
|
- JugOxygen
|
||||||
- Phosphorus
|
- JugPhosphorus
|
||||||
- Potassium
|
- JugPotassium
|
||||||
- Radium
|
- JugRadium
|
||||||
- Silicon
|
- JugSilicon
|
||||||
- Sodium
|
- JugSodium
|
||||||
- Sulfur
|
- JugSulfur
|
||||||
|
|
||||||
- type: reagentDispenserInventory
|
- type: reagentDispenserInventory
|
||||||
id: ChemDispenserEmaggedInventory
|
id: EmptyInventory
|
||||||
inventory: ##Feel free to change this to something more interesting when more chems are added
|
|
||||||
- Napalm
|
|
||||||
- Toxin
|
|
||||||
- Epinephrine
|
|
||||||
- Ultravasculine
|
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
id: DrinkBottlePlasticBaseFull
|
id: DrinkBottlePlasticBaseFull
|
||||||
abstract: true
|
abstract: true
|
||||||
components:
|
components:
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- DrinkBottle
|
||||||
- type: Openable
|
- type: Openable
|
||||||
sound:
|
sound:
|
||||||
collection: bottleOpenSounds
|
collection: bottleOpenSounds
|
||||||
@@ -13,6 +16,7 @@
|
|||||||
maxVol: 100
|
maxVol: 100
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: icon
|
state: icon
|
||||||
|
sprite: Objects/Consumable/Drinks/water.rsi # fallback to boring water jug
|
||||||
- type: Item
|
- type: Item
|
||||||
size: Normal
|
size: Normal
|
||||||
- type: Damageable
|
- type: Damageable
|
||||||
@@ -285,6 +289,8 @@
|
|||||||
reagents:
|
reagents:
|
||||||
- ReagentId: Rum
|
- ReagentId: Rum
|
||||||
Quantity: 100
|
Quantity: 100
|
||||||
|
- type: Label
|
||||||
|
currentLabel: rum
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/rumbottle.rsi
|
sprite: Objects/Consumable/Drinks/rumbottle.rsi
|
||||||
|
|
||||||
@@ -332,6 +338,8 @@
|
|||||||
reagents:
|
reagents:
|
||||||
- ReagentId: Tequila
|
- ReagentId: Tequila
|
||||||
Quantity: 100
|
Quantity: 100
|
||||||
|
- type: Label
|
||||||
|
currentLabel: tequila
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/tequillabottle.rsi
|
sprite: Objects/Consumable/Drinks/tequillabottle.rsi
|
||||||
|
|
||||||
@@ -347,6 +355,8 @@
|
|||||||
reagents:
|
reagents:
|
||||||
- ReagentId: Vermouth
|
- ReagentId: Vermouth
|
||||||
Quantity: 100
|
Quantity: 100
|
||||||
|
- type: Label
|
||||||
|
currentLabel: vermouth
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/vermouthbottle.rsi
|
sprite: Objects/Consumable/Drinks/vermouthbottle.rsi
|
||||||
|
|
||||||
@@ -377,6 +387,8 @@
|
|||||||
reagents:
|
reagents:
|
||||||
- ReagentId: Whiskey
|
- ReagentId: Whiskey
|
||||||
Quantity: 100
|
Quantity: 100
|
||||||
|
- type: Label
|
||||||
|
currentLabel: whiskey
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/whiskeybottle.rsi
|
sprite: Objects/Consumable/Drinks/whiskeybottle.rsi
|
||||||
|
|
||||||
@@ -392,6 +404,8 @@
|
|||||||
reagents:
|
reagents:
|
||||||
- ReagentId: Wine
|
- ReagentId: Wine
|
||||||
Quantity: 100
|
Quantity: 100
|
||||||
|
- type: Label
|
||||||
|
currentLabel: wine
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/winebottle.rsi
|
sprite: Objects/Consumable/Drinks/winebottle.rsi
|
||||||
|
|
||||||
@@ -417,6 +431,22 @@
|
|||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: DrinkBottleGlassBaseFull
|
parent: DrinkBottleGlassBaseFull
|
||||||
|
id: DrinkBeerGrowler # Needs to be renamed DrinkBeerBottleFull
|
||||||
|
name: Beer Growler # beer it is. coffee. beer? coff-ee? be-er? c-o... b-e
|
||||||
|
description: An alcoholic beverage made from malted grains, hops, yeast, and water. XL growler bottle.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 150
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Beer
|
||||||
|
Quantity: 150
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Drinks/beer.rsi
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
id: DrinkAleBottleFull
|
id: DrinkAleBottleFull
|
||||||
name: Magm-Ale
|
name: Magm-Ale
|
||||||
description: A true dorf's drink of choice.
|
description: A true dorf's drink of choice.
|
||||||
@@ -433,6 +463,22 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/alebottle.rsi
|
sprite: Objects/Consumable/Drinks/alebottle.rsi
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkAleBottleFullGrowler
|
||||||
|
name: Magm-Ale Growler
|
||||||
|
description: A true dorf's drink of choice. XL growler bottle.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 150
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Ale
|
||||||
|
Quantity: 150
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Drinks/alebottle.rsi
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: DrinkBottlePlasticBaseFull
|
parent: DrinkBottlePlasticBaseFull
|
||||||
id: DrinkWaterBottleFull
|
id: DrinkWaterBottleFull
|
||||||
@@ -451,3 +497,258 @@
|
|||||||
- type: Drink
|
- type: Drink
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/waterbottle.rsi
|
sprite: Objects/Consumable/Drinks/waterbottle.rsi
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkSodaWaterBottleFull
|
||||||
|
name: soda water bottle
|
||||||
|
description: Like water, but angry!
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 150
|
||||||
|
reagents:
|
||||||
|
- ReagentId: SodaWater
|
||||||
|
Quantity: 150
|
||||||
|
- type: Drink
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Drinks/waterbottle.rsi
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkTonicWaterBottleFull
|
||||||
|
name: tonic water bottle
|
||||||
|
description: Like soda water, but angrier maybe? Often sweeter.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 150
|
||||||
|
reagents:
|
||||||
|
- ReagentId: TonicWater
|
||||||
|
Quantity: 150
|
||||||
|
- type: Drink
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Drinks/waterbottle.rsi
|
||||||
|
|
||||||
|
# Cartons, TODO: this needs to be moved elsewhere eventually, since cartons shouldnt smash into glass shards
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkJuiceLimeCartonXL
|
||||||
|
name: lime juice XL
|
||||||
|
description: Sweet-sour goodness.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 150
|
||||||
|
reagents:
|
||||||
|
- ReagentId: JuiceLime
|
||||||
|
Quantity: 150
|
||||||
|
- type: Drink
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Drinks/limejuice.rsi
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkJuiceOrangeCartonXL
|
||||||
|
name: orange juice XL
|
||||||
|
description: Full of vitamins and deliciousness!
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 150
|
||||||
|
reagents:
|
||||||
|
- ReagentId: JuiceOrange
|
||||||
|
Quantity: 150
|
||||||
|
- type: Drink
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Drinks/orangejuice.rsi
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkCreamCartonXL
|
||||||
|
name: Milk Cream XL
|
||||||
|
description: It's cream. Made from milk. What else did you think you'd find in there?
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 150
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Cream
|
||||||
|
Quantity: 150
|
||||||
|
- type: Drink
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Drinks/cream.rsi
|
||||||
|
|
||||||
|
#boring jugs some more sprites are made
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkSugarJug
|
||||||
|
name: sugar
|
||||||
|
suffix: for drinks
|
||||||
|
description: some people put this in their coffee...
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Sugar
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkLemonLimeJug
|
||||||
|
name: lemon lime
|
||||||
|
description: a dual citrus sensation.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: LemonLime
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkMeadJug
|
||||||
|
name: mead jug
|
||||||
|
description: storing mead in a plastic jug should be a crime.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 150
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Mead
|
||||||
|
Quantity: 150
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkIceJug
|
||||||
|
name: ice jug
|
||||||
|
description: stubborn water. pretty cool.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Ice
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkCoffeeJug
|
||||||
|
name: coffee jug
|
||||||
|
description: wake up juice, of the heated kind.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Coffee
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkTeaJug
|
||||||
|
name: tea jug
|
||||||
|
description: the drink of choice for the Bri'ish and hipsters.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: Tea
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkGreenTeaJug
|
||||||
|
name: green tea jug
|
||||||
|
description: its like tea... but green! great for settling the stomach.
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: GreenTea
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkIcedTeaJug
|
||||||
|
name: iced tea jug
|
||||||
|
description: for when the regular tea is too hot for you boohoo
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: IcedTea
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkDrGibbJug
|
||||||
|
name: dr gibb jug
|
||||||
|
description: yeah I don't know either...
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: DrGibb
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkRootBeerJug
|
||||||
|
name: root beer jug
|
||||||
|
description: this drink makes Australians giggle
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: RootBeer
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkBottlePlasticBaseFull
|
||||||
|
id: DrinkWaterMelonJuiceJug
|
||||||
|
name: watermelon juice jug
|
||||||
|
description: May include leftover seeds
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
drink:
|
||||||
|
maxVol: 300
|
||||||
|
reagents:
|
||||||
|
- ReagentId: JuiceWatermelon
|
||||||
|
Quantity: 300
|
||||||
|
- type: Drink
|
||||||
|
|||||||
@@ -553,7 +553,7 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: medical
|
state: medical
|
||||||
- type: MachineBoard
|
- type: MachineBoard
|
||||||
prototype: ChemDispenser
|
prototype: ChemDispenserEmpty
|
||||||
requirements:
|
requirements:
|
||||||
Capacitor: 1
|
Capacitor: 1
|
||||||
materialRequirements:
|
materialRequirements:
|
||||||
@@ -1145,7 +1145,7 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: service
|
state: service
|
||||||
- type: MachineBoard
|
- type: MachineBoard
|
||||||
prototype: BoozeDispenser
|
prototype: BoozeDispenserEmpty
|
||||||
materialRequirements:
|
materialRequirements:
|
||||||
Steel: 5
|
Steel: 5
|
||||||
tagRequirements:
|
tagRequirements:
|
||||||
@@ -1178,7 +1178,7 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: service
|
state: service
|
||||||
- type: MachineBoard
|
- type: MachineBoard
|
||||||
prototype: soda_dispenser
|
prototype: SodaDispenserEmpty
|
||||||
materialRequirements:
|
materialRequirements:
|
||||||
Steel: 5
|
Steel: 5
|
||||||
tagRequirements:
|
tagRequirements:
|
||||||
|
|||||||
@@ -47,6 +47,9 @@
|
|||||||
price: 60
|
price: 60
|
||||||
- type: Label
|
- type: Label
|
||||||
originalName: jug
|
originalName: jug
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- ChemDispensable
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: Jug
|
parent: Jug
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
abstract: true
|
abstract: true
|
||||||
id: ReagentDispenserBase
|
id: ReagentDispenserBase
|
||||||
parent: ConstructibleMachine
|
parent: ConstructibleMachine
|
||||||
@@ -55,18 +55,20 @@
|
|||||||
sound:
|
sound:
|
||||||
path: /Audio/Effects/metalbreak.ogg
|
path: /Audio/Effects/metalbreak.ogg
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
- type: ItemSlots
|
storageWhitelist:
|
||||||
slots:
|
tags:
|
||||||
|
- Bottle
|
||||||
beakerSlot:
|
beakerSlot:
|
||||||
whitelistFailPopup: reagent-dispenser-component-cannot-put-entity-message
|
whitelistFailPopup: reagent-dispenser-component-cannot-put-entity-message
|
||||||
whitelist:
|
whitelist:
|
||||||
components:
|
components:
|
||||||
- FitsInDispenser
|
- FitsInDispenser
|
||||||
|
- type: ItemSlots
|
||||||
- type: ContainerContainer
|
- type: ContainerContainer
|
||||||
containers:
|
containers:
|
||||||
machine_board: !type:Container
|
machine_board: !type:Container
|
||||||
machine_parts: !type:Container
|
machine_parts: !type:Container
|
||||||
beakerSlot: !type:ContainerSlot
|
ReagentDispenser-beakerSlot: !type:ContainerSlot
|
||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 1000
|
price: 1000
|
||||||
- type: Wires
|
- type: Wires
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: BoozeDispenser
|
id: BoozeDispenser
|
||||||
name: booze dispenser
|
name: booze dispenser
|
||||||
|
suffix: Filled
|
||||||
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: ReagentDispenserBase
|
parent: ReagentDispenserBase
|
||||||
components:
|
components:
|
||||||
@@ -10,8 +11,10 @@
|
|||||||
drawdepth: SmallObjects
|
drawdepth: SmallObjects
|
||||||
state: booze
|
state: booze
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
|
storageWhitelist:
|
||||||
|
tags:
|
||||||
|
- DrinkBottle
|
||||||
pack: BoozeDispenserInventory
|
pack: BoozeDispenserInventory
|
||||||
emagPack: BoozeDispenserEmagInventory
|
|
||||||
- type: Transform
|
- type: Transform
|
||||||
noRot: false
|
noRot: false
|
||||||
- type: Machine
|
- type: Machine
|
||||||
@@ -24,3 +27,14 @@
|
|||||||
- Bartender
|
- Bartender
|
||||||
- type: StealTarget
|
- type: StealTarget
|
||||||
stealGroup: BoozeDispenser
|
stealGroup: BoozeDispenser
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: BoozeDispenserEmpty
|
||||||
|
suffix: Empty
|
||||||
|
parent: BoozeDispenser
|
||||||
|
components:
|
||||||
|
- type: ReagentDispenser
|
||||||
|
storageWhitelist:
|
||||||
|
tags:
|
||||||
|
- DrinkBottle
|
||||||
|
pack: EmptyInventory
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: ChemDispenser
|
id: ChemDispenser
|
||||||
name: chemical dispenser
|
name: chemical dispenser
|
||||||
|
suffix: Filled
|
||||||
parent: ReagentDispenserBase
|
parent: ReagentDispenserBase
|
||||||
description: An industrial grade chemical dispenser with a sizeable chemical supply.
|
description: An industrial grade chemical dispenser.
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Structures/dispensers.rsi
|
sprite: Structures/dispensers.rsi
|
||||||
state: industrial-working
|
state: industrial-working
|
||||||
snapCardinals: true
|
snapCardinals: true
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
|
storageWhitelist:
|
||||||
|
tags:
|
||||||
|
- ChemDispensable
|
||||||
pack: ChemDispenserStandardInventory
|
pack: ChemDispenserStandardInventory
|
||||||
emagPack: ChemDispenserEmaggedInventory
|
|
||||||
- type: ApcPowerReceiver
|
- type: ApcPowerReceiver
|
||||||
- type: ExtensionCableReceiver
|
- type: ExtensionCableReceiver
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
@@ -37,3 +40,12 @@
|
|||||||
- Chemist
|
- Chemist
|
||||||
- type: StealTarget
|
- type: StealTarget
|
||||||
stealGroup: ChemDispenser
|
stealGroup: ChemDispenser
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ChemDispenserEmpty
|
||||||
|
name: chemical dispenser
|
||||||
|
suffix: Empty
|
||||||
|
parent: ChemDispenser
|
||||||
|
components:
|
||||||
|
- type: ReagentDispenser
|
||||||
|
pack: EmptyInventory
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: soda_dispenser
|
id: soda_dispenser
|
||||||
name: soda dispenser
|
name: soda dispenser
|
||||||
|
suffix: Filled
|
||||||
parent: ReagentDispenserBase
|
parent: ReagentDispenserBase
|
||||||
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:
|
||||||
@@ -10,8 +11,10 @@
|
|||||||
drawdepth: SmallObjects
|
drawdepth: SmallObjects
|
||||||
state: soda
|
state: soda
|
||||||
- type: ReagentDispenser
|
- type: ReagentDispenser
|
||||||
|
storageWhitelist:
|
||||||
|
tags:
|
||||||
|
- DrinkBottle
|
||||||
pack: SodaDispenserInventory
|
pack: SodaDispenserInventory
|
||||||
emagPack: SodaDispenserEmagInventory
|
|
||||||
- type: Transform
|
- type: Transform
|
||||||
noRot: false
|
noRot: false
|
||||||
- type: Machine
|
- type: Machine
|
||||||
@@ -22,3 +25,14 @@
|
|||||||
- type: GuideHelp
|
- type: GuideHelp
|
||||||
guides:
|
guides:
|
||||||
- Bartender
|
- Bartender
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: SodaDispenserEmpty
|
||||||
|
suffix: Empty
|
||||||
|
parent: soda_dispenser
|
||||||
|
components:
|
||||||
|
- type: ReagentDispenser
|
||||||
|
storageWhitelist:
|
||||||
|
tags:
|
||||||
|
- DrinkBottle
|
||||||
|
pack: EmptyInventory
|
||||||
|
|||||||
@@ -305,6 +305,9 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
id: Chicken
|
id: Chicken
|
||||||
|
|
||||||
|
- type: Tag
|
||||||
|
id: ChemDispensable # container that can go into the chem dispenser
|
||||||
|
|
||||||
- type: Tag
|
- type: Tag
|
||||||
id: Cigarette
|
id: Cigarette
|
||||||
|
|
||||||
@@ -458,6 +461,9 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
id: DrinkSpaceGlue
|
id: DrinkSpaceGlue
|
||||||
|
|
||||||
|
- type: Tag
|
||||||
|
id: DrinkBottle
|
||||||
|
|
||||||
- type: Tag
|
- type: Tag
|
||||||
id: DroneUsable
|
id: DroneUsable
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user