[WIP] [Tweak] Ограничение раздатчиков реагентов и прочих жидкостей. (#498)

* Reapply "Add limited-reagent dispensers (#23907)"

This reverts commit 531becd592.

# Conflicts:
#	Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
#	Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
#	Content.Shared/Chemistry/SharedReagentDispenser.cs
#	Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs
#	Resources/Prototypes/Catalog/ReagentDispensers/beverage.yml
#	Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml
#	Resources/Prototypes/Entities/Structures/Dispensers/chem.yml

* Reapply "Fix comp.Owner (#24206)"

This reverts commit 2d2405ff93.

* Reapply "Use old reagent dispenser beaker slot ID (#24209)"

This reverts commit 388424e2f3.

* Add a container display to dispenser UI (#25391)

* Implemented contents display for dispenser UI

* Update Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs

Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>

* Resolve the netent into a euid first

---------

Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>

* Add prediction to hand labeler labels (#25869)

Added prediction to labels

* scoopable ash and foam, solution transfer prediction (#25832)

* move SolutionTransfer to shared and predict as much as possible

* fully move OpenableSystem to shared now that SolutionTransfer is

* fix imports for everything

* doc for solution transfer system

* trolling

* add scoopable system

* make ash and foam scoopable

* untroll

* untroll real

* make clickable it work

* troll

* the scooping room

---------

Co-authored-by: deltanedas <@deltanedas:kde.org>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
# Conflicts:
#	Resources/Prototypes/Entities/Effects/chemistry_effects.yml

* Reagent dispenser UI (#27831)

* reagent dispenser: fancy window

* reagent dispenser: dispense button grid

* reagent dispenser: rearrange containers & info

* reagent dispenser: remove `reagent-dispenser-window-container-label`

* reagent dispenser: add `Scrollcontainer` on right side

* reagent dispenser: get rid of pointless actions

* reagent dispenser: cleanup actions and `inventory` field on bound ui state

* reagent dispenser: cool reagent cards & finishing touches

* reagent dispenser: final cleanup and formatting

* reagent dispenser: `ButtonGrid` and `ReagentDispenserSetDispenseAmountMessage` refactor

* reagent dispenser: cleanup code & address minor concerns

* reagent dispenser: text in reagent cards no longer clips

* reagent dispenser: oh wait i forgot to change this and thats why the builds keep failing probably

* reagent dispenser mayybe this

* reagent dispenser: remove `using FastAccessors;`
# Conflicts:
#	Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs

* Reagent dispenser UI (Again) (#27958)

* reagent dispenser: fancy window

* reagent dispenser: dispense button grid

* reagent dispenser: rearrange containers & info

* reagent dispenser: remove `reagent-dispenser-window-container-label`

* reagent dispenser: add `Scrollcontainer` on right side

* reagent dispenser: get rid of pointless actions

* reagent dispenser: cleanup actions and `inventory` field on bound ui state

* reagent dispenser: cool reagent cards & finishing touches

* reagent dispenser: final cleanup and formatting

* reagent dispenser: `ButtonGrid` and `ReagentDispenserSetDispenseAmountMessage` refactor

* reagent dispenser: cleanup code & address minor concerns

* reagent dispenser: text in reagent cards no longer clips

* reagent dispenser: oh wait i forgot to change this and thats why the builds keep failing probably

* reagent dispenser mayybe this

* reagent dispenser: remove `using FastAccessors;`

* delete unused classes

* disable reagent button when container is empty

* Make things a bit bigger

* remove obsolete text color override

* пару фиксов поверх

* переводики хихиххи

* еще переводы

* feat: химические картриджи

---------

Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: Brandon Li <48413902+aspiringLich@users.noreply.github.com>
This commit is contained in:
Remuchi
2024-08-04 13:36:11 +07:00
committed by GitHub
parent 76b15fd787
commit 467eb84d43
57 changed files with 1398 additions and 732 deletions

View File

@@ -0,0 +1,119 @@
using System;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.Chemistry.UI;
/// <summary>
/// Creates a grid of buttons given a comma-seperated list of Text
/// </summary>
public sealed class ButtonGrid : GridContainer
{
private string _buttonList = "";
/// <summary>
/// A comma-seperated list of text to use for each button. These will be inserted sequentially.
/// </summary>
public string ButtonList
{
get => _buttonList;
set
{
_buttonList = value;
Update();
}
}
public bool RadioGroup { get; set; } = false;
private string? _selected;
/// <summary>
/// Which button is currently selected. Only matters when <see cref="RadioGroup"/> is true.
/// </summary>
public string? Selected
{
get => _selected;
set
{
_selected = value;
Update();
}
}
public Action<string>? OnButtonPressed;
/// <summary>
/// <see cref="GridContainer.Columns"/>
/// </summary>
public new int Columns
{
get => base.Columns;
set
{
base.Columns = value;
Update();
}
}
/// <summary>
/// <see cref="GridContainer.Rows"/>
/// </summary>
public new int Rows
{
get => base.Rows;
set
{
base.Rows = value;
Update();
}
}
private void Update()
{
if (ButtonList == "")
return;
this.Children.Clear();
var i = 0;
var list = ButtonList.Split(",");
var group = new ButtonGroup();
foreach (var button in list)
{
var btn = new Button();
btn.Text = button;
btn.OnPressed += _ =>
{
if (RadioGroup)
btn.Pressed = true;
Selected = button;
OnButtonPressed?.Invoke(button);
};
if (button == Selected)
btn.Pressed = true;
var sep = HSeparationOverride ?? 0;
// ReSharper disable once PossibleLossOfFraction
// btn.SetWidth = (this.PixelWidth - sep * (Columns - 1)) / 3;
btn.Group = group;
var row = i / Columns;
var col = i % Columns;
var last = i == list.Length - 1;
var lastCol = i == Columns - 1;
var lastRow = row == list.Length / Columns - 1;
if (row == 0 && (lastCol || last))
btn.AddStyleClass("OpenLeft");
else if (col == 0 && lastRow)
btn.AddStyleClass("OpenRight");
else
btn.AddStyleClass("OpenBoth");
this.Children.Add(btn);
i++;
}
}
}

View File

@@ -0,0 +1,36 @@
<Control xmlns="https://spacestation14.io" HorizontalExpand="True">
<BoxContainer Name="MainContainer"
Orientation="Horizontal"
HorizontalExpand="True">
<PanelContainer Name="ColorPanel"
VerticalExpand="True"
SetWidth="7"
Margin="0 1 0 0" />
<Button Name="MainButton"
HorizontalExpand="True"
VerticalExpand="True"
StyleClasses="ButtonSquare"
Margin="-1 0 0 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
Margin="-5 0 0 0">
<Label Name="ReagentNameLabel" />
<Label Name="FillLabel"
StyleClasses="LabelSubText"
Margin="0 -5 0 0" />
</BoxContainer>
</BoxContainer>
</Button>
<Button Name="EjectButton"
StyleClasses="OpenLeft"
VerticalExpand="True"
SetWidth="20">
<Label Name="EjectButtonIcon"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="-7 -4 0 0" />
</Button>
</BoxContainer>
</Control>

View File

@@ -0,0 +1,32 @@
using Content.Shared.Chemistry;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Chemistry.UI;
[GenerateTypedNameReferences]
public sealed partial class ReagentCardControl : Control
{
public string StorageSlotId { get; }
public Action<string>? OnPressed;
public Action<string>? OnEjectButtonPressed;
public ReagentCardControl(ReagentInventoryItem item)
{
RobustXamlLoader.Load(this);
StorageSlotId = item.StorageSlotId;
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = item.ReagentColor };
ReagentNameLabel.Text = item.ReagentLabel;
FillLabel.Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", item.Quantity));;
EjectButtonIcon.Text = Loc.GetString("reagent-dispenser-window-eject-container-button");
if (item.Quantity == 0.0)
MainButton.Disabled = true;
MainButton.OnPressed += args => OnPressed?.Invoke(StorageSlotId);
EjectButton.OnPressed += args => OnEjectButtonPressed?.Invoke(StorageSlotId);
}
}

View File

@@ -42,28 +42,11 @@ namespace Content.Client.Chemistry.UI
// Setup static button actions.
_window.EjectButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName));
_window.ClearButton.OnPressed += _ => SendMessage(new ReagentDispenserClearContainerSolutionMessage());
_window.DispenseButton1.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U1));
_window.DispenseButton5.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U5));
_window.DispenseButton10.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U10));
_window.DispenseButton15.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U15));
_window.DispenseButton20.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U20));
_window.DispenseButton25.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U25));
_window.DispenseButton30.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U30));
_window.DispenseButton50.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U50));
_window.DispenseButton100.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U100));
// Setup reagent button actions.
_window.OnDispenseReagentButtonPressed += (args, button) => SendMessage(new ReagentDispenserDispenseReagentMessage(button.ReagentId));
_window.OnDispenseReagentButtonMouseEntered += (args, button) =>
{
if (_lastState is not null)
_window.UpdateContainerInfo(_lastState, button.ReagentId);
};
_window.OnDispenseReagentButtonMouseExited += (args, button) =>
{
if (_lastState is not null)
_window.UpdateContainerInfo(_lastState);
};
_window.AmountGrid.OnButtonPressed += s => SendMessage(new ReagentDispenserSetDispenseAmountMessage(s));
_window.OnDispenseReagentButtonPressed += (id) => SendMessage(new ReagentDispenserDispenseReagentMessage(id));
_window.OnEjectJugButtonPressed += (id) => SendMessage(new ItemSlotButtonPressedEvent(id));
}
/// <summary>

View File

@@ -1,53 +1,78 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Title="{Loc 'reagent-dispenser-bound-user-interface-title'}"
MinSize="680 450">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'reagent-dispenser-window-amount-to-dispense-label'}"/>
<Control MinSize="20 0"></Control>
<Button Name="DispenseButton1" Access="Public" Text="1" StyleClasses="OpenRight"/>
<Button Name="DispenseButton5" Access="Public" Text="5" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton10" Access="Public" Text="10" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton15" Access="Public" Text="15" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton20" Access="Public" Text="20" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton25" Access="Public" Text="25" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton30" Access="Public" Text="30" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton50" Access="Public" Text="50" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton100" Access="Public" Text="100" StyleClasses="OpenLeft"/>
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
xmlns:ui="clr-namespace:Content.Client.Chemistry.UI"
Title="{Loc 'reagent-dispenser-bound-user-interface-title'}"
MinSize="600 300"
SetSize="800 500">
<BoxContainer Orientation="Horizontal">
<BoxContainer Orientation="Vertical" MinWidth="170">
<Label Text="{Loc 'reagent-dispenser-window-amount-to-dispense-label'}" HorizontalAlignment="Center" />
<ui:ButtonGrid
Name="AmountGrid"
Access="Public"
Columns="3"
HorizontalAlignment="Center"
Margin="5"
ButtonList="1,5,10,15,20,25,30,50,100"
RadioGroup="True">
</ui:ButtonGrid>
<Control VerticalExpand="True" />
<Label Name="ContainerInfoName"
Access="Public"
Text=""
HorizontalAlignment="Center" />
<Label Name="ContainerInfoFill"
Access="Public"
Text=""
HorizontalAlignment="Center"
StyleClasses="LabelSubText" />
<SpriteView Name="View"
Scale="4 4"
HorizontalAlignment="Center" />
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center">
<Button Name="ClearButton"
Access="Public"
Text="{Loc 'reagent-dispenser-window-clear-button'}"
StyleClasses="OpenRight" />
<Button Name="EjectButton"
Access="Public"
Text="{Loc 'reagent-dispenser-window-eject-button'}"
StyleClasses="OpenLeft" />
</BoxContainer>
</BoxContainer>
<Control MinSize="0 10"/>
<GridContainer Name="ChemicalList" HorizontalExpand="True" VerticalExpand="True" Access="Public" Columns="6">
</GridContainer>
<Control MinSize="0 10"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'reagent-dispenser-window-container-label'}"/>
<Button Name="ClearButton"
Access="Public"
Text="{Loc 'reagent-dispenser-window-clear-button'}"
StyleClasses="OpenRight"/>
<Button Name="EjectButton"
Access="Public"
Text="{Loc 'reagent-dispenser-window-eject-button'}"
StyleClasses="OpenLeft"/>
</BoxContainer>
<Control MinSize="0 10"/>
<BoxContainer Orientation="Horizontal">
<SpriteView Name="View" Scale="4 4" MinSize="150 150"/>
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True" MinSize="0 160">
<PanelContainer VerticalExpand="True"
SizeFlagsStretchRatio="6"
MinSize="0 150">
<SplitContainer Orientation="Vertical"
HorizontalExpand="True"
VerticalExpand="True">
<ScrollContainer HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True"
MinHeight="50"
SizeFlagsStretchRatio="2.5">
<GridContainer Name="ReagentList"
HorizontalExpand="True"
VerticalExpand="True"
Access="Public"
Columns="3" />
</ScrollContainer>
<ScrollContainer HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True"
MinHeight="50">
<PanelContainer VerticalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1b1b1e" />
</PanelContainer.PanelOverride>
<BoxContainer Name="ContainerInfo"
Orientation="Vertical"
HorizontalExpand="True">
<Label Text="{Loc 'reagent-dispenser-window-no-container-loaded-text'}"/>
Orientation="Vertical"
HorizontalExpand="True"
VerticalExpand="True"
Margin="5">
<Label Text="{Loc 'reagent-dispenser-window-no-container-loaded-text'}" />
</BoxContainer>
</PanelContainer>
</ScrollContainer>
</BoxContainer>
</SplitContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View File

@@ -1,11 +1,9 @@
using System.Linq;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using static Robust.Client.UserInterface.Controls.BoxContainer;
@@ -16,14 +14,12 @@ namespace Content.Client.Chemistry.UI
/// Client-side UI used to control a <see cref="ReagentDispenserComponent"/>.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class ReagentDispenserWindow : DefaultWindow
public sealed partial class ReagentDispenserWindow : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public event Action<BaseButton.ButtonEventArgs, DispenseReagentButton>? OnDispenseReagentButtonPressed;
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseEntered;
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseExited;
public event Action<string>? OnDispenseReagentButtonPressed;
public event Action<string>? OnEjectJugButtonPressed;
/// <summary>
/// Create and initialize the dispenser UI client-side. Creates the basic layout,
@@ -33,45 +29,27 @@ namespace Content.Client.Chemistry.UI
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var dispenseAmountGroup = new ButtonGroup();
DispenseButton1.Group = dispenseAmountGroup;
DispenseButton5.Group = dispenseAmountGroup;
DispenseButton10.Group = dispenseAmountGroup;
DispenseButton15.Group = dispenseAmountGroup;
DispenseButton20.Group = dispenseAmountGroup;
DispenseButton25.Group = dispenseAmountGroup;
DispenseButton30.Group = dispenseAmountGroup;
DispenseButton50.Group = dispenseAmountGroup;
DispenseButton100.Group = dispenseAmountGroup;
}
/// <summary>
/// Update the button grid of reagents which can be dispensed.
/// </summary>
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
public void UpdateReagentsList(List<ReagentId> inventory)
public void UpdateReagentsList(List<ReagentInventoryItem> inventory)
{
if (ChemicalList == null)
if (ReagentList == null)
return;
ChemicalList.Children.Clear();
ReagentList.Children.Clear();
//Sort inventory by reagentLabel
inventory.Sort((x, y) => x.ReagentLabel.CompareTo(y.ReagentLabel));
foreach (var entry in inventory.OrderBy(r =>
{
_prototypeManager.TryIndex(r.Prototype, out ReagentPrototype? p);
return p?.LocalizedName;
}))
foreach (var item in inventory)
{
var localizedName = _prototypeManager.TryIndex(entry.Prototype, out ReagentPrototype? p)
? 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.OnMouseEntered += args => OnDispenseReagentButtonMouseEntered?.Invoke(args, button);
button.OnMouseExited += args => OnDispenseReagentButtonMouseExited?.Invoke(args, button);
ChemicalList.AddChild(button);
var card = new ReagentCardControl(item);
card.OnPressed += OnDispenseReagentButtonPressed;
card.OnEjectButtonPressed += OnEjectJugButtonPressed;
ReagentList.Children.Add(card);
}
}
@@ -92,36 +70,7 @@ namespace Content.Client.Chemistry.UI
ClearButton.Disabled = castState.OutputContainer is null;
EjectButton.Disabled = castState.OutputContainer is null;
switch (castState.SelectedDispenseAmount)
{
case ReagentDispenserDispenseAmount.U1:
DispenseButton1.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U5:
DispenseButton5.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U10:
DispenseButton10.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U15:
DispenseButton15.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U20:
DispenseButton20.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U25:
DispenseButton25.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U30:
DispenseButton30.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U50:
DispenseButton50.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U100:
DispenseButton100.Pressed = true;
break;
}
AmountGrid.Selected = ((int)castState.SelectedDispenseAmount).ToString();
}
/// <summary>
@@ -129,31 +78,22 @@ namespace Content.Client.Chemistry.UI
/// <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,
/// 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();
if (state.OutputContainer is null)
{
ContainerInfoName.Text = "";
ContainerInfoFill.Text = "";
ContainerInfo.Children.Add(new Label { Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") });
return;
}
ContainerInfo.Children.Add(new BoxContainer // Name of the container and its fill status (Ex: 44/100u)
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
new Label {Text = $"{state.OutputContainer.DisplayName}: "},
new Label
{
Text = $"{state.OutputContainer.CurrentVolume}/{state.OutputContainer.MaxVolume}",
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
}
}
});
// Set Name of the container and its fill status (Ex: 44/100u)
ContainerInfoName.Text = state.OutputContainer.DisplayName;
ContainerInfoFill.Text = state.OutputContainer.CurrentVolume + "/" + state.OutputContainer.MaxVolume;
foreach (var (reagent, quantity) in state.OutputContainer.Reagents!)
{
@@ -169,12 +109,6 @@ namespace Content.Client.Chemistry.UI
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
{
Orientation = LayoutOrientation.Horizontal,
@@ -187,14 +121,4 @@ namespace Content.Client.Chemistry.UI
}
}
}
public sealed class DispenseReagentButton : Button {
public ReagentId ReagentId { get; }
public DispenseReagentButton(ReagentId reagentId, string text)
{
ReagentId = reagentId;
Text = text;
}
}
}

View File

@@ -1,6 +1,7 @@
using Content.Client.Chemistry.UI;
using Content.IntegrationTests.Tests.Interaction;
using Content.Shared.Chemistry;
using Content.Server.Chemistry.Components;
using Content.Shared.Containers.ItemSlots;
namespace Content.IntegrationTests.Tests.Chemistry;
@@ -24,7 +25,7 @@ public sealed class DispenserTest : InteractionTest
await Interact();
// Eject beaker via BUI.
var ev = new ItemSlotButtonPressedEvent(SharedChemMaster.InputSlotName);
var ev = new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName);
await SendBui(ReagentDispenserUiKey.Key, ev);
// Beaker is back in the player's hands

View File

@@ -1,3 +1,5 @@
using Content.Shared.Whitelist;
using Content.Shared.Containers.ItemSlots;
using Content.Server.Chemistry.EntitySystems;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Dispenser;
@@ -7,20 +9,52 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
namespace Content.Server.Chemistry.Components
{
/// <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>
[RegisterComponent]
[Access(typeof(ReagentDispenserSystem), typeof(ChemMasterSystem))]
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>))]
[ViewVariables(VVAccess.ReadWrite)]
public string? PackPrototypeId = default!;
[DataField("emagPack", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentDispenserInventoryPrototype>))]
[ViewVariables(VVAccess.ReadWrite)]
public string? EmagPackPrototypeId = default!;
/// <summary>
/// Maximum number of internal storage slots. Dispenser can't store (or dispense) more than
/// 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;
[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)]
public SoundSpecifier ClickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");

View File

@@ -1,6 +1,5 @@
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.DeviceLinking.Systems;
using Content.Server.Labels;
using Content.Server.Popups;
using Content.Server.Storage.EntitySystems;
@@ -11,7 +10,6 @@ using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Database;
using Content.Shared.DeviceLinking.Events;
using Content.Shared.FixedPoint;
using Content.Shared.Storage;
using JetBrains.Annotations;
@@ -25,7 +23,6 @@ using System.Linq;
namespace Content.Server.Chemistry.EntitySystems
{
/// <summary>
/// Contains all the server-side logic for ChemMasters.
/// <seealso cref="ChemMasterComponent"/>
@@ -41,8 +38,6 @@ namespace Content.Server.Chemistry.EntitySystems
[Dependency] private readonly StorageSystem _storageSystem = default!;
[Dependency] private readonly LabelSystem _labelSystem = default!;
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
[Dependency] private readonly ReagentDispenserSystem _dispenserSystem = default!; // WD
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!; // WD
[ValidatePrototypeId<EntityPrototype>]
private const string PillPrototypeId = "Pill";
@@ -57,13 +52,6 @@ namespace Content.Server.Chemistry.EntitySystems
SubscribeLocalEvent<ChemMasterComponent, EntRemovedFromContainerMessage>(SubscribeUpdateUiState);
SubscribeLocalEvent<ChemMasterComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
// WD START
SubscribeLocalEvent<ChemMasterComponent, ComponentInit>(OnComponentInit);
SubscribeLocalEvent<ChemMasterComponent, PortDisconnectedEvent>(OnPortDisconnected);
SubscribeLocalEvent<ChemMasterComponent, AnchorStateChangedEvent>(OnAnchor);
// WD END
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetModeMessage>(OnSetModeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterSetPillTypeMessage>(OnSetPillTypeMessage);
SubscribeLocalEvent<ChemMasterComponent, ChemMasterReagentAmountButtonMessage>(OnReagentButtonMessage);
@@ -71,30 +59,6 @@ namespace Content.Server.Chemistry.EntitySystems
SubscribeLocalEvent<ChemMasterComponent, ChemMasterOutputToBottleMessage>(OnOutputToBottleMessage);
}
// WD START
private void OnComponentInit(EntityUid uid, ChemMasterComponent clonePod, ComponentInit args)
{
_signalSystem.EnsureSinkPorts(uid, ChemMasterComponent.ChemMasterPort);
}
private void OnPortDisconnected(EntityUid uid, ChemMasterComponent component, PortDisconnectedEvent args)
{
component.ConnectedDispenser = null;
}
private void OnAnchor(EntityUid uid, ChemMasterComponent component, ref AnchorStateChangedEvent args)
{
if (component.ConnectedDispenser == null ||
!TryComp<ReagentDispenserComponent>(component.ConnectedDispenser, out var dispenserComp))
return;
if (!args.Anchored)
return;
_dispenserSystem.UpdateConnection(component.ConnectedDispenser.Value, uid, dispenserComp, component);
}
// WD END
private void SubscribeUpdateUiState<T>(Entity<ChemMasterComponent> ent, ref T ev)
{
UpdateUiState(ent);

View File

@@ -1,26 +1,20 @@
using Content.Server.Administration.Logs;
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.DeviceLinking.Systems;
using Content.Server.Nutrition.Components;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Dispenser;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Database;
using Content.Shared.DeviceLinking;
using Content.Shared.DeviceLinking.Events;
using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems;
using Content.Shared.FixedPoint;
using Content.Shared.Nutrition.EntitySystems;
using JetBrains.Annotations;
using Robust.Server.Audio;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Labels.Components;
namespace Content.Server.Chemistry.EntitySystems
{
@@ -33,12 +27,12 @@ namespace Content.Server.Chemistry.EntitySystems
{
[Dependency] private readonly AudioSystem _audioSystem = default!;
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly SolutionTransferSystem _solutionTransferSystem = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly DeviceLinkSystem _signalSystem = default!; // WD
[Dependency] private readonly ChemMasterSystem _chemMasterSystem = default!; // WD
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly OpenableSystem _openable = default!;
public override void Initialize()
{
@@ -50,108 +44,13 @@ namespace Content.Server.Chemistry.EntitySystems
SubscribeLocalEvent<ReagentDispenserComponent, EntRemovedFromContainerMessage>(SubscribeUpdateUiState);
SubscribeLocalEvent<ReagentDispenserComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
// WD START
SubscribeLocalEvent<ReagentDispenserComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<ReagentDispenserComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<ReagentDispenserComponent, NewLinkEvent>(OnNewLink);
SubscribeLocalEvent<ReagentDispenserComponent, PortDisconnectedEvent>(OnPortDisconnected);
SubscribeLocalEvent<ReagentDispenserComponent, AnchorStateChangedEvent>(OnAnchorChanged);
// WD END
SubscribeLocalEvent<ReagentDispenserComponent, GotEmaggedEvent>(OnEmagged);
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserSetDispenseAmountMessage>(OnSetDispenseAmountMessage);
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserDispenseReagentMessage>(OnDispenseReagentMessage);
SubscribeLocalEvent<ReagentDispenserComponent, ReagentDispenserClearContainerSolutionMessage>(OnClearContainerSolutionMessage);
SubscribeLocalEvent<ReagentDispenserComponent, MapInitEvent>(OnMapInit, before: new []{typeof(ItemSlotsSystem)});
}
// WD START
private void OnInit(EntityUid uid, ReagentDispenserComponent component, ComponentInit args)
{
_signalSystem.EnsureSourcePorts(uid, ReagentDispenserComponent.ChemMasterPort);
}
private void OnMapInit(EntityUid uid, ReagentDispenserComponent component, MapInitEvent args)
{
if (!TryComp<DeviceLinkSourceComponent>(uid, out var receiver))
return;
foreach (var port in receiver.Outputs.Values.SelectMany(ports => ports))
{
if (!TryComp<ChemMasterComponent>(port, out var master))
continue;
UpdateConnection(uid, port, component, master);
break;
}
}
private void OnNewLink(EntityUid uid, ReagentDispenserComponent component, NewLinkEvent args)
{
if (TryComp<ChemMasterComponent>(args.Sink, out var master) && args.SourcePort == ReagentDispenserComponent.ChemMasterPort)
UpdateConnection(uid, args.Sink, component, master);
}
private void OnPortDisconnected(EntityUid uid, ReagentDispenserComponent component, PortDisconnectedEvent args)
{
if (args.Port != ReagentDispenserComponent.ChemMasterPort)
return;
component.ChemMaster = null;
component.ChemMasterInRange = false;
}
private void OnAnchorChanged(EntityUid uid, ReagentDispenserComponent component, ref AnchorStateChangedEvent args)
{
if (args.Anchored)
RecheckConnections(uid, component);
}
public void UpdateConnection(
EntityUid dispenser,
EntityUid chemMaster,
ReagentDispenserComponent? dispenserComp = null,
ChemMasterComponent? chemMasterComp = null)
{
if (!Resolve(dispenser, ref dispenserComp) || !Resolve(chemMaster, ref chemMasterComp))
return;
if (dispenserComp.ChemMaster.HasValue && dispenserComp.ChemMaster.Value != chemMaster &&
TryComp(dispenserComp.ChemMaster, out ChemMasterComponent? oldMaster))
{
oldMaster.ConnectedDispenser = null;
}
if (chemMasterComp.ConnectedDispenser.HasValue && chemMasterComp.ConnectedDispenser.Value != dispenser &&
TryComp(dispenserComp.ChemMaster, out ReagentDispenserComponent? oldDispenser))
{
oldDispenser.ChemMaster = null;
oldDispenser.ChemMasterInRange = false;
}
dispenserComp.ChemMaster = chemMaster;
chemMasterComp.ConnectedDispenser = dispenser;
RecheckConnections(dispenser, dispenserComp);
}
private void RecheckConnections(EntityUid dispenser, ReagentDispenserComponent? component = null)
{
if (!Resolve(dispenser, ref component))
return;
if (component.ChemMaster == null)
{
component.ChemMasterInRange = false;
return;
}
Transform(component.ChemMaster.Value).Coordinates
.TryDistance(EntityManager, Transform(dispenser).Coordinates, out var distance);
component.ChemMasterInRange = distance <= 1.5f;
}
// WD END
private void SubscribeUpdateUiState<T>(Entity<ReagentDispenserComponent> ent, ref T ev)
{
UpdateUiState(ent);
@@ -184,35 +83,39 @@ namespace Content.Server.Chemistry.EntitySystems
return null;
}
private List<ReagentId> GetInventory(Entity<ReagentDispenserComponent> ent)
private List<ReagentInventoryItem> GetInventory(Entity<ReagentDispenserComponent> reagentDispenser)
{
var reagentDispenser = ent.Comp;
var inventory = new List<ReagentId>();
var inventory = new List<ReagentInventoryItem>();
if (reagentDispenser.PackPrototypeId is not null
&& _prototypeManager.TryIndex(reagentDispenser.PackPrototypeId, out ReagentDispenserInventoryPrototype? packPrototype))
for (var i = 0; i < reagentDispenser.Comp.NumSlots; i++)
{
inventory.AddRange(packPrototype.Inventory.Select(x => new ReagentId(x, null)));
}
var storageSlotId = ReagentDispenserComponent.BaseStorageSlotId + i;
var storedContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser.Owner, storageSlotId);
if (HasComp<EmaggedComponent>(ent)
&& reagentDispenser.EmagPackPrototypeId is not null
&& _prototypeManager.TryIndex(reagentDispenser.EmagPackPrototypeId, out ReagentDispenserInventoryPrototype? emagPackPrototype))
{
inventory.AddRange(emagPackPrototype.Inventory.Select(x => new ReagentId(x, null)));
// 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;
// Get volume remaining and color of solution
FixedPoint2 quantity = 0f;
var reagentColor = Color.White;
if (storedContainer != null && _solutionContainerSystem.TryGetDrainableSolution(storedContainer.Value, out _, out var sol))
{
quantity = sol.Volume;
reagentColor = sol.GetColor(_prototypeManager);
}
inventory.Add(new ReagentInventoryItem(storageSlotId, reagentLabel, quantity, reagentColor));
}
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)
{
reagentDispenser.Comp.DispenseAmount = message.ReagentDispenserDispenseAmount;
@@ -223,33 +126,23 @@ namespace Content.Server.Chemistry.EntitySystems
private void OnDispenseReagentMessage(Entity<ReagentDispenserComponent> reagentDispenser, ref ReagentDispenserDispenseReagentMessage message)
{
// 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;
var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName);
if (outputContainer is not { Valid: true } || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution, out _))
{
// WD EDIT START
var chemMasterUid = reagentDispenser.Comp.ChemMaster;
if (!reagentDispenser.Comp.ChemMasterInRange ||
!TryComp(chemMasterUid, out ChemMasterComponent? chemMaster) ||
!TryComp(chemMasterUid, out SolutionContainerManagerComponent? solutionContainer) ||
!_solutionContainerSystem.TryGetSolution((chemMasterUid.Value, solutionContainer),
SharedChemMaster.BufferSolutionName, out var bufferSolution))
return;
bufferSolution.Value.Comp.Solution.AddReagent(message.ReagentId, FixedPoint2.New((int)reagentDispenser.Comp.DispenseAmount));
_chemMasterSystem.UpdateUiState((chemMasterUid.Value, chemMaster));
ClickSound(reagentDispenser);
return;
} // WD EDIT END
if (_solutionContainerSystem.TryAddReagent(solution.Value, message.ReagentId, (int) reagentDispenser.Comp.DispenseAmount, out var dispensedAmount)
&& message.Session.AttachedEntity is not null)
if (_solutionContainerSystem.TryGetDrainableSolution(storedContainer.Value, out var src, out _) &&
_solutionContainerSystem.TryGetRefillableSolution(outputContainer.Value, out var dst, out _))
{
_adminLogger.Add(LogType.ChemicalReaction, LogImpact.Medium,
$"{ToPrettyString(message.Session.AttachedEntity.Value):player} dispensed {dispensedAmount}u of {message.ReagentId} into {ToPrettyString(outputContainer.Value):entity}");
// force open container, if applicable, to avoid confusing people on why it doesn't dispense
_openable.SetOpen(storedContainer.Value, true);
_solutionTransferSystem.Transfer(reagentDispenser,
storedContainer.Value, src.Value,
outputContainer.Value, dst.Value,
(int)reagentDispenser.Comp.DispenseAmount);
}
UpdateUiState(reagentDispenser);
@@ -271,5 +164,41 @@ namespace Content.Server.Chemistry.EntitySystems
{
_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, SharedReagentDispenser.OutputSlotName, component.BeakerSlot);
}
}
}

View File

@@ -1,4 +1,4 @@
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
@@ -14,8 +14,7 @@ namespace Content.Shared.Chemistry.Dispenser
[Serializable, NetSerializable, Prototype("reagentDispenserInventory")]
public sealed partial class ReagentDispenserInventoryPrototype : IPrototype
{
// TODO use ReagentId
[DataField("inventory", customTypeSerializer: typeof(PrototypeIdListSerializer<ReagentPrototype>))]
[DataField("inventory", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
public List<string> Inventory = new();
[ViewVariables, IdDataField]

View File

@@ -1,67 +1,133 @@
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Serialization;
namespace Content.Shared.Chemistry;
/// <summary>
/// This class holds constants that are shared between client and server.
/// </summary>
public sealed class SharedReagentDispenser
namespace Content.Shared.Chemistry
{
public const string OutputSlotName = "beakerSlot";
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount amount)
: BoundUserInterfaceMessage
{
public readonly ReagentDispenserDispenseAmount ReagentDispenserDispenseAmount = amount;
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserDispenseReagentMessage(ReagentId reagentId) : BoundUserInterfaceMessage
{
public readonly ReagentId ReagentId = reagentId;
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserClearContainerSolutionMessage : BoundUserInterfaceMessage;
public enum ReagentDispenserDispenseAmount
{
U1 = 1,
U5 = 5,
U10 = 10,
U15 = 15,
U20 = 20,
U25 = 25,
U30 = 30,
U50 = 50,
U100 = 100,
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserBoundUserInterfaceState(
ContainerInfo? outputContainer,
NetEntity? outputContainerEntity,
List<ReagentId> inventory,
ReagentDispenserDispenseAmount selectedDispenseAmount)
: BoundUserInterfaceState
{
public readonly ContainerInfo? OutputContainer = outputContainer;
public readonly NetEntity? OutputContainerEntity = outputContainerEntity;
/// <summary>
/// A list of the reagents which this dispenser can dispense.
/// This class holds constants that are shared between client and server.
/// </summary>
public readonly List<ReagentId> Inventory = inventory;
public sealed class SharedReagentDispenser
{
public const string OutputSlotName = "beakerSlot";
}
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount = selectedDispenseAmount;
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserSetDispenseAmountMessage : BoundUserInterfaceMessage
{
public readonly ReagentDispenserDispenseAmount ReagentDispenserDispenseAmount;
[Serializable, NetSerializable]
public enum ReagentDispenserUiKey
{
Key
public ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount amount)
{
ReagentDispenserDispenseAmount = amount;
}
/// <summary>
/// Create a new instance from interpreting a String as an integer,
/// throwing an exception if it is unable to parse.
/// </summary>
public ReagentDispenserSetDispenseAmountMessage(String s)
{
switch (s)
{
case "1":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U1;
break;
case "5":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U5;
break;
case "10":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U10;
break;
case "15":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U15;
break;
case "20":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U20;
break;
case "25":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U25;
break;
case "30":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U30;
break;
case "50":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U50;
break;
case "100":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U100;
break;
default:
throw new Exception($"Cannot convert the string `{s}` into a valid ReagentDispenser DispenseAmount");
}
}
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserDispenseReagentMessage : BoundUserInterfaceMessage
{
public readonly string SlotId;
public ReagentDispenserDispenseReagentMessage(string slotId)
{
SlotId = slotId;
}
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserClearContainerSolutionMessage : BoundUserInterfaceMessage
{
}
public enum ReagentDispenserDispenseAmount
{
U1 = 1,
U5 = 5,
U10 = 10,
U15 = 15,
U20 = 20,
U25 = 25,
U30 = 30,
U50 = 50,
U100 = 100,
}
[Serializable, NetSerializable]
public sealed class ReagentInventoryItem(string storageSlotId, string reagentLabel, FixedPoint2 quantity, Color reagentColor)
{
public string StorageSlotId = storageSlotId;
public string ReagentLabel = reagentLabel;
public FixedPoint2 Quantity = quantity;
public Color ReagentColor = reagentColor;
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState
{
public readonly ContainerInfo? OutputContainer;
public readonly NetEntity? OutputContainerEntity;
/// <summary>
/// A list of the reagents which this dispenser can dispense.
/// </summary>
public readonly List<ReagentInventoryItem> Inventory;
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List<ReagentInventoryItem> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
{
OutputContainer = outputContainer;
OutputContainerEntity = outputContainerEntity;
Inventory = inventory;
SelectedDispenseAmount = selectedDispenseAmount;
}
}
[Serializable, NetSerializable]
public enum ReagentDispenserUiKey
{
Key
}
}

View File

@@ -12,14 +12,16 @@ namespace Content.Shared.Containers.ItemSlots
/// Used for entities that can hold items in different slots. Needed by ItemSlotSystem to support basic
/// insert/eject interactions.
/// </summary>
[RegisterComponent, Access(typeof(ItemSlotsSystem)), NetworkedComponent]
[RegisterComponent]
[Access(typeof(ItemSlotsSystem))]
[NetworkedComponent]
public sealed partial class ItemSlotsComponent : Component
{
/// <summary>
/// The dictionary that stores all of the item slots whose interactions will be managed by the <see
/// cref="ItemSlotsSystem"/>.
/// </summary>
[DataField(readOnly: true)]
[DataField("slots", readOnly:true)]
public Dictionary<string, ItemSlot> Slots = new();
// There are two ways to use item slots:
@@ -39,21 +41,26 @@ namespace Content.Shared.Containers.ItemSlots
}
[Serializable, NetSerializable]
public sealed class ItemSlotsComponentState(Dictionary<string, ItemSlot> slots) : ComponentState
public sealed class ItemSlotsComponentState : ComponentState
{
public readonly Dictionary<string, ItemSlot> Slots = slots;
public readonly Dictionary<string, ItemSlot> Slots;
public ItemSlotsComponentState(Dictionary<string, ItemSlot> slots)
{
Slots = slots;
}
}
/// <summary>
/// This is effectively a wrapper for a ContainerSlot that adds content functionality like entity whitelists and
/// insert/eject sounds.
/// </summary>
[DataDefinition, Access(typeof(ItemSlotsSystem)), Serializable, NetSerializable]
[DataDefinition]
[Access(typeof(ItemSlotsSystem))]
[Serializable, NetSerializable]
public sealed partial class ItemSlot
{
public ItemSlot()
{
}
public ItemSlot() { }
public ItemSlot(ItemSlot other)
{
@@ -61,6 +68,7 @@ namespace Content.Shared.Containers.ItemSlots
}
[DataField]
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
public EntityWhitelist? Whitelist;
[DataField]
@@ -79,8 +87,8 @@ namespace Content.Shared.Containers.ItemSlots
/// This will be passed through Loc.GetString. If the name is an empty string, then verbs will use the name
/// of the currently held or currently inserted entity instead.
/// </remarks>
[DataField(readOnly: true), Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
// FIXME Friends
[DataField(readOnly: true)]
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)] // FIXME Friends
public string Name = string.Empty;
/// <summary>
@@ -91,9 +99,9 @@ namespace Content.Shared.Containers.ItemSlots
/// property of that component (e.g., cell slot size category), and this can lead to unnecessary changes
/// when mapping.
/// </remarks>
[DataField(readOnly: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>)),
Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute), NonSerialized]
// FIXME Friends
[DataField(readOnly: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)] // FIXME Friends
[NonSerialized]
public string? StartingItem;
/// <summary>
@@ -103,8 +111,9 @@ namespace Content.Shared.Containers.ItemSlots
/// This doesn't have to mean the slot is somehow physically locked. In the case of the item cabinet, the
/// cabinet may simply be closed at the moment and needs to be opened first.
/// </remarks>
[DataField(readOnly: true), ViewVariables(VVAccess.ReadWrite)]
public bool Locked;
[DataField(readOnly: true)]
[ViewVariables(VVAccess.ReadWrite)]
public bool Locked = false;
/// <summary>
/// Prevents adding the eject alt-verb, but still lets you swap items.
@@ -113,7 +122,7 @@ namespace Content.Shared.Containers.ItemSlots
/// This does not affect EjectOnInteract, since if you do that you probably want ejecting to work.
/// </remarks>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool DisableEject;
public bool DisableEject = false;
/// <summary>
/// Whether the item slots system will attempt to insert item from the user's hands into this slot when interacted with.
@@ -131,7 +140,7 @@ namespace Content.Shared.Containers.ItemSlots
/// contents when clicked on normally.
/// </remarks>
[DataField]
public bool EjectOnInteract;
public bool EjectOnInteract = false;
/// <summary>
/// If true, and if this slot is attached to an item, then it will attempt to eject slot when to the slot is
@@ -143,7 +152,7 @@ namespace Content.Shared.Containers.ItemSlots
/// menu, nor will it disable alt-click interactions.
/// </remarks>
[DataField]
public bool EjectOnUse;
public bool EjectOnUse = false;
/// <summary>
/// Override the insert verb text. Defaults to using the slot's name (if specified) or the name of the
@@ -160,7 +169,7 @@ namespace Content.Shared.Containers.ItemSlots
public string? EjectVerbText;
[ViewVariables, NonSerialized]
public ContainerSlot? ContainerSlot;
public ContainerSlot? ContainerSlot = default!;
/// <summary>
/// If this slot belongs to some de-constructible component, should the item inside the slot be ejected upon
@@ -169,15 +178,19 @@ namespace Content.Shared.Containers.ItemSlots
/// <remarks>
/// The actual deconstruction logic is handled by the server-side EmptyOnMachineDeconstructSystem.
/// </remarks>
[DataField, NonSerialized]
[DataField]
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
[NonSerialized]
public bool EjectOnDeconstruct = true;
/// <summary>
/// If this slot belongs to some breakable or destructible entity, should the item inside the slot be
/// ejected when it is broken or destroyed?
/// </summary>
[DataField, NonSerialized]
public bool EjectOnBreak;
[DataField]
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
[NonSerialized]
public bool EjectOnBreak = false;
/// <summary>
/// When specified, a popup will be generated whenever someone attempts to insert a bad item into this slot.
@@ -207,23 +220,20 @@ namespace Content.Shared.Containers.ItemSlots
/// want to insert more than one item that matches the same whitelist.
/// </remarks>
[DataField]
[Access(typeof(ItemSlotsSystem), Other = AccessPermissions.ReadWriteExecute)]
public bool Swap = true;
public string? ID => ContainerSlot?.ID;
// Convenience properties
public bool HasItem => ContainerSlot?.ContainedEntity != null;
public EntityUid? Item => ContainerSlot?.ContainedEntity;
/// <summary>
/// Priority for use with the eject & insert verbs for this slot.
/// </summary>
[DataField]
public int Priority;
[DataField("maxStackAmount")] // WD
public int MaxStackAmount;
public int Priority = 0;
/// <summary>
/// If false, errors when adding an item slot with a duplicate key are suppressed. Local==true implies that
@@ -232,6 +242,9 @@ namespace Content.Shared.Containers.ItemSlots
[NonSerialized]
public bool Local = true;
[DataField] // WD
public int MaxStackAmount;
public void CopyFrom(ItemSlot other)
{
// These fields are mutable reference types. But they generally don't get modified, so this should be fine.
@@ -247,10 +260,10 @@ namespace Content.Shared.Containers.ItemSlots
InsertVerbText = other.InsertVerbText;
EjectVerbText = other.EjectVerbText;
WhitelistFailPopup = other.WhitelistFailPopup;
LockedFailPopup = other.LockedFailPopup;
InsertSuccessPopup = other.InsertSuccessPopup;
Swap = other.Swap;
Priority = other.Priority;
MaxStackAmount = other.MaxStackAmount;
}
}
@@ -258,21 +271,11 @@ namespace Content.Shared.Containers.ItemSlots
/// Event raised on the slot entity and the item being inserted to determine if an item can be inserted into an item slot.
/// </summary>
[ByRefEvent]
public record struct ItemSlotInsertAttemptEvent(
EntityUid SlotEntity,
EntityUid Item,
EntityUid? User,
ItemSlot Slot,
bool Cancelled = false);
public record struct ItemSlotInsertAttemptEvent(EntityUid SlotEntity, EntityUid Item, EntityUid? User, ItemSlot Slot, bool Cancelled = false);
/// <summary>
/// Event raised on the slot entity and the item being inserted to determine if an item can be ejected from an item slot.
/// </summary>
[ByRefEvent]
public record struct ItemSlotEjectAttemptEvent(
EntityUid SlotEntity,
EntityUid Item,
EntityUid? User,
ItemSlot Slot,
bool Cancelled = false);
public record struct ItemSlotEjectAttemptEvent(EntityUid SlotEntity, EntityUid Item, EntityUid? User, ItemSlot Slot, bool Cancelled = false);
}

View File

@@ -0,0 +1,2 @@
reagent-name-tranquility = tranquility
reagent-desc-tranquility = Emits a strange aura of tranquility...

View File

@@ -10,9 +10,9 @@ reagent-dispenser-bound-user-interface-title = Reagent dispenser
## UI
reagent-dispenser-window-amount-to-dispense-label = Amount
reagent-dispenser-window-container-label = Container:
reagent-dispenser-window-clear-button = Clear
reagent-dispenser-window-eject-button = Eject
reagent-dispenser-window-eject-container-button = ⏏
reagent-dispenser-window-no-container-loaded-text = No container loaded.
reagent-dispenser-window-reagent-name-not-found-text = Reagent name not found
reagent-dispenser-window-unknown-reagent-text = Unknown reagent

View File

@@ -0,0 +1,48 @@
ent-ChemicalCartridge = химический картридж
.desc = Используется для хранения огромного количества химикатов. Используется в химических раздатчиках
ent-ChemicalCartridgeCarbon = химический картридж (углерод)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeIodine = химический картридж (йод)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeFluorine = химический картридж (фтор)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeChlorine = химический картридж (хлор)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeAluminium = химический картридж (алюминий)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgePhosphorus = химический картридж (фосфор)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeSulfur = химический картридж (сера)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeSilicon = химический картридж (кремний)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeHydrogen = химический картридж (водород)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeLithium = химический картридж (литий)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeSodium = химический картридж (натрий)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgePotassium = химический картридж (калий)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeRadium = химический картридж (радий)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeIron = химический картридж (железо)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeCopper = химический картридж (медь)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeGold = химический картридж (золото)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeSugar = химический картридж (сахар)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeMercury = химический картридж (ртуть)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeSilver = химический картридж (серебро)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeEthanol = химический картридж (этанол)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeSugar = химический картридж (сахар)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeNitrogen = химический картридж (азот)
.desc = { ent-ChemicalCartridge.desc }
ent-ChemicalCartridgeOxygen = химический картридж (кислород)
.desc = { ent-ChemicalCartridge.desc }

View File

@@ -1 +1,4 @@
reagent-popup-tranquility = Вы чувствуете себя странно спокойными...
reagent-name-tranquility = спокойствие
reagent-desc-tranquility = Источает странную ауру спокойствия...

View File

@@ -1,4 +0,0 @@
reagent-name-potassium-iodide = Йодид калия
reagent-desc-potassium-iodide = Снижает поражающее действие радиации на 90%. Только для профилактического применения.
reagent-name-haloperidol = Галоперидол
reagent-desc-haloperidol = Выводит большинство стимулирующих/галлюциногенных препаратов. Уменьшает наркотические эффекты и нервозность. Вызывает сонливость.

View File

@@ -2,41 +2,32 @@ ent-EnergyShield = энергетический щит
.desc = Экзотический энергетический щит в сложенном виде может поместиться даже в кармане.
ent-BrokenEnergyShield = сломанный энергетический щит
.desc = Что-то внутри сгорело, оно больше не работает.
ent-Jug = кувшин
.desc = Используется для содержания очень большого количества химикатов или растворов. Пыхтение крайне опрометчиво.
ent-JugCarbon = кувшин (углерод)
.desc = { ent-Jug.desc }
ent-JugIodine = кувшин (йод)
.desc = { ent-Jug.desc }
ent-JugFluorine = кувшин (фтор)
.desc = { ent-Jug.desc }
ent-JugChlorine = кувшин (хлор)
.desc = { ent-Jug.desc }
ent-JugAluminium = кувшин (алюминий)
.desc = { ent-Jug.desc }
ent-JugPhosphorus = кувшин (фосфор)
.desc = { ent-Jug.desc }
ent-JugSulfur = кувшин (сера)
.desc = { ent-Jug.desc }
ent-JugSilicon = кувшин (кремний)
.desc = { ent-Jug.desc }
ent-JugHydrogen = кувшин (водород)
.desc = { ent-Jug.desc }
ent-JugLithium = кувшин (литий)
.desc = { ent-Jug.desc }
ent-JugSodium = кувшин (натрий)
.desc = { ent-Jug.desc }
ent-JugPotassium = кувшин (калий)
.desc = { ent-Jug.desc }
ent-JugRadium = кувшин (радий)
.desc = { ent-Jug.desc }
ent-JugIron = кувшин (железо)
.desc = { ent-Jug.desc }
ent-JugCopper = кувшин (медь)
.desc = { ent-Jug.desc }
ent-JugGold = кувшин (золото)
.desc = { ent-Jug.desc }
ent-JugSugar = кувшин (сахар)
.desc = { ent-Jug.desc }
ent-JugWeldingFuel = кувшин (сварочное топливо)
.desc = { ent-Jug.desc }
ent-CognizineChemistryBottle = бутылка когнизина
.desc = { ent-BaseChemistryEmptyBottle.desc }
ent-ToxinChemistryBottle = бутылка с токсином
.desc = { ent-BaseChemistryEmptyBottle.desc }
ent-BaseBeakerMetallic = ""
.desc = ""
ent-CryoxadoneBeakerSmall = стакан криоксадона
.desc = Заполнен реагентом, используемым в криогенных пробирках.
ent-SyringeBluespace = блюспейс шприц
.desc = Внедрение передовой технологии bluespace.
ent-SyndicateSponge = куб обезьяны
.desc = Просто добавь воды!
ent-WatermelonSeeds = пакет арбузных семечек
.desc = { ent-SeedBase.desc }
ent-GrapeSeeds = пакет виноградных косточек
.desc = { ent-SeedBase.desc }
ent-MopBucketFull = Ведро для мытья пола
.desc = { ent-MopBucket.desc }
ent-WetFloorSignMineExplosive = табличка 'Мокрый пол'
.desc = Осторожность! Мокрый пол!
ent-Plunger = вантуз
.desc = Вантуз с красной пластиковой присоской и деревянной ручкой. Используется для прочистки стоков.
ent-MegaSprayBottle = мега распылитель
.desc = Огромный распылитель, способный на непревзойденную уборочную мощь.
ent-BigVapor = ""
.desc = ""
ent-MechEquipmentGrabberSmall = небольшой гидравлический зажим
.desc = Дает меху возможность хватать предметы и перетаскивать их.

View File

@@ -1,40 +0,0 @@
ent-JugMercury = кувшин (ртуть)
.desc = { ent-Jug.desc }
ent-JugSilver = кувшин (серебро)
.desc = { ent-Jug.desc }
ent-JugEthanol = кувшин (этанол)
.desc = { ent-Jug.desc }
ent-JugSugar = jug (sugar)
.desc = { ent-Jug.desc }
ent-JugNitrogen = кувшин (азот)
.desc = { ent-Jug.desc }
ent-JugOxygen = кувшин (кислород)
.desc = { ent-Jug.desc }
ent-CognizineChemistryBottle = бутылка когнизина
.desc = { ent-BaseChemistryEmptyBottle.desc }
ent-ToxinChemistryBottle = бутылка с токсином
.desc = { ent-BaseChemistryEmptyBottle.desc }
ent-BaseBeakerMetallic = ""
.desc = ""
ent-CryoxadoneBeakerSmall = стакан криоксадона
.desc = Заполнен реагентом, используемым в криогенных пробирках.
ent-SyringeBluespace = блюспейс шприц
.desc = Внедрение передовой технологии bluespace.
ent-SyndicateSponge = куб обезьяны
.desc = Просто добавь воды!
ent-WatermelonSeeds = пакет арбузных семечек
.desc = { ent-SeedBase.desc }
ent-GrapeSeeds = пакет виноградных косточек
.desc = { ent-SeedBase.desc }
ent-MopBucketFull = Ведро для мытья пола
.desc = { ent-MopBucket.desc }
ent-WetFloorSignMineExplosive = табличка 'Мокрый пол'
.desc = Осторожность! Мокрый пол!
ent-Plunger = вантуз
.desc = Вантуз с красной пластиковой присоской и деревянной ручкой. Используется для прочистки стоков.
ent-MegaSprayBottle = мега распылитель
.desc = Огромный распылитель, способный на непревзойденную уборочную мощь.
ent-BigVapor = ""
.desc = ""
ent-MechEquipmentGrabberSmall = небольшой гидравлический зажим
.desc = Дает меху возможность хватать предметы и перетаскивать их.

View File

@@ -26,8 +26,8 @@ ent-CrystalBlue = синий кристалл
.desc = Это блестящий синий кристалл.
ent-CrystalCyan = голубой кристалл
.desc = Это блестящий голубой кристалл.
ent-ChemDispenser = дозатор химикатов
.desc = Дозатор химикатов промышленного класса с большим запасом химикатов.
ent-ChemDispenser = раздатчик химикатов
.desc = Раздатчик химикатов промышленного класса с большим запасом химикатов.
ent-AirlockExternalCargoLocked = { ent-AirlockExternal }
.desc = { ent-AirlockExternal.desc }
.suffix = Внешний, Карго, Закрыт

View File

@@ -0,0 +1,50 @@
ent-Jug = кувшин
.desc = Используется для содержания очень большого количества химикатов или растворов. Пыхтение крайне опрометчиво.
ent-JugCarbon = кувшин (углерод)
.desc = { ent-Jug.desc }
ent-JugIodine = кувшин (йод)
.desc = { ent-Jug.desc }
ent-JugFluorine = кувшин (фтор)
.desc = { ent-Jug.desc }
ent-JugChlorine = кувшин (хлор)
.desc = { ent-Jug.desc }
ent-JugAluminium = кувшин (алюминий)
.desc = { ent-Jug.desc }
ent-JugPhosphorus = кувшин (фосфор)
.desc = { ent-Jug.desc }
ent-JugSulfur = кувшин (сера)
.desc = { ent-Jug.desc }
ent-JugSilicon = кувшин (кремний)
.desc = { ent-Jug.desc }
ent-JugHydrogen = кувшин (водород)
.desc = { ent-Jug.desc }
ent-JugLithium = кувшин (литий)
.desc = { ent-Jug.desc }
ent-JugSodium = кувшин (натрий)
.desc = { ent-Jug.desc }
ent-JugPotassium = кувшин (калий)
.desc = { ent-Jug.desc }
ent-JugRadium = кувшин (радий)
.desc = { ent-Jug.desc }
ent-JugIron = кувшин (железо)
.desc = { ent-Jug.desc }
ent-JugCopper = кувшин (медь)
.desc = { ent-Jug.desc }
ent-JugGold = кувшин (золото)
.desc = { ent-Jug.desc }
ent-JugSugar = кувшин (сахар)
.desc = { ent-Jug.desc }
ent-JugWeldingFuel = кувшин (сварочное топливо)
.desc = { ent-Jug.desc }
ent-JugMercury = кувшин (ртуть)
.desc = { ent-Jug.desc }
ent-JugSilver = кувшин (серебро)
.desc = { ent-Jug.desc }
ent-JugEthanol = кувшин (этанол)
.desc = { ent-Jug.desc }
ent-JugSugar = кувшин (сахар)
.desc = { ent-Jug.desc }
ent-JugNitrogen = кувшин (азот)
.desc = { ent-Jug.desc }
ent-JugOxygen = кувшин (кислород)
.desc = { ent-Jug.desc }

View File

@@ -7,9 +7,15 @@ reagent-desc-insect-blood = Окей, это уже реально мерзко.
reagent-name-slime = слизь
reagent-desc-slime = Сначала вам показалось, что это градиент крови, но вы ошиблись.
reagent-name-sap = живица
reagent-desc-sap = Липкая, сладкая кровь деревьев.
reagent-name-hemocyanin-blood = синяя кровь
reagent-desc-hemocyanin-blood = Содержит медь, а не железо, что придаёт ей ярко выраженный голубой цвет.
reagent-name-ammonia-blood = анаэробная кровь
reagent-desc-ammonia-blood = Ничто во всей вселенной не пахнет так ужасно.
reagent-name-zombie-blood = кровь зомби
reagent-desc-zombie-blood = Не рекомендуется употреблять в пищу. Может быть использована для создания вакцины от инфекции.
@@ -21,3 +27,6 @@ reagent-desc-fat = Независимо от того, как он был пол
reagent-name-vomit = рвота
reagent-desc-vomit = Вы можете увидеть в ней несколько кусков чьей-то последней еды.
reagent-name-grey-matter = серое вещество
reagent-desc-grey-matter = Сок мыслей, вытекающий из ваших ушей.

View File

@@ -6,3 +6,22 @@ reagent-name-sodium-carbonate = карбонат натрия
reagent-desc-sodium-carbonate = Белая водорастворимая соль без запаха, которая образует щелочной раствор в воде. Также известен как кальцинированная сода.
reagent-name-artifexium = артистизм
reagent-desc-artifexium = Лавандовая смесь микроскопических фрагментов артефакта и сильной кислоты. Обладает способностью активировать артефакты..
reagent-name-benzene = бензол
reagent-desc-benzene = Ароматическое, слегка канцерогенное углеродное кольцо, образующее основу для многих органических соединений.
reagent-name-hydroxide = гидроксид
reagent-desc-hydroxide = Сильнощелочное химическое вещество, образующее основу для многих органических соединений.
reagent-name-sodium-hydroxide = гидроксид натрия
reagent-desc-sodium-hydroxide = Белая водорастворимая соль без запаха, образующая в воде сильный щелочной раствор. При проглатывании вызывает ожоги и рвоту.
reagent-name-fersilicite = ферсилицит
reagent-desc-fersilicite = Интерметаллическое соединение с необычными магнитными свойствами при низких температурах.
reagent-name-sodium-polyacrylate = полиакрилат натрия
reagent-desc-sodium-polyacrylate = Супервпитывающий полимер, имеющий разнообразное промышленное применение.
reagent-name-cellulose = целлюлозные волокна
reagent-desc-cellulose = Кристаллический полимер полидекстрозы. Растения любят этот материал.

View File

@@ -30,8 +30,8 @@ reagent-name-nothing = ничего
reagent-desc-nothing = Абсолютно ничего.
reagent-name-nuclear-cola = ядерная кола
reagent-desc-nuclear-cola = Кола, кола никогда не меняется.
reagent-name-soda-water = содовая
reagent-desc-soda-water = Газированная вода. Почему бы не сделать виски с содовой?
reagent-name-soda-water = газировка
reagent-desc-soda-water = Газированная вода. Почему бы не сделать виски с газировкой?
reagent-name-soy-latte = соевый латте
reagent-desc-soy-latte = Кофейный напиток, приготовленный из эспрессо и подогретого соевого молока.
reagent-name-tea = чай

View File

@@ -14,6 +14,10 @@ reagent-name-ketchup = кетчуп
reagent-desc-ketchup = Приготовлен из томатного пюре с добавлением специяй.
reagent-name-ketchunaise = кетчюнез
reagent-desc-ketchunaise = Так называемый русский соус, популярный среди космонавтов.
reagent-name-laughin-syrup = Ржачный сироп
reagent-desc-laughin-syrup = Сок Ржачных Бобов. Шипучий, и меняет вкус в зависимости от того, с чем его едят!
reagent-name-mayo = майонез
reagent-desc-mayo = Соус, сделанный из масла, яйца и немного (съедобной) кислоты.
reagent-name-vinaigrette = винегрет
@@ -22,3 +26,9 @@ reagent-name-soysauce = соевый соус
reagent-desc-soysauce = Соленая приправа на основе сои.
reagent-name-table-salt = столовая соль
reagent-desc-table-salt = Хлорид натрия, широко известный как соль, часто используется в качестве пищевой приправы или для мгновенного уничтожения мозговых червей.
reagent-name-mustard = горчица
reagent-desc-mustard = Желтая горчица, изготовленная из семян горчичного растения.
reagent-name-syrup = сироп
reagent-desc-syrup = Вкусный сироп из древесного сока, более липкий, чем клей.

View File

@@ -6,3 +6,12 @@ reagent-name-vitamin = витамины
reagent-desc-vitamin = Содержатся в здоровом, полноценном питании.
reagent-name-protein = протеины
reagent-desc-protein = Также известные как белки. Содержатся в некоторых блюдах, полезны для здоровья организма.
reagent-name-cocoapowder = какао порошок
reagent-desc-cocoapowder = Из лучших сортов какао-бобов
reagent-name-butter = масло
reagent-desc-butter = Вы можете ему верить!
reagent-name-pumpkin-flesh = тыквенная мякоть
reagent-desc-pumpkin-flesh = Мягкий, сладкий плод тыквы.

View File

@@ -6,8 +6,12 @@ reagent-name-oats = овёс
reagent-desc-oats = Используется для различных вкусных целей.
reagent-name-enzyme = универсальный фермент
reagent-desc-enzyme = Используется в приготовлении различных блюд.
reagent-name-egg = яйцо
reagent-desc-egg = Используется в выпечке.
reagent-name-egg = приготовленное яйцо
reagent-desc-egg = Вареный куриный эмбрион. Очень вкусно!
reagent-name-raw-egg = сырое яйцо
reagent-desc-raw-egg = используется в готовке.
reagent-name-sugar = сахар
reagent-desc-sugar = Вкусный космический сахар!
reagent-name-blackpepper = чёрный перец

View File

@@ -10,3 +10,12 @@ reagent-name-saxoite = саксонит
reagent-desc-saxoite = Отдаёт джазом.
reagent-name-licoxide = ликоксид
reagent-desc-licoxide = Это выглядит... электризующе.
reagent-name-fresium = Фрезиум
reagent-desc-fresium = Загадочное соединение, замедляющее вибрацию атомов и молекул... каким-то образом. По-простому, от него становится холодно... ОЧЕНЬ холодно. При проглатывании может вызвать длительные проблемы с передвижением.
reagent-name-weh = Сок, заставляющий вас Weh!
reagent-desc-weh = Чистая эссенция игрушки ящера. Заставляет вас Weh!
reagent-name-razorium = разориум
reagent-desc-razorium = Странное неньютоновское химическое вещество. Образуется при объединении двух лекарств от физических повреждений. При попадании в организм образует миллионы крошечных острых лезвий. Очень острых.

View File

@@ -52,6 +52,9 @@ reagent-desc-barozine = Сильнодействующий химикат, пр
reagent-name-phalanximine = фалангимин
reagent-desc-phalanximine = Современный препарат, используемый при лечении рака. Вызывает умеренное лучевое поражение организма и тошноту. Потенциально может удалить ген смерти у растений.
reagent-name-polypyrylium-oligomers = Полипирилиевые олигомеры
reagent-desc-polypyrylium-oligomers = Пурпурная смесь коротких полиэлектролитных цепей, не синтезируемых в лаборатории. Лечат удушье и физические травмы. Со временем останавливает кровотечение.
reagent-name-ambuzol = амбузол
reagent-desc-ambuzol = Высокотехнологичный препарат, способный остановить развитие зомби-вируса.
@@ -138,3 +141,15 @@ reagent-desc-silversulfadiazine = Это соединение, обладающ
reagent-name-stypticpowder = кровоостанавливающая пудра
reagent-desc-stypticpowder = Кровоостанавливающий порошок из сульфата алюминия помогает остановить кровотечение и способствует заживлению телесных повреждений.
reagent-name-mannitol = маннитол
reagent-desc-mannitol = Устраняет повреждения мозга.
reagent-name-psicodine = псикодин
reagent-desc-psicodine = Подавляет тревогу и прочие формы ментальных проблем. Передозировка вызывает галлюцинации и интоксикацию.
reagent-name-potassium-iodide = йодистый калий
reagent-desc-potassium-iodide = Снижает поражающее действие от радиации на 90%. Только профилактическое применение.
reagent-name-haloperidol = галоперидол
reagent-desc-haloperidol = Выводит из организма большую часть стимулирующих или галлюцигенных химикатов. Вызывает сонливость.

View File

@@ -10,7 +10,11 @@ reagent-name-thc = ТГК
reagent-desc-thc = Он же тетрагидроканнабинол. Основное психоактивное вещество в конопле.
reagent-name-thc-oil = масло ТГК
reagent-desc-thc-oil = Чистое масло ТГК, полученное из листьев конопли. Оно намного сильнее, чем в натуральной форме, и может использоваться для снятия хронической боли у пациентов.
reagent-name-nicotine = никотин
reagent-name-bananadine = бананадин
reagent-desc-bananadine = Слабый психоделик, содержащийся в небольших в шкурках от бананов.
reagent-name-nicotine = никотинколичествах
reagent-desc-nicotine = Опасен и вызывает сильное привыкание.
reagent-name-impedrezene = импедризин
reagent-desc-impedrezene = Наркотик, который лишает человека дееспособности, замедляя высшие функции клеток мозга. Вызывает обширные повреждения мозга.
@@ -22,3 +26,10 @@ reagent-name-mute-toxin = токсин немоты
reagent-desc-mute-toxin = Лишает вас возможности разговаривать пока в организме.
reagent-name-norepinephric-acid = норэпинефриновая кислота
reagent-desc-norepinephric-acid = Лишает вас возможности видеть пока усваивается организмом.
reagent-name-tear-gas = слезоточивый газ
reagent-desc-tear-gas = Химическое вещество, вызывающее сильное раздражение и слезы, обычно используемое при борьбе с толпой.
reagent-name-happiness = счастье
reagent-desc-happiness = Наполняет экстатическим оцепенением и вызывает незначительные травмы мозга. Вызывает привыкание крайне быстро. Передозировка вызывает резкие перепады настроения.

View File

@@ -13,6 +13,9 @@ reagent-desc-polytrinic-acid = Чрезвычайно едкое химичес
reagent-name-chloral-hydrate = хлоралгидрат
reagent-desc-chloral-hydrate = Успокаивающее и гипнотическое химическое вещество. Обычно используется для усыпления других людей, независимо от того, хотят они этого или нет.
reagent-name-gastrotoxin = гастротоксин
reagent-desc-gastrotoxin = Токсичный побочный продукт разложения. Чаще всего встречается в просроченых продуктах.
reagent-name-ferrochromic-acid = феррохромовая кислота
reagent-desc-ferrochromic-acid = Слабоагрессивный раствор, не способный вызвать серьезную опасность, если только его не выпить.
@@ -72,3 +75,6 @@ reagent-desc-vestine = Вызывает негативную реакцию в
reagent-name-tazinide = тазинид
reagent-desc-tazinide = Очень опасная металлическая смесь, которая может нарушить возможность передвигаться благодаря электризующему воздействию.
reagent-name-lipolicide = липолицид
reagent-desc-lipolicide = Мощный токсин, который разрушает жировые клетки, значительно снижая массу тела за короткое время. Смертельно для тех, у кого нет питательных веществ в организме.

View File

@@ -31,3 +31,10 @@ ent-CrateEmergencyAdvancedKit = Продвинутый аварийный наб
ent-CrateEmergencyRadiationKit = Аварийный набор выведения радиации
.desc = Ящик, содержащий 4 набора для выведения радиации.
.suffix = { "" }
ent-CrateChemistryP = ящик химикатов (P)
.desc = Содержит химикаты из P-блока периодической таблицы элементов.
ent-CrateChemistryS = ящик химикатов (S)
.desc = Содержит химикаты из S-блока периодической таблицы элементов.
ent-CrateChemistryD = ящик химикатов (D)
.desc = Содержит химикаты из D-блока периодической таблицы элементов.

View File

@@ -71,7 +71,7 @@ ent-DrinkBooger = козявка
.desc = Фууу...
.suffix = { "" }
ent-DrinkBraveBullGlass = бокал храброго быка
.desc = Текилла и кофейный ликер, объединенные в аппетитный микс. Выпьем.
.desc = Текила и кофейный ликер, объединенные в аппетитный микс. Выпьем.
.suffix = { "" }
ent-DrinkCarrotJuice = морковный сок
.desc = Как морковь, но не хрустит.
@@ -394,3 +394,7 @@ ent-DrinkGlassCoupeShaped = бокал
ent-DrinkFlaskBar = металлическая фляжка
.desc = Металлическая фляжка, часто выдаваемая барменом взаймы. Не забудьте вернуть ее!
.suffix = { "" }
ent-DrinkIcedTeaJug = бидон холодного чая
.desc = Для тех, кто считает обычный чай слишком "горячим". Слабаки.
ent-DrinkSugarJug = кувшин сахара
.desc = Некоторые люди кладут его в свое кофе. Отвратительно!

View File

@@ -32,7 +32,7 @@ ent-DrinkMelonLiquorBottleFull = дынный ликёр Эмеральдин
.desc = Бутылка 23-градусного Дынного ликёра Эмеральдин. Сладкий и легкий.
.suffix = { "" }
ent-DrinkPatronBottleFull = бутылка покровителя в художественной обёртке
.desc = Текилла с привкусом серебра, которую подают в ночных клубах по всей галактике.
.desc = Текила с привкусом серебра, которую подают в ночных клубах по всей галактике.
.suffix = { "" }
ent-DrinkPoisonWinebottleFull = бутылка колдовского бархата
.desc = Какая восхитительная упаковка для несомненно высококачественного вина! Урожай, должно быть, потрясающий!

View File

@@ -114,7 +114,7 @@
sprite: Objects/Specific/Service/vending_machine_restock.rsi
state: base
product: CrateVendingMachineRestockChemVendFilled
cost: 3820
cost: 4000
category: cargoproduct-category-name-medical
group: market

View File

@@ -1,57 +1,43 @@
- type: reagentDispenserInventory
id: SodaDispenserInventory
inventory:
- CoconutWater
- Coffee
- Cola
- Cream
- DrGibb
- GreenTea
- Ice
- JuiceLime
- JuiceOrange
- LemonLime
- RootBeer
- SodaWater
- SpaceMountainWind
- SpaceUp
- Sugar
- Tea
- TonicWater
- JuiceWatermelon
- DrinkIceJug
- DrinkCoffeeJug
- DrinkCreamCartonXL
- DrinkTeaJug
- DrinkGreenTeaJug
- DrinkIcedTeaJug
- DrinkColaBottleFull
- DrinkSpaceMountainWindBottleFull
- DrinkDrGibbJug
- DrinkRootBeerJug
- DrinkSpaceUpBottleFull
- DrinkTonicWaterBottleFull
- DrinkSodaWaterBottleFull
- DrinkLemonLimeJug
- DrinkSugarJug
- DrinkJuiceOrangeCartonXL
- DrinkJuiceLimeCartonXL
- DrinkWaterMelonJuiceJug
- type: reagentDispenserInventory
id: BoozeDispenserInventory
inventory:
- Beer
- CoffeeLiqueur
- Whiskey
- Wine
- Vodka
- Gin
- Rum
- Tequila
- Vermouth
- Cognac
- Ale
- Mead
###Hacked
#- Goldschlager
#- Patron
#- JuiceWatermelon
#- JuiceBerry
- type: reagentDispenserInventory
id: SodaDispenserEmagInventory
inventory:
- FourteenLoko
- Ephedrine
- Histamine
- type: reagentDispenserInventory
id: BoozeDispenserEmagInventory
inventory:
- AtomicBomb
- Ethanol
- Iron
- DrinkLemonLimeJug
- DrinkSugarJug
- DrinkJuiceOrangeCartonXL
- DrinkJuiceLimeCartonXL
- DrinkTonicWaterBottleFull
- DrinkSodaWaterBottleFull
- DrinkBeerGrowler
- DrinkCoffeeLiqueurBottleFull
- DrinkWhiskeyBottleFull
- DrinkWineBottleFull
- DrinkVodkaBottleFull
- DrinkGinBottleFull
- DrinkRumBottleFull
- DrinkTequilaBottleFull
- DrinkVermouthBottleFull
- DrinkCognacBottleFull
- DrinkAleBottleFullGrowler
- DrinkMeadJug

View File

@@ -1,31 +1,26 @@
- type: reagentDispenserInventory
id: ChemDispenserStandardInventory
inventory:
- Aluminium
- Carbon
- Chlorine
- Copper
- Ethanol
- Fluorine
- Sugar
- Hydrogen
- Iodine
- Iron
- Lithium
- Mercury
- Nitrogen
- Oxygen
- Phosphorus
- Potassium
- Radium
- Silicon
- Sodium
- Sulfur
- ChemicalCartridgeAluminium
- ChemicalCartridgeCarbon
- ChemicalCartridgeChlorine
- ChemicalCartridgeCopper
- ChemicalCartridgeEthanol
- ChemicalCartridgeFluorine
- ChemicalCartridgeSugar
- ChemicalCartridgeHydrogen
- ChemicalCartridgeIodine
- ChemicalCartridgeIron
- ChemicalCartridgeLithium
- ChemicalCartridgeMercury
- ChemicalCartridgeNitrogen
- ChemicalCartridgeOxygen
- ChemicalCartridgePhosphorus
- ChemicalCartridgePotassium
- ChemicalCartridgeRadium
- ChemicalCartridgeSilicon
- ChemicalCartridgeSodium
- ChemicalCartridgeSulfur
- type: reagentDispenserInventory
id: ChemDispenserEmaggedInventory
inventory: ##Feel free to change this to something more interesting when more chems are added
- Napalm
- Toxin
- Epinephrine
- Ultravasculine
id: EmptyInventory

View File

@@ -1,27 +1,28 @@
- type: vendingMachineInventory
id: ChemVendInventory
startingInventory:
Jug: 2
JugAluminium: 1
JugCarbon: 1
JugChlorine: 1
JugCopper: 1
JugEthanol: 1
JugFluorine: 1
JugHydrogen: 1
JugIodine: 1
JugIron: 1
JugLithium: 1
JugMercury: 1
JugNitrogen: 1
JugOxygen: 1
JugPhosphorus: 1
JugPotassium: 1
JugRadium: 1
JugSilicon: 1
JugSodium: 1
JugSugar: 1
JugSulfur: 1
Jug: 8
ChemicalCartridge: 2
ChemicalCartridgeAluminium: 1
ChemicalCartridgeCarbon: 1
ChemicalCartridgeChlorine: 1
ChemicalCartridgeCopper: 1
ChemicalCartridgeEthanol: 1
ChemicalCartridgeFluorine: 1
ChemicalCartridgeHydrogen: 1
ChemicalCartridgeIodine: 1
ChemicalCartridgeIron: 1
ChemicalCartridgeLithium: 1
ChemicalCartridgeMercury: 1
ChemicalCartridgeNitrogen: 1
ChemicalCartridgeOxygen: 1
ChemicalCartridgePhosphorus: 1
ChemicalCartridgePotassium: 1
ChemicalCartridgeRadium: 1
ChemicalCartridgeSilicon: 1
ChemicalCartridgeSodium: 1
ChemicalCartridgeSugar: 1
ChemicalCartridgeSulfur: 1
emaggedInventory:
ToxinChemistryBottle: 1

View File

@@ -91,9 +91,8 @@
animationState: foam-dissolve
- type: Slippery
- type: StepTrigger
# disabled until foam reagent duplication is fixed
#- type: ScoopableSolution
# solution: solutionArea
- type: ScoopableSolution
solution: solutionArea
- type: entity
id: MetalFoam

View File

@@ -212,7 +212,7 @@
- ReagentId: Cognac
Quantity: 100
- type: Label
currentLabel: cognac
currentLabel: коньяк
- type: Sprite
sprite: Objects/Consumable/Drinks/cognacbottle.rsi
- type: Sealable
@@ -230,7 +230,7 @@
- ReagentId: Cola
Quantity: 100
- type: Label
currentLabel: cola
currentLabel: кола
- type: Sprite
sprite: Objects/Consumable/Drinks/colabottle.rsi
- type: Sealable
@@ -268,7 +268,7 @@
- ReagentId: Gin
Quantity: 100
- type: Label
currentLabel: gin
currentLabel: джин
- type: Sprite
sprite: Objects/Consumable/Drinks/ginbottle.rsi
- type: Sealable
@@ -302,7 +302,7 @@
- ReagentId: CoffeeLiqueur
Quantity: 100
- type: Label
currentLabel: coffee liqueur
currentLabel: кофейный ликёр
- type: Sprite
sprite: Objects/Consumable/Drinks/coffeeliqueurbottle.rsi
- type: Sealable
@@ -378,7 +378,7 @@
- ReagentId: Rum
Quantity: 100
- type: Label
currentLabel: rum
currentLabel: ром
- type: Sprite
sprite: Objects/Consumable/Drinks/rumbottle.rsi
- type: Sealable
@@ -397,7 +397,7 @@
Quantity: 100
- type: Drink
- type: Label
currentLabel: space mountain wind
currentLabel: маунтин винд
- type: Sprite
sprite: Objects/Consumable/Drinks/space_mountain_wind_bottle.rsi
- type: Sealable
@@ -416,7 +416,7 @@
Quantity: 100
- type: Drink
- type: Label
currentLabel: space-up
currentLabel: спейс-ап
- type: Sprite
sprite: Objects/Consumable/Drinks/space-up_bottle.rsi
- type: Sealable
@@ -434,7 +434,7 @@
- ReagentId: Tequila
Quantity: 100
- type: Label
currentLabel: tequila
currentLabel: текила
- type: Sprite
sprite: Objects/Consumable/Drinks/tequillabottle.rsi
- type: Sealable
@@ -452,7 +452,7 @@
- ReagentId: Vermouth
Quantity: 100
- type: Label
currentLabel: vermouth
currentLabel: вермут
- type: Sprite
sprite: Objects/Consumable/Drinks/vermouthbottle.rsi
- type: Sealable
@@ -470,7 +470,7 @@
- ReagentId: Vodka
Quantity: 100
- type: Label
currentLabel: vodka
currentLabel: водка
- type: Sprite
sprite: Objects/Consumable/Drinks/vodkabottle.rsi
- type: Sealable
@@ -488,7 +488,7 @@
- ReagentId: Whiskey
Quantity: 100
- type: Label
currentLabel: whiskey
currentLabel: виски
- type: Sprite
sprite: Objects/Consumable/Drinks/whiskeybottle.rsi
- type: Sealable
@@ -506,7 +506,7 @@
- ReagentId: Wine
Quantity: 100
- type: Label
currentLabel: wine
currentLabel: вино
- type: Sprite
sprite: Objects/Consumable/Drinks/winebottle.rsi
- type: Sealable
@@ -553,7 +553,7 @@
- ReagentId: Beer
Quantity: 150
- type: Label
currentLabel: beer
currentLabel: пиво
- type: Sprite
sprite: Objects/Consumable/Drinks/beer.rsi
- type: Openable
@@ -597,7 +597,7 @@
- ReagentId: Ale
Quantity: 150
- type: Label
currentLabel: ale
currentLabel: эль
- type: Sprite
sprite: Objects/Consumable/Drinks/alebottle.rsi
- type: Openable
@@ -649,7 +649,7 @@
- ReagentId: SodaWater
Quantity: 150
- type: Label
currentLabel: soda water
currentLabel: газировка
- type: entity
parent: DrinkWaterBottleFull
@@ -665,7 +665,7 @@
- ReagentId: TonicWater
Quantity: 150
- type: Label
currentLabel: tonic water
currentLabel: тоник
- type: entity
parent: [DrinkBottleVisualsOpenable, DrinkBottleGlassBaseFull]
@@ -680,7 +680,7 @@
- ReagentId: Sake
Quantity: 50
- type: Label
currentLabel: Sake
currentLabel: Саке
- type: Sprite
sprite: Objects/Consumable/Drinks/sakebottle.rsi
- type: Sealable
@@ -702,7 +702,7 @@
Quantity: 150
- type: Drink
- type: Label
currentLabel: lime juice
currentLabel: лаймовый сок
- type: Sprite
sprite: Objects/Consumable/Drinks/limejuice.rsi
@@ -721,7 +721,7 @@
Quantity: 150
- type: Drink
- type: Label
currentLabel: orange juice
currentLabel: апельсиновый сок
- type: Sprite
sprite: Objects/Consumable/Drinks/orangejuice.rsi
@@ -740,7 +740,7 @@
Quantity: 150
- type: Drink
- type: Label
currentLabel: cream
currentLabel: сливки
- type: Sprite
sprite: Objects/Consumable/Drinks/cream.rsi
@@ -777,7 +777,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: lemon-lime
currentLabel: лимон-лайм
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -794,7 +794,7 @@
Quantity: 150
- type: Drink
- type: Label
currentLabel: mead
currentLabel: медовуха
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -811,7 +811,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: ice
currentLabel: лёд
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -828,7 +828,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: coconut water
currentLabel: кокосовая вода
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -845,7 +845,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: coffee
currentLabel: кофе
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -862,7 +862,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: tea
currentLabel: чай
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -879,7 +879,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: green tea
currentLabel: зеленый чай
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -895,6 +895,8 @@
- ReagentId: IcedTea
Quantity: 300
- type: Drink
- type: Label
currentLabel: холодный чай
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -911,7 +913,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: dr gibb
currentLabel: доктор Гибб
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -928,7 +930,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: root beer
currentLabel: рутбир
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -945,7 +947,7 @@
Quantity: 300
- type: Drink
- type: Label
currentLabel: watermelon juice
currentLabel: арбузный сок
- type: entity
parent: DrinkBottlePlasticBaseFull
@@ -962,7 +964,7 @@
Quantity: 100
- type: Drink
- type: Label
currentLabel: red bool
currentLabel: редбул
- type: entity
parent: DrinkBottlePlasticBaseFull

View File

@@ -569,7 +569,7 @@
- type: Sprite
state: medical
- type: MachineBoard
prototype: ChemDispenser
prototype: ChemDispenserEmpty
requirements:
Capacitor: 1
materialRequirements:
@@ -1187,7 +1187,7 @@
- type: Sprite
state: service
- type: MachineBoard
prototype: BoozeDispenser
prototype: BoozeDispenserEmpty
materialRequirements:
Steel: 5
tagRequirements:
@@ -1220,7 +1220,7 @@
- type: Sprite
state: service
- type: MachineBoard
prototype: soda_dispenser
prototype: SodaDispenserEmpty
materialRequirements:
Steel: 5
tagRequirements:

View File

@@ -43,40 +43,10 @@
- type: SolutionContainerVisuals
maxFillLevels: 6
fillBaseName: jug
inHandsMaxFillLevels: 5
inHandsFillBaseName: -fill-
- type: StaticPrice
price: 60
- type: Damageable
damageContainer: Inorganic
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 200
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- trigger:
!type:DamageTrigger
damage: 20
behaviors:
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
params:
volume: -4
- !type:SpillBehavior { }
- !type:SpawnEntitiesBehavior
spawn:
SheetPlastic1:
min: 0
max: 1
transferForensics: true
- !type:DoActsBehavior
acts: [ "Destruction" ]
- type: Label
originalName: jug
originalName: кувшин
- type: MeleeWeapon
canBeBlocked: false
soundNoDamage:

View File

@@ -55,13 +55,15 @@
sound:
collection: MetalGlassBreak
- type: ReagentDispenser
storageWhitelist:
tags:
- Bottle
beakerSlot:
whitelistFailPopup: reagent-dispenser-component-cannot-put-entity-message
whitelist:
components:
- FitsInDispenser
- type: ItemSlots
slots:
beakerSlot:
whitelistFailPopup: reagent-dispenser-component-cannot-put-entity-message
whitelist:
components:
- FitsInDispenser
- type: ContainerContainer
containers:
machine_board: !type:Container

View File

@@ -1,6 +1,7 @@
- type: entity
id: BoozeDispenser
name: booze dispenser
suffix: Filled
description: A booze dispenser with a single slot for a container to be filled.
parent: ReagentDispenserBase
components:
@@ -10,8 +11,10 @@
drawdepth: SmallObjects
state: booze
- type: ReagentDispenser
storageWhitelist:
tags:
- DrinkBottle
pack: BoozeDispenserInventory
emagPack: BoozeDispenserEmagInventory
- type: Transform
noRot: false
- type: Machine
@@ -21,3 +24,14 @@
- Bartender
- type: StealTarget
stealGroup: BoozeDispenser
- type: entity
id: BoozeDispenserEmpty
suffix: Empty
parent: BoozeDispenser
components:
- type: ReagentDispenser
storageWhitelist:
tags:
- DrinkBottle
pack: EmptyInventory

View File

@@ -1,16 +1,19 @@
- type: entity
id: ChemDispenser
name: chemical dispenser
suffix: Filled
parent: ReagentDispenserBase
description: An industrial grade chemical dispenser with a sizeable chemical supply.
description: An industrial grade chemical dispenser.
components:
- type: Sprite
sprite: Structures/dispensers.rsi
state: industrial-working
snapCardinals: true
- type: ReagentDispenser
storageWhitelist:
tags:
- ChemDispensable
pack: ChemDispenserStandardInventory
emagPack: ChemDispenserEmaggedInventory
- type: ApcPowerReceiver
- type: ExtensionCableReceiver
- type: Destructible
@@ -28,12 +31,21 @@
acts: ["Destruction"]
- type: Machine
board: ChemDispenserMachineCircuitboard
- type: Wires
boardName: wires-board-name-chemdispenser
layoutId: ChemDispenser
- type: GuideHelp
guides:
- Chemicals
- Chemist
- type: StealTarget
stealGroup: ChemDispenser
- type: DeviceNetwork
deviceNetId: Wired
receiveFrequencyId: BasicDevice
- type: entity
id: ChemDispenserEmpty
name: chemical dispenser
suffix: Empty
parent: ChemDispenser
components:
- type: ReagentDispenser
pack: EmptyInventory

View File

@@ -1,6 +1,7 @@
- type: entity
id: soda_dispenser
name: soda dispenser
suffix: Filled
parent: ReagentDispenserBase
description: A beverage dispenser with a selection of soda and several other common beverages. Has a single fill slot for containers.
components:
@@ -10,8 +11,10 @@
drawdepth: SmallObjects
state: soda
- type: ReagentDispenser
storageWhitelist:
tags:
- DrinkBottle
pack: SodaDispenserInventory
emagPack: SodaDispenserEmagInventory
- type: Transform
noRot: false
- type: Machine
@@ -19,3 +22,14 @@
- type: GuideHelp
guides:
- Bartender
- type: entity
id: SodaDispenserEmpty
suffix: Empty
parent: soda_dispenser
components:
- type: ReagentDispenser
storageWhitelist:
tags:
- DrinkBottle
pack: EmptyInventory

View File

@@ -0,0 +1,370 @@
- type: entity
id: ChemicalCartridge
name: chemical cartridge
parent: [DrinkBottleVisualsOpenable, BaseItem]
description: Used to contain a very large amount of chemicals or solutions. Used in chemical dispensers
components:
- type: SolutionContainerManager
solutions:
beaker:
maxVol: 500
canMix: true
- type: Openable
sound:
collection: bottleCloseSounds
closeable: true
closeSound:
collection: bottleCloseSounds
- type: Sprite
sprite: White/Objects/Specific/Chemical/chemical_cartridge.rsi
state: icon
scale: 0.8, 0.8
- type: Item
size: Huge
- type: RefillableSolution
solution: beaker
- type: DrainableSolution
solution: beaker
- type: ExaminableSolution
solution: beaker
- type: SolutionTransfer
canChangeTransferAmount: false
- type: Spillable
solution: beaker
- type: StaticPrice
price: 150
- type: Label
originalName: химический картридж
- type: Tag
tags:
- ChemDispensable
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (carbon)
id: ChemicalCartridgeCarbon
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-carbon
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Carbon
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (iodine)
id: ChemicalCartridgeIodine
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-iodine
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Iodine
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (fluorine)
id: ChemicalCartridgeFluorine
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-fluorine
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Fluorine
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (chlorine)
id: ChemicalCartridgeChlorine
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-chlorine
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Chlorine
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (aluminium)
id: ChemicalCartridgeAluminium
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-aluminium
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Aluminium
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (phosphorus)
id: ChemicalCartridgePhosphorus
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-phosphorus
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Phosphorus
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (sulfur)
id: ChemicalCartridgeSulfur
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-sulfur
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Sulfur
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (silicon)
id: ChemicalCartridgeSilicon
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-silicon
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Silicon
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (hydrogen)
id: ChemicalCartridgeHydrogen
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-hydrogen
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Hydrogen
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (lithium)
id: ChemicalCartridgeLithium
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-lithium
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Lithium
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (sodium)
id: ChemicalCartridgeSodium
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-sodium
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Sodium
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (potassium)
id: ChemicalCartridgePotassium
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-potassium
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Potassium
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (radium)
id: ChemicalCartridgeRadium
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-radium
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Radium
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (iron)
id: ChemicalCartridgeIron
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-iron
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Iron
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (copper)
id: ChemicalCartridgeCopper
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-copper
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Copper
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (gold)
id: ChemicalCartridgeGold
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-gold
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Gold
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (mercury)
id: ChemicalCartridgeMercury
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-mercury
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Mercury
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (silver)
id: ChemicalCartridgeSilver
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-silver
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Silver
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (ethanol)
id: ChemicalCartridgeEthanol
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-ethanol
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Ethanol
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (Sugar)
id: ChemicalCartridgeSugar
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-sugar
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Sugar
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (nitrogen)
id: ChemicalCartridgeNitrogen
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-nitrogen
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Nitrogen
Quantity: 500
- type: entity
parent: ChemicalCartridge
name: chemical cartridge (oxygen)
id: ChemicalCartridgeOxygen
noSpawn: true
components:
- type: Label
currentLabel: reagent-name-oxygen
- type: SolutionContainerManager
solutions:
beaker:
reagents:
- ReagentId: Oxygen
Quantity: 500

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

View File

@@ -0,0 +1,33 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Made by 6mirage6",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
},
{
"name": "icon_open"
},
{
"name": "inhand-left-open",
"directions": 4
},
{
"name": "inhand-right-open",
"directions": 4
}
]
}