diff --git a/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs b/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs
index 3765d45fa2..aaeaf538f3 100644
--- a/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs
+++ b/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs
@@ -19,14 +19,9 @@ namespace Content.Client.AME.UI
{
base.Open();
- _window = new AMEWindow();
+ _window = new AMEWindow(this);
_window.OnClose += Close;
_window.OpenCentered();
-
- _window.EjectButton.OnPressed += _ => ButtonPressed(UiButton.Eject);
- _window.ToggleInjection.OnPressed += _ => ButtonPressed(UiButton.ToggleInjection);
- _window.IncreaseFuelButton.OnPressed += _ => ButtonPressed(UiButton.IncreaseFuel);
- _window.DecreaseFuelButton.OnPressed += _ => ButtonPressed(UiButton.DecreaseFuel);
}
///
@@ -44,7 +39,7 @@ namespace Content.Client.AME.UI
_window?.UpdateState(castState); //Update window state
}
- private void ButtonPressed(UiButton button, int dispenseIndex = -1)
+ public void ButtonPressed(UiButton button, int dispenseIndex = -1)
{
SendMessage(new UiButtonPressedMessage(button));
}
diff --git a/Content.Client/AME/UI/AMEWindow.cs b/Content.Client/AME/UI/AMEWindow.cs
deleted file mode 100644
index e9104e6f67..0000000000
--- a/Content.Client/AME/UI/AMEWindow.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-using Content.Client.Stylesheets;
-using Robust.Client.UserInterface;
-using Robust.Client.UserInterface.Controls;
-using Robust.Client.UserInterface.CustomControls;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Localization;
-using static Content.Shared.AME.SharedAMEControllerComponent;
-using static Robust.Client.UserInterface.Controls.BoxContainer;
-
-namespace Content.Client.AME.UI
-{
- public class AMEWindow : SS14Window
- {
- public Label InjectionStatus { get; set; }
- public Button EjectButton { get; set; }
- public Button ToggleInjection { get; set; }
- public Button IncreaseFuelButton { get; set; }
- public Button DecreaseFuelButton { get; set; }
- public ProgressBar? FuelMeter { get; set; }
- public Label FuelAmount { get; set; }
- public Label InjectionAmount { get; set; }
- public Label CoreCount { get; set; }
-
-
- public AMEWindow()
- {
- IoCManager.InjectDependencies(this);
-
- Title = Loc.GetString("ame-window-title");
-
- MinSize = SetSize = (250, 250);
-
- Contents.AddChild(new BoxContainer
- {
- Orientation = LayoutOrientation.Vertical,
- Children =
- {
- new BoxContainer
- {
- Orientation = LayoutOrientation.Horizontal,
- Children =
- {
- new Label {Text = Loc.GetString("ame-window-engine-status-label") + " "},
- (InjectionStatus = new Label {Text = Loc.GetString("ame-window-engine-injection-status-not-injecting-label")})
- }
- },
- new BoxContainer
- {
- Orientation = LayoutOrientation.Horizontal,
- Children =
- {
- (ToggleInjection = new Button {Text = Loc.GetString("ame-window-toggle-injection-button"), StyleClasses = {StyleBase.ButtonOpenBoth}, Disabled = true}),
- }
- },
- new BoxContainer
- {
- Orientation = LayoutOrientation.Horizontal,
- Children =
- {
- new Label {Text = Loc.GetString("ame-window-fuel-status-label") + " "},
- (FuelAmount = new Label {Text = Loc.GetString("ame-window-fuel-not-inserted-text")})
- }
- },
- new BoxContainer
- {
- Orientation = LayoutOrientation.Horizontal,
- Children =
- {
- (EjectButton = new Button {Text = Loc.GetString("ame-window-eject-button"), StyleClasses = {StyleBase.ButtonOpenBoth}, Disabled = true}),
- }
- },
- new BoxContainer
- {
- Orientation = LayoutOrientation.Horizontal,
- Children =
- {
- new Label {Text = Loc.GetString("ame-window-injection-amount-label") + " "},
- (InjectionAmount = new Label {Text = "0"})
- }
- },
- new BoxContainer
- {
- Orientation = LayoutOrientation.Horizontal,
- Children =
- {
- (IncreaseFuelButton = new Button {Text = Loc.GetString("ame-window-increase-fuel-button"), StyleClasses = {StyleBase.ButtonOpenRight}}),
- (DecreaseFuelButton = new Button {Text = Loc.GetString("ame-window-decrease-fuel-button"), StyleClasses = {StyleBase.ButtonOpenLeft}}),
- }
- },
- new BoxContainer
- {
- Orientation = LayoutOrientation.Horizontal,
- Children =
- {
- new Label { Text = Loc.GetString("ame-window-core-count-label") + " "},
- (CoreCount = new Label { Text = "0"}),
- }
- }
- }
- });
- }
-
- ///
- /// This searches recursively through all the children of "parent"
- /// and sets the Disabled value of any buttons found to "val"
- ///
- /// The control which childrens get searched
- /// The value to which disabled gets set
- private void SetButtonDisabledRecursive(Control parent, bool val)
- {
- foreach (var child in parent.Children)
- {
- if (child is Button but)
- {
- but.Disabled = val;
- continue;
- }
-
- if (child.Children != null)
- {
- SetButtonDisabledRecursive(child, val);
- }
- }
- }
-
- ///
- /// Update the UI state when new state data is received from the server.
- ///
- /// State data sent by the server.
- public void UpdateState(BoundUserInterfaceState state)
- {
- var castState = (AMEControllerBoundUserInterfaceState) state;
-
- // Disable all buttons if not powered
- if (Contents.Children != null)
- {
- SetButtonDisabledRecursive(Contents, !castState.HasPower);
- EjectButton.Disabled = false;
- }
-
- if (!castState.HasFuelJar)
- {
- EjectButton.Disabled = true;
- ToggleInjection.Disabled = true;
- FuelAmount.Text = Loc.GetString("ame-window-fuel-not-inserted-text");
- }
- else
- {
- EjectButton.Disabled = false;
- ToggleInjection.Disabled = false;
- FuelAmount.Text = $"{castState.FuelAmount}";
- }
-
- if (!castState.IsMaster)
- {
- ToggleInjection.Disabled = true;
- }
-
- if (!castState.Injecting)
- {
- InjectionStatus.Text = Loc.GetString("ame-window-engine-injection-status-not-injecting-label") + " ";
- }
- else
- {
- InjectionStatus.Text = Loc.GetString("ame-window-engine-injection-status-injecting-label") + " ";
- }
-
- CoreCount.Text = $"{castState.CoreCount}";
- InjectionAmount.Text = $"{castState.InjectionAmount}";
- }
- }
-}
diff --git a/Content.Client/AME/UI/AMEWindow.xaml b/Content.Client/AME/UI/AMEWindow.xaml
new file mode 100644
index 0000000000..bc1e7d9ded
--- /dev/null
+++ b/Content.Client/AME/UI/AMEWindow.xaml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/AME/UI/AMEWindow.xaml.cs b/Content.Client/AME/UI/AMEWindow.xaml.cs
new file mode 100644
index 0000000000..90c345faf7
--- /dev/null
+++ b/Content.Client/AME/UI/AMEWindow.xaml.cs
@@ -0,0 +1,74 @@
+using Content.Client.UserInterface;
+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.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
+using static Content.Shared.AME.SharedAMEControllerComponent;
+
+namespace Content.Client.AME.UI
+{
+ [GenerateTypedNameReferences]
+ public partial class AMEWindow : SS14Window
+ {
+ public AMEWindow(AMEControllerBoundUserInterface ui)
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+
+ EjectButton.OnPressed += _ => ui.ButtonPressed(UiButton.Eject);
+ ToggleInjection.OnPressed += _ => ui.ButtonPressed(UiButton.ToggleInjection);
+ IncreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.IncreaseFuel);
+ DecreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.DecreaseFuel);
+ }
+
+ ///
+ /// Update the UI state when new state data is received from the server.
+ ///
+ /// State data sent by the server.
+ public void UpdateState(BoundUserInterfaceState state)
+ {
+ var castState = (AMEControllerBoundUserInterfaceState) state;
+
+ // Disable all buttons if not powered
+ if (Contents.Children != null)
+ {
+ ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower);
+ EjectButton.Disabled = false;
+ }
+
+ if (!castState.HasFuelJar)
+ {
+ EjectButton.Disabled = true;
+ ToggleInjection.Disabled = true;
+ FuelAmount.Text = Loc.GetString("ame-window-fuel-not-inserted-text");
+ }
+ else
+ {
+ EjectButton.Disabled = false;
+ ToggleInjection.Disabled = false;
+ FuelAmount.Text = $"{castState.FuelAmount}";
+ }
+
+ if (!castState.IsMaster)
+ {
+ ToggleInjection.Disabled = true;
+ }
+
+ if (!castState.Injecting)
+ {
+ InjectionStatus.Text = Loc.GetString("ame-window-engine-injection-status-not-injecting-label") + " ";
+ }
+ else
+ {
+ InjectionStatus.Text = Loc.GetString("ame-window-engine-injection-status-injecting-label") + " ";
+ }
+
+ CoreCount.Text = $"{castState.CoreCount}";
+ InjectionAmount.Text = $"{castState.InjectionAmount}";
+ }
+ }
+}
diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.cs b/Content.Client/Access/UI/IdCardConsoleWindow.cs
deleted file mode 100644
index 4c3093baa2..0000000000
--- a/Content.Client/Access/UI/IdCardConsoleWindow.cs
+++ /dev/null
@@ -1,208 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Content.Shared.Access;
-using Robust.Client.UserInterface;
-using Robust.Client.UserInterface.Controls;
-using Robust.Client.UserInterface.CustomControls;
-using Robust.Shared.Localization;
-using Robust.Shared.Maths;
-using Robust.Shared.Prototypes;
-using static Content.Shared.Access.SharedIdCardConsoleComponent;
-using static Robust.Client.UserInterface.Controls.BoxContainer;
-
-namespace Content.Client.Access.UI
-{
- public class IdCardConsoleWindow : SS14Window
- {
- private readonly Button _privilegedIdButton;
- private readonly Button _targetIdButton;
-
- private readonly Label _privilegedIdLabel;
- private readonly Label _targetIdLabel;
-
- private readonly Label _fullNameLabel;
- private readonly LineEdit _fullNameLineEdit;
- private readonly Label _jobTitleLabel;
- private readonly LineEdit _jobTitleLineEdit;
-
- private readonly Button _fullNameSaveButton;
- private readonly Button _jobTitleSaveButton;
-
- private readonly IdCardConsoleBoundUserInterface _owner;
-
- private readonly Dictionary _accessButtons = new();
-
- private string? _lastFullName;
- private string? _lastJobTitle;
-
- public IdCardConsoleWindow(IdCardConsoleBoundUserInterface owner, IPrototypeManager prototypeManager)
- {
- MinSize = SetSize = (650, 290);
- _owner = owner;
- var vBox = new BoxContainer
- {
- Orientation = LayoutOrientation.Vertical
- };
-
- vBox.AddChild(new GridContainer
- {
- Columns = 3,
- Children =
- {
- new Label {Text = Loc.GetString("id-card-console-window-privileged-id")},
- (_privilegedIdButton = new Button()),
- (_privilegedIdLabel = new Label()),
-
- new Label {Text = Loc.GetString("id-card-console-window-target-id")},
- (_targetIdButton = new Button()),
- (_targetIdLabel = new Label())
- }
- });
-
- _privilegedIdButton.OnPressed += _ => _owner.ButtonPressed(UiButton.PrivilegedId);
- _targetIdButton.OnPressed += _ => _owner.ButtonPressed(UiButton.TargetId);
-
- // Separator
- vBox.AddChild(new Control {MinSize = (0, 8)});
-
- // Name and job title line edits.
- vBox.AddChild(new GridContainer
- {
- Columns = 3,
- HSeparationOverride = 4,
- Children =
- {
- // Name
- (_fullNameLabel = new Label
- {
- Text = Loc.GetString("id-card-console-window-full-name-label")
- }),
- (_fullNameLineEdit = new LineEdit
- {
- HorizontalExpand = true,
- }),
- (_fullNameSaveButton = new Button
- {
- Text = Loc.GetString("id-card-console-window-save-button"),
- Disabled = true
- }),
-
- // Title
- (_jobTitleLabel = new Label
- {
- Text = Loc.GetString("id-card-console-window-job-title-label")
- }),
- (_jobTitleLineEdit = new LineEdit
- {
- HorizontalExpand = true
- }),
- (_jobTitleSaveButton = new Button
- {
- Text = Loc.GetString("id-card-console-window-save-button"),
- Disabled = true
- }),
- },
- });
-
- _fullNameLineEdit.OnTextEntered += _ => SubmitData();
- _fullNameLineEdit.OnTextChanged += _ =>
- {
- _fullNameSaveButton.Disabled = _fullNameSaveButton.Text == _lastFullName;
- };
- _fullNameSaveButton.OnPressed += _ => SubmitData();
-
- _jobTitleLineEdit.OnTextEntered += _ => SubmitData();
- _jobTitleLineEdit.OnTextChanged += _ =>
- {
- _jobTitleSaveButton.Disabled = _jobTitleLineEdit.Text == _lastJobTitle;
- };
- _jobTitleSaveButton.OnPressed += _ => SubmitData();
-
- // Separator
- vBox.AddChild(new Control {MinSize = (0, 8)});
-
- {
- var grid = new GridContainer
- {
- Columns = 5,
- HorizontalAlignment = HAlignment.Center
- };
- vBox.AddChild(grid);
-
- foreach (var accessLevel in prototypeManager.EnumeratePrototypes())
- {
- var newButton = new Button
- {
- Text = accessLevel.Name,
- ToggleMode = true,
- };
- grid.AddChild(newButton);
- _accessButtons.Add(accessLevel.ID, newButton);
- newButton.OnPressed += _ => SubmitData();
- }
- }
-
- Contents.AddChild(vBox);
- }
-
- public void UpdateState(IdCardConsoleBoundUserInterfaceState state)
- {
- _privilegedIdButton.Text = state.IsPrivilegedIdPresent
- ? Loc.GetString("id-card-console-window-eject-button")
- : Loc.GetString("id-card-console-window-insert-button");
-
- _privilegedIdLabel.Text = state.PrivilegedIdName;
-
- _targetIdButton.Text = state.IsTargetIdPresent
- ? Loc.GetString("id-card-console-window-eject-button")
- : Loc.GetString("id-card-console-window-insert-button");
-
- _targetIdLabel.Text = state.TargetIdName;
-
- var interfaceEnabled =
- state.IsPrivilegedIdPresent && state.IsPrivilegedIdAuthorized && state.IsTargetIdPresent;
-
- var fullNameDirty = _lastFullName != null && _fullNameLineEdit.Text != state.TargetIdFullName;
- var jobTitleDirty = _lastJobTitle != null && _jobTitleLineEdit.Text != state.TargetIdJobTitle;
-
- _fullNameLabel.Modulate = interfaceEnabled ? Color.White : Color.Gray;
- _fullNameLineEdit.Editable = interfaceEnabled;
- if (!fullNameDirty)
- {
- _fullNameLineEdit.Text = state.TargetIdFullName ?? string.Empty;
- }
-
- _fullNameSaveButton.Disabled = !interfaceEnabled || !fullNameDirty;
-
- _jobTitleLabel.Modulate = interfaceEnabled ? Color.White : Color.Gray;
- _jobTitleLineEdit.Editable = interfaceEnabled;
- if (!jobTitleDirty)
- {
- _jobTitleLineEdit.Text = state.TargetIdJobTitle ?? string.Empty;
- }
-
- _jobTitleSaveButton.Disabled = !interfaceEnabled || !jobTitleDirty;
-
- foreach (var (accessName, button) in _accessButtons)
- {
- button.Disabled = !interfaceEnabled;
- if (interfaceEnabled)
- {
- button.Pressed = state.TargetIdAccessList?.Contains(accessName) ?? false;
- }
- }
-
- _lastFullName = state.TargetIdFullName;
- _lastJobTitle = state.TargetIdJobTitle;
- }
-
- private void SubmitData()
- {
- _owner.SubmitData(
- _fullNameLineEdit.Text,
- _jobTitleLineEdit.Text,
- // Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
- _accessButtons.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
- }
- }
-}
diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.xaml b/Content.Client/Access/UI/IdCardConsoleWindow.xaml
new file mode 100644
index 0000000000..b384e448fa
--- /dev/null
+++ b/Content.Client/Access/UI/IdCardConsoleWindow.xaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs
new file mode 100644
index 0000000000..dfb35f36ac
--- /dev/null
+++ b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs
@@ -0,0 +1,121 @@
+using System.Collections.Generic;
+using System.Linq;
+using Content.Shared.Access;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Localization;
+using Robust.Shared.Maths;
+using Robust.Shared.Prototypes;
+using static Content.Shared.Access.SharedIdCardConsoleComponent;
+
+namespace Content.Client.Access.UI
+{
+ [GenerateTypedNameReferences]
+ public partial class IdCardConsoleWindow : SS14Window
+ {
+ private readonly IdCardConsoleBoundUserInterface _owner;
+
+ private readonly Dictionary _accessButtons = new();
+
+ private string? _lastFullName;
+ private string? _lastJobTitle;
+
+ public IdCardConsoleWindow(IdCardConsoleBoundUserInterface owner, IPrototypeManager prototypeManager)
+ {
+ RobustXamlLoader.Load(this);
+
+ _owner = owner;
+
+ PrivilegedIdButton.OnPressed += _ => _owner.ButtonPressed(UiButton.PrivilegedId);
+ TargetIdButton.OnPressed += _ => _owner.ButtonPressed(UiButton.TargetId);
+
+ FullNameLineEdit.OnTextEntered += _ => SubmitData();
+ FullNameLineEdit.OnTextChanged += _ =>
+ {
+ FullNameSaveButton.Disabled = FullNameSaveButton.Text == _lastFullName;
+ };
+ FullNameSaveButton.OnPressed += _ => SubmitData();
+
+ JobTitleLineEdit.OnTextEntered += _ => SubmitData();
+ JobTitleLineEdit.OnTextChanged += _ =>
+ {
+ JobTitleSaveButton.Disabled = JobTitleLineEdit.Text == _lastJobTitle;
+ };
+ JobTitleSaveButton.OnPressed += _ => SubmitData();
+
+ foreach (var accessLevel in prototypeManager.EnumeratePrototypes())
+ {
+ var newButton = new Button
+ {
+ Text = accessLevel.Name,
+ ToggleMode = true,
+ };
+ AccessLevelGrid.AddChild(newButton);
+ _accessButtons.Add(accessLevel.ID, newButton);
+ newButton.OnPressed += _ => SubmitData();
+ }
+ }
+
+ public void UpdateState(IdCardConsoleBoundUserInterfaceState state)
+ {
+ PrivilegedIdButton.Text = state.IsPrivilegedIdPresent
+ ? Loc.GetString("id-card-console-window-eject-button")
+ : Loc.GetString("id-card-console-window-insert-button");
+
+ PrivilegedIdLabel.Text = state.PrivilegedIdName;
+
+ TargetIdButton.Text = state.IsTargetIdPresent
+ ? Loc.GetString("id-card-console-window-eject-button")
+ : Loc.GetString("id-card-console-window-insert-button");
+
+ TargetIdLabel.Text = state.TargetIdName;
+
+ var interfaceEnabled =
+ state.IsPrivilegedIdPresent && state.IsPrivilegedIdAuthorized && state.IsTargetIdPresent;
+
+ var fullNameDirty = _lastFullName != null && FullNameLineEdit.Text != state.TargetIdFullName;
+ var jobTitleDirty = _lastJobTitle != null && JobTitleLineEdit.Text != state.TargetIdJobTitle;
+
+ FullNameLabel.Modulate = interfaceEnabled ? Color.White : Color.Gray;
+ FullNameLineEdit.Editable = interfaceEnabled;
+ if (!fullNameDirty)
+ {
+ FullNameLineEdit.Text = state.TargetIdFullName ?? string.Empty;
+ }
+
+ FullNameSaveButton.Disabled = !interfaceEnabled || !fullNameDirty;
+
+ JobTitleLabel.Modulate = interfaceEnabled ? Color.White : Color.Gray;
+ JobTitleLineEdit.Editable = interfaceEnabled;
+ if (!jobTitleDirty)
+ {
+ JobTitleLineEdit.Text = state.TargetIdJobTitle ?? string.Empty;
+ }
+
+ JobTitleSaveButton.Disabled = !interfaceEnabled || !jobTitleDirty;
+
+ foreach (var (accessName, button) in _accessButtons)
+ {
+ button.Disabled = !interfaceEnabled;
+ if (interfaceEnabled)
+ {
+ button.Pressed = state.TargetIdAccessList?.Contains(accessName) ?? false;
+ }
+ }
+
+ _lastFullName = state.TargetIdFullName;
+ _lastJobTitle = state.TargetIdJobTitle;
+ }
+
+ private void SubmitData()
+ {
+ _owner.SubmitData(
+ FullNameLineEdit.Text,
+ JobTitleLineEdit.Text,
+ // Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
+ _accessButtons.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
+ }
+ }
+}
diff --git a/Content.Client/Alerts/UI/AlertsUI.xaml b/Content.Client/Alerts/UI/AlertsUI.xaml
new file mode 100644
index 0000000000..516db31159
--- /dev/null
+++ b/Content.Client/Alerts/UI/AlertsUI.xaml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/Content.Client/Alerts/UI/AlertsUI.cs b/Content.Client/Alerts/UI/AlertsUI.xaml.cs
similarity index 71%
rename from Content.Client/Alerts/UI/AlertsUI.cs
rename to Content.Client/Alerts/UI/AlertsUI.xaml.cs
index 46e6721acd..0a1d35ef88 100644
--- a/Content.Client/Alerts/UI/AlertsUI.cs
+++ b/Content.Client/Alerts/UI/AlertsUI.xaml.cs
@@ -1,8 +1,9 @@
using Content.Client.Chat.Managers;
using Content.Client.Chat.UI;
-using Content.Client.Stylesheets;
+using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
namespace Content.Client.Alerts.UI
@@ -10,13 +11,20 @@ namespace Content.Client.Alerts.UI
///
/// The status effects display on the right side of the screen.
///
- public sealed class AlertsUI : Control
+ [GenerateTypedNameReferences]
+ public sealed partial class AlertsUI : Control
{
+ [Dependency] private readonly IChatManager _chatManager = default!;
+
public const float ChatSeparation = 38f;
- public GridContainer Grid { get; }
+
+ public GridContainer Grid => AlertContainer;
public AlertsUI()
{
+ IoCManager.InjectDependencies(this);
+ RobustXamlLoader.Load(this);
+
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.Begin);
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.End);
LayoutContainer.SetAnchorTop(this, 0f);
@@ -25,28 +33,11 @@ namespace Content.Client.Alerts.UI
LayoutContainer.SetMarginBottom(this, -180);
LayoutContainer.SetMarginTop(this, 250);
LayoutContainer.SetMarginRight(this, -10);
- var panelContainer = new PanelContainer
- {
- StyleClasses = {StyleNano.StyleClassTransparentBorderedWindowPanel},
- HorizontalAlignment = HAlignment.Right,
- VerticalAlignment = VAlignment.Top
- };
- AddChild(panelContainer);
-
- Grid = new GridContainer
- {
- MaxGridHeight = 64,
- ExpandBackwards = true
- };
- panelContainer.AddChild(Grid);
-
- MinSize = (64, 64);
}
protected override void EnteredTree()
{
base.EnteredTree();
- var _chatManager = IoCManager.Resolve();
_chatManager.OnChatBoxResized += OnChatResized;
OnChatResized(new ChatResizedEventArgs(HudChatBox.InitialChatBottom));
}
@@ -54,15 +45,12 @@ namespace Content.Client.Alerts.UI
protected override void ExitedTree()
{
base.ExitedTree();
- var _chatManager = IoCManager.Resolve();
_chatManager.OnChatBoxResized -= OnChatResized;
}
-
private void OnChatResized(ChatResizedEventArgs chatResizedEventArgs)
{
// resize us to fit just below the chatbox
- var _chatManager = IoCManager.Resolve();
if (_chatManager.CurrentChatBox != null)
{
LayoutContainer.SetMarginTop(this, chatResizedEventArgs.NewBottom + ChatSeparation);
@@ -81,12 +69,12 @@ namespace Content.Client.Alerts.UI
// this is here because there isn't currently a good way to allow the grid to adjust its height based
// on constraints, otherwise we would use anchors to lay it out
base.Resized();
- Grid.MaxGridHeight = Height;
+ AlertContainer.MaxGridHeight = Height;
}
protected override void UIScaleChanged()
{
- Grid.MaxGridHeight = Height;
+ AlertContainer.MaxGridHeight = Height;
base.UIScaleChanged();
}
}
diff --git a/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs
index 9beb61a3c9..ee46b25881 100644
--- a/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs
+++ b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs
@@ -19,6 +19,7 @@ namespace Content.Client.Atmos.EntitySystems
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
// Gas overlays
private readonly float[] _timer = new float[Atmospherics.TotalNumberOfGases];
@@ -38,16 +39,12 @@ namespace Content.Client.Atmos.EntitySystems
private readonly Dictionary> _tileData =
new();
- private AtmosphereSystem _atmosphereSystem = default!;
-
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent(HandleGasOverlayMessage);
_mapManager.OnGridRemoved += OnGridRemoved;
- _atmosphereSystem = Get();
-
for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{
var overlay = _atmosphereSystem.GetOverlay(i);
diff --git a/Content.Client/Audio/BackgroundAudioSystem.cs b/Content.Client/Audio/BackgroundAudioSystem.cs
index 4d79891649..8a6f2b2607 100644
--- a/Content.Client/Audio/BackgroundAudioSystem.cs
+++ b/Content.Client/Audio/BackgroundAudioSystem.cs
@@ -25,6 +25,7 @@ namespace Content.Client.Audio
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly IBaseClient _client = default!;
+ [Dependency] private readonly ClientGameTicker _gameTicker = default!;
private SoundCollectionPrototype _ambientCollection = default!;
@@ -48,7 +49,7 @@ namespace Content.Client.Audio
_client.PlayerJoinedServer += OnJoin;
_client.PlayerLeaveServer += OnLeave;
- Get().LobbyStatusUpdated += LobbySongReceived;
+ _gameTicker.LobbyStatusUpdated += LobbySongReceived;
}
public override void Shutdown()
@@ -60,7 +61,7 @@ namespace Content.Client.Audio
_client.PlayerJoinedServer -= OnJoin;
_client.PlayerLeaveServer -= OnLeave;
- Get().LobbyStatusUpdated -= LobbySongReceived;
+ _gameTicker.LobbyStatusUpdated -= LobbySongReceived;
EndAmbience();
EndLobbyMusic();
@@ -165,7 +166,7 @@ namespace Content.Client.Audio
private void StartLobbyMusic()
{
EndLobbyMusic();
- var file = Get().LobbySong;
+ var file = _gameTicker.LobbySong;
if (file == null) // We have not received the lobby song yet.
{
return;
diff --git a/Content.Client/Chemistry/UI/ChemMasterWindow.cs b/Content.Client/Chemistry/UI/ChemMasterWindow.cs
index c627470286..5f3a895e35 100644
--- a/Content.Client/Chemistry/UI/ChemMasterWindow.cs
+++ b/Content.Client/Chemistry/UI/ChemMasterWindow.cs
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using Content.Client.Stylesheets;
+using Content.Client.UserInterface;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Robust.Client.Graphics;
@@ -279,34 +280,11 @@ namespace Content.Client.Chemistry.UI
UpdatePanelInfo(castState);
if (Contents.Children != null)
{
- SetButtonDisabledRecursive(Contents, !castState.HasPower);
+ ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower);
EjectButton.Disabled = !castState.HasBeaker;
}
}
- ///
- /// This searches recursively through all the children of "parent"
- /// and sets the Disabled value of any buttons found to "val"
- ///
- /// The control which childrens get searched
- /// The value to which disabled gets set
- private void SetButtonDisabledRecursive(Control parent, bool val)
- {
- foreach (var child in parent.Children)
- {
- if (child is Button but)
- {
- but.Disabled = val;
- continue;
- }
-
- if (child.Children != null)
- {
- SetButtonDisabledRecursive(child, val);
- }
- }
- }
-
///
/// Update the container, buffer, and packaging panels.
///
diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.cs b/Content.Client/Chemistry/UI/ReagentDispenserWindow.cs
index e5b3571027..34311fb74d 100644
--- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.cs
+++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Content.Client.Stylesheets;
+using Content.Client.UserInterface;
using Content.Shared.Chemistry.Dispenser;
using Content.Shared.Chemistry.Reagent;
using Robust.Client.Graphics;
@@ -173,29 +174,6 @@ namespace Content.Client.Chemistry.UI
}
}
- ///
- /// This searches recursively through all the children of "parent"
- /// and sets the Disabled value of any buttons found to "val"
- ///
- /// The control which childrens get searched
- /// The value to which disabled gets set
- private void SetButtonDisabledRecursive(Control parent, bool val)
- {
- foreach (var child in parent.Children)
- {
- if (child is Button but)
- {
- but.Disabled = val;
- continue;
- }
-
- if (child.Children != null)
- {
- SetButtonDisabledRecursive(child, val);
- }
- }
- }
-
///
/// Update the UI state when new state data is received from the server.
///
@@ -209,7 +187,7 @@ namespace Content.Client.Chemistry.UI
// Disable all buttons if not powered
if (Contents.Children != null)
{
- SetButtonDisabledRecursive(Contents, !castState.HasPower);
+ ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower);
EjectButton.Disabled = false;
}
diff --git a/Content.Client/DragDrop/DragDropSystem.cs b/Content.Client/DragDrop/DragDropSystem.cs
index 7051978def..7163623a4b 100644
--- a/Content.Client/DragDrop/DragDropSystem.cs
+++ b/Content.Client/DragDrop/DragDropSystem.cs
@@ -36,6 +36,8 @@ namespace Content.Client.DragDrop
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
+ [Dependency] private readonly InputSystem _inputSystem = default!;
// how often to recheck possible targets (prevents calling expensive
// check logic each update)
@@ -69,8 +71,6 @@ namespace Content.Client.DragDrop
private ShaderInstance? _dropTargetInRangeShader;
private ShaderInstance? _dropTargetOutOfRangeShader;
- private SharedInteractionSystem _interactionSystem = default!;
- private InputSystem _inputSystem = default!;
private readonly List _highlightedSprites = new();
@@ -80,8 +80,6 @@ namespace Content.Client.DragDrop
_dropTargetInRangeShader = _prototypeManager.Index(ShaderDropTargetInRange).Instance();
_dropTargetOutOfRangeShader = _prototypeManager.Index(ShaderDropTargetOutOfRange).Instance();
- _interactionSystem = Get();
- _inputSystem = Get();
// needs to fire on mouseup and mousedown so we can detect a drag / drop
CommandBinds.Builder
.Bind(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false))
diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs
index c8c591b40c..f5d976796d 100644
--- a/Content.Client/Entry/IgnoredComponents.cs
+++ b/Content.Client/Entry/IgnoredComponents.cs
@@ -57,7 +57,6 @@ namespace Content.Client.Entry
"CablePlacer",
"Drink",
"Food",
- "FoodContainer",
"MagicMirror",
"FloorTile",
"ShuttleController",
@@ -93,6 +92,7 @@ namespace Content.Client.Entry
"ExaminableBattery",
"PottedPlantHide",
"SecureEntityStorage",
+ "Lock",
"PresetIdCard",
"SolarControlConsole",
"FlashOnTrigger",
@@ -277,6 +277,7 @@ namespace Content.Client.Entry
"Advertise",
"PowerNetworkBattery",
"BatteryCharger",
+ "SpawnItemsOnUse"
};
}
}
diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml b/Content.Client/Kitchen/UI/GrinderMenu.xaml
new file mode 100644
index 0000000000..38fd6ee197
--- /dev/null
+++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
new file mode 100644
index 0000000000..2698dab900
--- /dev/null
+++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs
@@ -0,0 +1,131 @@
+using System.Collections.Generic;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Chemistry.Solution;
+using Content.Shared.Kitchen.Components;
+using Robust.Client.AutoGenerated;
+using Robust.Client.GameObjects;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Localization;
+using Robust.Shared.Maths;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.Kitchen.UI
+{
+ [GenerateTypedNameReferences]
+ public partial class GrinderMenu : SS14Window
+ {
+ private readonly IEntityManager _entityManager;
+ private readonly IPrototypeManager _prototypeManager ;
+ private readonly ReagentGrinderBoundUserInterface _owner;
+
+ private readonly Dictionary _chamberVisualContents = new();
+
+ public GrinderMenu(ReagentGrinderBoundUserInterface owner, IEntityManager entityManager, IPrototypeManager prototypeManager)
+ {
+ RobustXamlLoader.Load(this);
+ _entityManager = entityManager;
+ _prototypeManager = prototypeManager;
+ _owner = owner;
+ GrindButton.OnPressed += owner.StartGrinding;
+ JuiceButton.OnPressed += owner.StartJuicing;
+ ChamberContentBox.EjectButton.OnPressed += owner.EjectAll;
+ BeakerContentBox.EjectButton.OnPressed += owner.EjectBeaker;
+ ChamberContentBox.BoxContents.OnItemSelected += OnChamberBoxContentsItemSelected;
+ BeakerContentBox.BoxContents.SelectMode = ItemList.ItemListSelectMode.None;
+ }
+
+ private void OnChamberBoxContentsItemSelected(ItemList.ItemListSelectedEventArgs args)
+ {
+ _owner.EjectChamberContent(_chamberVisualContents[args.ItemIndex]);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ _chamberVisualContents.Clear();
+ GrindButton.OnPressed -= _owner.StartGrinding;
+ JuiceButton.OnPressed -= _owner.StartJuicing;
+ ChamberContentBox.EjectButton.OnPressed -= _owner.EjectAll;
+ BeakerContentBox.EjectButton.OnPressed -= _owner.EjectBeaker;
+ ChamberContentBox.BoxContents.OnItemSelected -= OnChamberBoxContentsItemSelected;
+ }
+
+ public void UpdateState(ReagentGrinderInterfaceState state)
+ {
+ BeakerContentBox.EjectButton.Disabled = !state.HasBeakerIn;
+ ChamberContentBox.EjectButton.Disabled = state.ChamberContents.Length <= 0;
+ GrindButton.Disabled = !state.CanGrind || !state.Powered;
+ JuiceButton.Disabled = !state.CanJuice || !state.Powered;
+ RefreshContentsDisplay(state.ReagentQuantities, state.ChamberContents, state.HasBeakerIn);
+ }
+
+ public void HandleMessage(BoundUserInterfaceMessage message)
+ {
+ switch (message)
+ {
+ case SharedReagentGrinderComponent.ReagentGrinderWorkStartedMessage workStarted:
+ GrindButton.Disabled = true;
+ GrindButton.Modulate = workStarted.GrinderProgram == SharedReagentGrinderComponent.GrinderProgram.Grind ? Color.Green : Color.White;
+ JuiceButton.Disabled = true;
+ JuiceButton.Modulate = workStarted.GrinderProgram == SharedReagentGrinderComponent.GrinderProgram.Juice ? Color.Green : Color.White;
+ BeakerContentBox.EjectButton.Disabled = true;
+ ChamberContentBox.EjectButton.Disabled = true;
+ break;
+ case SharedReagentGrinderComponent.ReagentGrinderWorkCompleteMessage doneMessage:
+ GrindButton.Disabled = false;
+ JuiceButton.Disabled = false;
+ GrindButton.Modulate = Color.White;
+ JuiceButton.Modulate = Color.White;
+ BeakerContentBox.EjectButton.Disabled = false;
+ ChamberContentBox.EjectButton.Disabled = false;
+ break;
+ }
+ }
+
+ private void RefreshContentsDisplay(IList? reagents, IReadOnlyList containedSolids, bool isBeakerAttached)
+ {
+ //Refresh chamber contents
+ _chamberVisualContents.Clear();
+
+ ChamberContentBox.BoxContents.Clear();
+ foreach (var uid in containedSolids)
+ {
+ if (!_entityManager.TryGetEntity(uid, out var entity))
+ {
+ return;
+ }
+ var texture = entity.GetComponent().Icon?.Default;
+
+ var solidItem = ChamberContentBox.BoxContents.AddItem(entity.Name, texture);
+ var solidIndex = ChamberContentBox.BoxContents.IndexOf(solidItem);
+ _chamberVisualContents.Add(solidIndex, uid);
+ }
+
+ //Refresh beaker contents
+ BeakerContentBox.BoxContents.Clear();
+ //if no beaker is attached use this guard to prevent hitting a null reference.
+ if (!isBeakerAttached || reagents == null)
+ {
+ return;
+ }
+
+ //Looks like we have a beaker attached.
+ if (reagents.Count <= 0)
+ {
+ BeakerContentBox.BoxContents.AddItem(Loc.GetString("grinder-menu-beaker-content-box-is-empty"));
+ }
+ else
+ {
+ foreach (var reagent in reagents)
+ {
+ var reagentName = _prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype? proto) ? Loc.GetString($"{reagent.Quantity} {proto.Name}") : "???";
+ BeakerContentBox.BoxContents.AddItem(reagentName);
+ }
+ }
+ }
+ }
+}
diff --git a/Content.Client/Kitchen/UI/LabelledContentBox.xaml b/Content.Client/Kitchen/UI/LabelledContentBox.xaml
new file mode 100644
index 0000000000..d69e52e2a1
--- /dev/null
+++ b/Content.Client/Kitchen/UI/LabelledContentBox.xaml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Content.Client/Kitchen/UI/LabelledContentBox.xaml.cs b/Content.Client/Kitchen/UI/LabelledContentBox.xaml.cs
new file mode 100644
index 0000000000..b88f8fc4e3
--- /dev/null
+++ b/Content.Client/Kitchen/UI/LabelledContentBox.xaml.cs
@@ -0,0 +1,15 @@
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+
+namespace Content.Client.Kitchen.UI
+{
+ [GenerateTypedNameReferences]
+ public partial class LabelledContentBox : BoxContainer
+ {
+ public string? LabelText { get => Label.Text; set => Label.Text = value; }
+ public string? ButtonText { get => Button.Text; set => Button.Text = value; }
+
+ public ItemList BoxContents => ItemList;
+ public Button EjectButton => Button;
+ }
+}
diff --git a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs
index e33cae9e5e..c0398d7e6e 100644
--- a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs
+++ b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs
@@ -1,17 +1,10 @@
-using System.Collections.Generic;
-using Content.Shared.Chemistry.Reagent;
using Content.Shared.Kitchen.Components;
using Robust.Client.GameObjects;
-using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
-using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
-using Robust.Shared.Localization;
-using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using static Content.Shared.Chemistry.Solution.Solution;
-using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Kitchen.UI
{
@@ -21,8 +14,6 @@ namespace Content.Client.Kitchen.UI
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private GrinderMenu? _menu;
- private readonly Dictionary _chamberVisualContents = new();
- private readonly Dictionary _beakerVisualContents = new();
public ReagentGrinderBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) { }
@@ -30,22 +21,9 @@ namespace Content.Client.Kitchen.UI
{
base.Open();
- _menu = new GrinderMenu(this);
+ _menu = new GrinderMenu(this, _entityManager, _prototypeManager);
_menu.OpenCentered();
_menu.OnClose += Close;
- _menu.GrindButton.OnPressed += args => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderGrindStartMessage());
- _menu.JuiceButton.OnPressed += args => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderJuiceStartMessage());
- _menu.ChamberContentBox.EjectButton.OnPressed += args => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectChamberAllMessage());
- _menu.BeakerContentBox.EjectButton.OnPressed += args => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectBeakerMessage());
- _menu.ChamberContentBox.BoxContents.OnItemSelected += args =>
- {
- SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectChamberContentMessage(_chamberVisualContents[args.ItemIndex]));
- };
-
- _menu.BeakerContentBox.BoxContents.OnItemSelected += args =>
- {
- SendMessage(new SharedReagentGrinderComponent.ReagentGrinderVaporizeReagentIndexedMessage(_beakerVisualContents[args.ItemIndex]));
- };
}
protected override void Dispose(bool disposing)
@@ -56,8 +34,6 @@ namespace Content.Client.Kitchen.UI
return;
}
- _chamberVisualContents?.Clear();
- _beakerVisualContents?.Clear();
_menu?.Dispose();
}
@@ -69,243 +45,19 @@ namespace Content.Client.Kitchen.UI
return;
}
- if (_menu == null)
- {
- return;
- }
-
- _menu.BeakerContentBox.EjectButton.Disabled = !cState.HasBeakerIn;
- _menu.ChamberContentBox.EjectButton.Disabled = cState.ChamberContents.Length <= 0;
- _menu.GrindButton.Disabled = !cState.CanGrind || !cState.Powered;
- _menu.JuiceButton.Disabled = !cState.CanJuice || !cState.Powered;
- RefreshContentsDisplay(cState.ReagentQuantities, cState.ChamberContents, cState.HasBeakerIn);
+ _menu?.UpdateState(cState);
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
{
base.ReceiveMessage(message);
-
- if (_menu == null)
- {
- return;
- }
-
- switch (message)
- {
- case SharedReagentGrinderComponent.ReagentGrinderWorkStartedMessage workStarted:
- _menu.GrindButton.Disabled = true;
- _menu.GrindButton.Modulate = workStarted.GrinderProgram == SharedReagentGrinderComponent.GrinderProgram.Grind ? Color.Green : Color.White;
- _menu.JuiceButton.Disabled = true;
- _menu.JuiceButton.Modulate = workStarted.GrinderProgram == SharedReagentGrinderComponent.GrinderProgram.Juice ? Color.Green : Color.White;
- _menu.BeakerContentBox.EjectButton.Disabled = true;
- _menu.ChamberContentBox.EjectButton.Disabled = true;
- break;
- case SharedReagentGrinderComponent.ReagentGrinderWorkCompleteMessage doneMessage:
- _menu.GrindButton.Disabled = false;
- _menu.JuiceButton.Disabled = false;
- _menu.GrindButton.Modulate = Color.White;
- _menu.JuiceButton.Modulate = Color.White;
- _menu.BeakerContentBox.EjectButton.Disabled = false;
- _menu.ChamberContentBox.EjectButton.Disabled = false;
- break;
- }
+ _menu?.HandleMessage(message);
}
- private void RefreshContentsDisplay(IList? reagents, IReadOnlyList containedSolids, bool isBeakerAttached)
- {
- //Refresh chamber contents
- _chamberVisualContents.Clear();
-
- if (_menu == null)
- {
- return;
- }
-
- _menu.ChamberContentBox.BoxContents.Clear();
- foreach (var uid in containedSolids)
- {
- if (!_entityManager.TryGetEntity(uid, out var entity))
- {
- return;
- }
- var texture = entity.GetComponent().Icon?.Default;
-
- var solidItem = _menu.ChamberContentBox.BoxContents.AddItem(entity.Name, texture);
- var solidIndex = _menu.ChamberContentBox.BoxContents.IndexOf(solidItem);
- _chamberVisualContents.Add(solidIndex, uid);
- }
-
- //Refresh beaker contents
- _beakerVisualContents.Clear();
- _menu.BeakerContentBox.BoxContents.Clear();
- //if no beaker is attached use this guard to prevent hitting a null reference.
- if (!isBeakerAttached || reagents == null)
- {
- return;
- }
-
- //Looks like we have a beaker attached.
- if (reagents.Count <= 0)
- {
- _menu.BeakerContentBox.BoxContents.AddItem(Loc.GetString("grinder-menu-beaker-content-box-is-empty"));
- }
- else
- {
- for (var i = 0; i < reagents.Count; i++)
- {
- var goodIndex = _prototypeManager.TryIndex(reagents[i].ReagentId, out ReagentPrototype? proto);
- var reagentName = goodIndex ? Loc.GetString($"{reagents[i].Quantity} {proto!.Name}") : "???";
- var reagentAdded = _menu.BeakerContentBox.BoxContents.AddItem(reagentName);
- var reagentIndex = _menu.BeakerContentBox.BoxContents.IndexOf(reagentAdded);
- _beakerVisualContents.Add(reagentIndex, reagents[i]);
- }
- }
- }
-
- public class GrinderMenu : SS14Window
- {
- /*The contents of the chamber and beaker will both be vertical scroll rectangles.
- * Will have a vsplit to split the g/j buttons from the contents menu.
- * |--------------------------------\
- * | | Chamber [E] Beaker [E] |
- * | [G] | | | | | |
- * | | | | | | |
- * | | | | | | |
- * | [J] | |-----| |-----| |
- * | | |
- * \---------------------------------/
- *
- */
-
- private ReagentGrinderBoundUserInterface Owner { get; set; }
-
- //We'll need 4 buttons, grind, juice, eject beaker, eject the chamber contents.
- //The other 2 are referenced in the Open function.
- public Button GrindButton { get; }
- public Button JuiceButton { get; }
-
- public LabelledContentBox ChamberContentBox { get; }
- public LabelledContentBox BeakerContentBox { get; }
-
- public sealed class LabelledContentBox : VBoxContainer
- {
- public string? LabelText { get; set; }
-
- public ItemList BoxContents { get; set; }
-
- public Button EjectButton { get; set; }
-
- private Label _label;
-
- public LabelledContentBox(string labelText, string buttonText)
- {
- _label = new Label
- {
- Text = labelText,
- Align = Label.AlignMode.Center,
- };
-
- EjectButton = new Button
- {
- Text = buttonText,
- TextAlign = Label.AlignMode.Center,
- };
-
- var vSplit = new HSplitContainer
- {
- Children =
- {
- _label,
- EjectButton
- }
- };
-
- AddChild(vSplit);
- BoxContents = new ItemList
- {
- VerticalExpand = true,
- HorizontalExpand = true,
- SelectMode = ItemList.ItemListSelectMode.Button,
- SizeFlagsStretchRatio = 2,
- MinSize = (100, 128)
- };
- AddChild(BoxContents);
- }
- }
-
- public GrinderMenu(ReagentGrinderBoundUserInterface owner)
- {
- SetSize = MinSize = (512, 256);
- Owner = owner;
- Title = Loc.GetString("grinder-menu-title");
-
- var hSplit = new BoxContainer
- {
- Orientation = LayoutOrientation.Horizontal
- };
-
- var vBoxGrindJuiceButtonPanel = new BoxContainer
- {
- Orientation = LayoutOrientation.Vertical,
- VerticalAlignment = VAlignment.Center
- };
-
- GrindButton = new Button
- {
- Text = Loc.GetString("grinder-menu-grind-button"),
- TextAlign = Label.AlignMode.Center,
- MinSize = (64, 64)
- };
-
- JuiceButton = new Button
- {
- Text = Loc.GetString("grinder-menu-juice-button"),
- TextAlign = Label.AlignMode.Center,
- MinSize = (64, 64)
- };
-
- vBoxGrindJuiceButtonPanel.AddChild(GrindButton);
- //inner button padding
- vBoxGrindJuiceButtonPanel.AddChild(new Control
- {
- MinSize = (0, 16),
- });
- vBoxGrindJuiceButtonPanel.AddChild(JuiceButton);
-
- ChamberContentBox = new LabelledContentBox(Loc.GetString("grinder-menu-chamber-content-box-label"), Loc.GetString("grinder-menu-chamber-content-box-button"))
- {
- //Modulate = Color.Red,
- VerticalExpand = true,
- HorizontalExpand = true,
- SizeFlagsStretchRatio = 2,
-
- };
-
- BeakerContentBox = new LabelledContentBox(Loc.GetString("grinder-menu-beaker-content-box-label"), Loc.GetString("grinder-menu-beaker-content-box-button"))
- {
- //Modulate = Color.Blue,
- VerticalExpand = true,
- HorizontalExpand = true,
- SizeFlagsStretchRatio = 2,
- };
-
- hSplit.AddChild(vBoxGrindJuiceButtonPanel);
-
- //Padding between the g/j buttons panel and the itemlist boxes panel.
- hSplit.AddChild(new Control
- {
- MinSize = (16, 0),
- });
- hSplit.AddChild(ChamberContentBox);
-
- //Padding between the two itemlists.
- hSplit.AddChild(new Control
- {
- MinSize = (8, 0),
- });
- hSplit.AddChild(BeakerContentBox);
- Contents.AddChild(hSplit);
- }
- }
+ public void StartGrinding(BaseButton.ButtonEventArgs? args = null) => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderGrindStartMessage());
+ public void StartJuicing(BaseButton.ButtonEventArgs? args = null) => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderJuiceStartMessage());
+ public void EjectAll(BaseButton.ButtonEventArgs? args = null) => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectChamberAllMessage());
+ public void EjectBeaker(BaseButton.ButtonEventArgs? args = null) => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectBeakerMessage());
+ public void EjectChamberContent(EntityUid uid) => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectChamberContentMessage(uid));
}
}
diff --git a/Content.Client/Nutrition/Visualizers/DrinkFoodContainerVisualizer.cs b/Content.Client/Nutrition/Visualizers/DrinkFoodContainerVisualizer.cs
deleted file mode 100644
index 5117ebe5e2..0000000000
--- a/Content.Client/Nutrition/Visualizers/DrinkFoodContainerVisualizer.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System;
-using Content.Shared.Nutrition.Components;
-using Content.Shared.Rounding;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.Serialization.Manager.Attributes;
-
-namespace Content.Client.Nutrition.Visualizers
-{
- [UsedImplicitly]
- public sealed class FoodContainerVisualizer : AppearanceVisualizer
- {
- [DataField("base_state", required: true)]
- private string? _baseState;
-
- [DataField("steps", required: true)]
- private int _steps;
-
- [DataField("mode")]
- private FoodContainerVisualMode _mode = FoodContainerVisualMode.Rounded;
-
- public override void OnChangeData(AppearanceComponent component)
- {
- var sprite = component.Owner.GetComponent();
-
- if (!component.TryGetData(FoodContainerVisuals.Current, out var current))
- {
- return;
- }
-
- if (!component.TryGetData(FoodContainerVisuals.Capacity, out var capacity))
- {
- return;
- }
-
- int step;
-
- switch (_mode)
- {
- case FoodContainerVisualMode.Discrete:
- step = Math.Min(_steps - 1, current);
- break;
- case FoodContainerVisualMode.Rounded:
- step = ContentHelpers.RoundToLevels(current, capacity, _steps);
- break;
- default:
- throw new NullReferenceException();
- }
-
- sprite.LayerSetState(0, $"{_baseState}-{step}");
- }
- }
-}
diff --git a/Content.Client/Storage/Visualizers/StorageVisualizer.cs b/Content.Client/Storage/Visualizers/StorageVisualizer.cs
index 7b7aaf28c4..43a8df5684 100644
--- a/Content.Client/Storage/Visualizers/StorageVisualizer.cs
+++ b/Content.Client/Storage/Visualizers/StorageVisualizer.cs
@@ -1,4 +1,4 @@
-using Content.Shared.Storage;
+using Content.Shared.Storage;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
diff --git a/Content.Client/UserInterface/ButtonHelpers.cs b/Content.Client/UserInterface/ButtonHelpers.cs
new file mode 100644
index 0000000000..38abc8684c
--- /dev/null
+++ b/Content.Client/UserInterface/ButtonHelpers.cs
@@ -0,0 +1,31 @@
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+
+namespace Content.Client.UserInterface
+{
+ public static class ButtonHelpers
+ {
+ ///
+ /// This searches recursively through all the children of "parent"
+ /// and sets the Disabled value of any buttons found to "val"
+ ///
+ /// The control which childrens get searched
+ /// The value to which disabled gets set
+ public static void SetButtonDisabledRecursive(Control parent, bool val)
+ {
+ foreach (var child in parent.Children)
+ {
+ if (child is Button but)
+ {
+ but.Disabled = val;
+ continue;
+ }
+
+ if (child.ChildCount > 0)
+ {
+ SetButtonDisabledRecursive(child, val);
+ }
+ }
+ }
+ }
+}
diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
index d793e3c501..0253c71f76 100644
--- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
+++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs
@@ -18,6 +18,7 @@ namespace Content.Client.Weapons.Melee
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly EffectSystem _effectSystem = default!;
public override void Initialize()
{
@@ -67,7 +68,6 @@ namespace Content.Client.Weapons.Melee
source.TryGetComponent(out ISpriteComponent? sourceSprite) &&
sourceSprite.BaseRSI?.Path != null)
{
- var sys = Get();
var curTime = _gameTiming.CurTime;
var effect = new EffectSystemMessage
{
@@ -81,7 +81,8 @@ namespace Content.Client.Weapons.Melee
Born = curTime,
DeathTime = curTime.Add(TimeSpan.FromMilliseconds(300f)),
};
- sys.CreateEffect(effect);
+
+ _effectSystem.CreateEffect(effect);
}
}
diff --git a/Content.Client/Weapons/Ranged/RangedWeaponSystem.cs b/Content.Client/Weapons/Ranged/RangedWeaponSystem.cs
index 85de5e4d55..38ffb63802 100644
--- a/Content.Client/Weapons/Ranged/RangedWeaponSystem.cs
+++ b/Content.Client/Weapons/Ranged/RangedWeaponSystem.cs
@@ -24,21 +24,12 @@ namespace Content.Client.Weapons.Ranged
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly InputSystem _inputSystem = default!;
+ [Dependency] private readonly CombatModeSystem _combatModeSystem = default!;
- private InputSystem _inputSystem = default!;
- private CombatModeSystem _combatModeSystem = default!;
private bool _blocked;
private int _shotCounter;
- public override void Initialize()
- {
- base.Initialize();
-
- IoCManager.InjectDependencies(this);
- _inputSystem = Get();
- _combatModeSystem = Get();
- }
-
public override void Update(float frameTime)
{
base.Update(frameTime);
diff --git a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs
new file mode 100644
index 0000000000..9587897442
--- /dev/null
+++ b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs
@@ -0,0 +1,77 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Content.Server.Chemistry.Components;
+using Content.Server.Fluids.Components;
+using Content.Shared.Chemistry.Reaction;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Coordinates;
+using NUnit.Framework;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Timing;
+using Robust.Shared.Utility;
+
+namespace Content.IntegrationTests.Tests.Chemistry
+{
+ [TestFixture]
+ [TestOf(typeof(ReactionPrototype))]
+ public class TryAllReactionsTest : ContentIntegrationTest
+ {
+ [Test]
+ public async Task TryAllTest()
+ {
+ var server = StartServerDummyTicker();
+
+ await server.WaitIdleAsync();
+
+ var mapManager = server.ResolveDependency();
+ var entityManager = server.ResolveDependency();
+ var prototypeManager = server.ResolveDependency();
+
+ foreach (var reactionPrototype in prototypeManager.EnumeratePrototypes())
+ {
+ //since i have no clue how to isolate each loop assert-wise im just gonna throw this one in for good measure
+ Console.WriteLine($"Testing {reactionPrototype.ID}");
+
+ IEntity beaker;
+ SolutionContainerComponent component = null;
+
+ server.Assert(() =>
+ {
+ mapManager.CreateNewMapEntity(MapId.Nullspace);
+
+ beaker = entityManager.SpawnEntity("BluespaceBeaker", MapCoordinates.Nullspace);
+ Assert.That(beaker.TryGetComponent(out component));
+ foreach (var (id, reactant) in reactionPrototype.Reactants)
+ {
+ Assert.That(component.TryAddReagent(id, reactant.Amount, out var quantity));
+ Assert.That(reactant.Amount, Is.EqualTo(quantity));
+ }
+ });
+
+ await server.WaitIdleAsync();
+
+ server.Assert(() =>
+ {
+ //you just got linq'd fool
+ //(i'm sorry)
+ var foundProductsMap = reactionPrototype.Products
+ .Concat(reactionPrototype.Reactants.Where(x => x.Value.Catalyst).ToDictionary(x => x.Key, x => x.Value.Amount))
+ .ToDictionary(x => x, x => false);
+ foreach (var reagent in component.Solution.Contents)
+ {
+ Assert.That(foundProductsMap.TryFirstOrNull(x => x.Key.Key == reagent.ReagentId && x.Key.Value == reagent.Quantity, out var foundProduct));
+ foundProductsMap[foundProduct.Value.Key] = true;
+ }
+
+ Assert.That(foundProductsMap.All(x => x.Value));
+ });
+ }
+
+ }
+ }
+
+}
diff --git a/Content.Server/AI/Pathfinding/Accessible/AiReachableSystem.cs b/Content.Server/AI/Pathfinding/Accessible/AiReachableSystem.cs
index 5f66ec5e2e..64791ce9ff 100644
--- a/Content.Server/AI/Pathfinding/Accessible/AiReachableSystem.cs
+++ b/Content.Server/AI/Pathfinding/Accessible/AiReachableSystem.cs
@@ -37,8 +37,7 @@ namespace Content.Server.AI.Pathfinding.Accessible
*/
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
-
- private PathfindingSystem _pathfindingSystem = default!;
+ [Dependency] private readonly PathfindingSystem _pathfindingSystem = default!;
///
/// Queued region updates
@@ -80,7 +79,6 @@ namespace Content.Server.AI.Pathfinding.Accessible
public override void Initialize()
{
- _pathfindingSystem = Get();
SubscribeLocalEvent(Reset);
SubscribeLocalEvent(RecalculateNodeRegions);
#if DEBUG
diff --git a/Content.Server/AI/Steering/AiSteeringSystem.cs b/Content.Server/AI/Steering/AiSteeringSystem.cs
index 7db0a97349..b7e1e468c6 100644
--- a/Content.Server/AI/Steering/AiSteeringSystem.cs
+++ b/Content.Server/AI/Steering/AiSteeringSystem.cs
@@ -27,8 +27,7 @@ namespace Content.Server.AI.Steering
// http://www.red3d.com/cwr/papers/1999/gdc99steer.html for a steering overview
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPauseManager _pauseManager = default!;
-
- private PathfindingSystem _pathfindingSystem = default!;
+ [Dependency] private readonly PathfindingSystem _pathfindingSystem = default!;
///
/// Whether we try to avoid non-blocking physics objects
@@ -87,7 +86,6 @@ namespace Content.Server.AI.Steering
public override void Initialize()
{
base.Initialize();
- _pathfindingSystem = Get();
for (var i = 0; i < AgentListCount; i++)
{
diff --git a/Content.Server/Atmos/EntityNetworkUtils.cs b/Content.Server/Atmos/EntityNetworkUtils.cs
deleted file mode 100644
index 7b1671b6e6..0000000000
--- a/Content.Server/Atmos/EntityNetworkUtils.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using Robust.Shared.Maths;
-
-namespace Content.Server.Atmos
-{
- public static class EntityNetworkUtils
- {
- public static Vector2i CardinalToIntVec(this Direction dir)
- {
- switch (dir)
- {
- case Direction.North:
- return new Vector2i(0, 1);
- case Direction.East:
- return new Vector2i(1, 0);
- case Direction.South:
- return new Vector2i(0, -1);
- case Direction.West:
- return new Vector2i(-1, 0);
- default:
- throw new ArgumentException($"Direction dir {dir} is not a cardinal direction", nameof(dir));
- }
- }
-
- public static Vector2i Offset(this Vector2i pos, Direction dir)
- {
- return pos + (Vector2i) dir.CardinalToIntVec();
- }
- }
-}
diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
index a1fea661a1..b3b0d4dd5a 100644
--- a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs
@@ -12,6 +12,7 @@ namespace Content.Server.Atmos.EntitySystems
public class AirtightSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
public override void Initialize()
{
@@ -42,7 +43,7 @@ namespace Content.Server.Atmos.EntitySystems
if (airtight.FixVacuum)
{
- Get().FixVacuum(airtight.LastPosition.Item1, airtight.LastPosition.Item2);
+ _atmosphereSystem.FixVacuum(airtight.LastPosition.Item1, airtight.LastPosition.Item2);
}
}
@@ -93,9 +94,8 @@ namespace Content.Server.Atmos.EntitySystems
if (!gridId.IsValid())
return;
- var atmosphereSystem = Get();
- atmosphereSystem.UpdateAdjacent(gridId, pos);
- atmosphereSystem.InvalidateTile(gridId, pos);
+ _atmosphereSystem.UpdateAdjacent(gridId, pos);
+ _atmosphereSystem.InvalidateTile(gridId, pos);
}
private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle)
diff --git a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
index 87a9bc0952..d28ac4324f 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs
@@ -21,6 +21,7 @@ namespace Content.Server.Atmos.EntitySystems
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
///
/// Players allowed to see the atmos debug overlay.
@@ -127,7 +128,6 @@ namespace Content.Server.Atmos.EntitySystems
AccumulatedFrameTime -= _updateCooldown;
var currentTick = _gameTiming.CurTick;
- var atmosphereSystem = Get();
// Now we'll go through each player, then through each chunk in range of that player checking if the player is still in range
// If they are, check if they need the new data to send (i.e. if there's an overlay for the gas).
@@ -157,7 +157,7 @@ namespace Content.Server.Atmos.EntitySystems
for (var x = 0; x < LocalViewRange; x++)
{
var Vector2i = new Vector2i(baseTile.X + x, baseTile.Y + y);
- debugOverlayContent[index++] = ConvertTileToData(atmosphereSystem.GetTileAtmosphereOrCreateSpace(grid, gam, Vector2i));
+ debugOverlayContent[index++] = ConvertTileToData(_atmosphereSystem.GetTileAtmosphereOrCreateSpace(grid, gam, Vector2i));
}
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs
index 4693761b33..df9fbd7c1e 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs
@@ -15,6 +15,7 @@ namespace Content.Server.Atmos.EntitySystems
public bool MonstermosRipTiles { get; private set; }
public bool GridImpulse { get; private set; }
public bool Superconduction { get; private set; }
+ public bool ExcitedGroups { get; private set; }
public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; }
public float AtmosMaxProcessTime { get; private set; }
public float AtmosTickRate { get; private set; }
@@ -31,6 +32,7 @@ namespace Content.Server.Atmos.EntitySystems
_cfg.OnValueChanged(CCVars.Superconduction, value => Superconduction = value, true);
_cfg.OnValueChanged(CCVars.AtmosMaxProcessTime, value => AtmosMaxProcessTime = value, true);
_cfg.OnValueChanged(CCVars.AtmosTickRate, value => AtmosTickRate = value, true);
+ _cfg.OnValueChanged(CCVars.ExcitedGroups, value => ExcitedGroups = value, true);
_cfg.OnValueChanged(CCVars.ExcitedGroupsSpaceIsAllConsuming, value => ExcitedGroupsSpaceIsAllConsuming = value, true);
}
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
index ba11dd0740..16469a0a58 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs
@@ -42,13 +42,6 @@ namespace Content.Server.Atmos.EntitySystems
return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity);
}
- public float GetHeatCapacityArchived(GasMixture mixture)
- {
- Span tmp = stackalloc float[mixture.Moles.Length];
- NumericsHelpers.Multiply(mixture.MolesArchived, GasSpecificHeats, tmp);
- return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity);
- }
-
public float GetThermalEnergy(GasMixture mixture)
{
return mixture.Temperature * GetHeatCapacity(mixture);
@@ -79,7 +72,7 @@ namespace Content.Server.Atmos.EntitySystems
public float Share(GasMixture receiver, GasMixture sharer, int atmosAdjacentTurfs)
{
- var temperatureDelta = receiver.TemperatureArchived - sharer.TemperatureArchived;
+ var temperatureDelta = receiver.Temperature - sharer.Temperature;
var absTemperatureDelta = Math.Abs(temperatureDelta);
var oldHeatCapacity = 0f;
var oldSharerHeatCapacity = 0f;
@@ -130,12 +123,12 @@ namespace Content.Server.Atmos.EntitySystems
// Transfer of thermal energy (via changed heat capacity) between self and sharer.
if (!receiver.Immutable && newHeatCapacity > Atmospherics.MinimumHeatCapacity)
{
- receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * receiver.TemperatureArchived) + (heatCapacitySharerToThis * sharer.TemperatureArchived)) / newHeatCapacity;
+ receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * receiver.Temperature) + (heatCapacitySharerToThis * sharer.Temperature)) / newHeatCapacity;
}
if (!sharer.Immutable && newSharerHeatCapacity > Atmospherics.MinimumHeatCapacity)
{
- sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * sharer.TemperatureArchived) + (heatCapacityToSharer*receiver.TemperatureArchived)) / newSharerHeatCapacity;
+ sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * sharer.Temperature) + (heatCapacityToSharer*receiver.Temperature)) / newSharerHeatCapacity;
}
// Thermal energy of the system (self and sharer) is unchanged.
@@ -154,17 +147,17 @@ namespace Content.Server.Atmos.EntitySystems
var moles = receiver.TotalMoles;
var theirMoles = sharer.TotalMoles;
- return (receiver.TemperatureArchived * (moles + movedMoles)) - (sharer.TemperatureArchived * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume;
+ return (receiver.Temperature * (moles + movedMoles)) - (sharer.Temperature * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume;
}
public float TemperatureShare(GasMixture receiver, GasMixture sharer, float conductionCoefficient)
{
- var temperatureDelta = receiver.TemperatureArchived - sharer.TemperatureArchived;
+ var temperatureDelta = receiver.Temperature - sharer.Temperature;
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
{
- var heatCapacity = GetHeatCapacityArchived(receiver);
- var sharerHeatCapacity = GetHeatCapacityArchived(sharer);
+ var heatCapacity = GetHeatCapacity(receiver);
+ var sharerHeatCapacity = GetHeatCapacity(sharer);
if (sharerHeatCapacity > Atmospherics.MinimumHeatCapacity && heatCapacity > Atmospherics.MinimumHeatCapacity)
{
@@ -183,10 +176,10 @@ namespace Content.Server.Atmos.EntitySystems
public float TemperatureShare(GasMixture receiver, float conductionCoefficient, float sharerTemperature, float sharerHeatCapacity)
{
- var temperatureDelta = receiver.TemperatureArchived - sharerTemperature;
+ var temperatureDelta = receiver.Temperature - sharerTemperature;
if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider)
{
- var heatCapacity = GetHeatCapacityArchived(receiver);
+ var heatCapacity = GetHeatCapacity(receiver);
if (sharerHeatCapacity > Atmospherics.MinimumHeatCapacity && heatCapacity > Atmospherics.MinimumHeatCapacity)
{
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs
index 41424c990a..661b5b169f 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs
@@ -23,13 +23,10 @@ namespace Content.Server.Atmos.EntitySystems
public partial class AtmosphereSystem
{
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
-
- private GasTileOverlaySystem _gasTileOverlaySystem = default!;
+ [Dependency] private readonly GasTileOverlaySystem _gasTileOverlaySystem = default!;
private void InitializeGrid()
{
- _gasTileOverlaySystem = Get();
-
SubscribeLocalEvent(OnGridAtmosphereInit);
}
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
index 1fbb4f0c7d..df78bc015d 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs
@@ -108,10 +108,11 @@ namespace Content.Server.Atmos.EntitySystems
{
Volume = exposedVolume * 25f,
Temperature = exposedTemperature,
- SkippedFirstProcess = tile.CurrentCycle > gridAtmosphere.UpdateCounter
+ SkippedFirstProcess = tile.CurrentCycle > gridAtmosphere.UpdateCounter,
+ Valid = true,
+ State = 1
};
- tile.Hotspot.Start();
AddActiveTile(gridAtmosphere, tile);
gridAtmosphere.HotspotTiles.Add(tile);
@@ -139,7 +140,7 @@ namespace Content.Server.Atmos.EntitySystems
Merge(tile.Air, affected);
}
- var tileRef = tile.GridIndices.GetTileRef(tile.GridIndex);
+ var tileRef = tile.GridIndices.GetTileRef(tile.GridIndex, _mapManager);
foreach (var entity in tileRef.GetEntitiesInTileFast())
{
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs
index 93b73458b1..2629bb4d33 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs
@@ -16,9 +16,6 @@ namespace Content.Server.Atmos.EntitySystems
return;
}
- if (tile.ArchivedCycle < fireCount)
- Archive(tile, fireCount);
-
tile.CurrentCycle = fireCount;
var adjacentTileLength = 0;
@@ -38,11 +35,10 @@ namespace Content.Server.Atmos.EntitySystems
// If the tile is null or has no air, we don't do anything for it.
if(enemyTile?.Air == null) continue;
if (fireCount <= enemyTile.CurrentCycle) continue;
- Archive(enemyTile, fireCount);
var shouldShareAir = false;
- if (tile.ExcitedGroup != null && enemyTile.ExcitedGroup != null)
+ if (ExcitedGroups && tile.ExcitedGroup != null && enemyTile.ExcitedGroup != null)
{
if (tile.ExcitedGroup != enemyTile.ExcitedGroup)
{
@@ -57,21 +53,24 @@ namespace Content.Server.Atmos.EntitySystems
AddActiveTile(gridAtmosphere, enemyTile);
}
- var excitedGroup = tile.ExcitedGroup;
- excitedGroup ??= enemyTile.ExcitedGroup;
-
- if (excitedGroup == null)
+ if (ExcitedGroups)
{
- excitedGroup = new ExcitedGroup();
- gridAtmosphere.ExcitedGroups.Add(excitedGroup);
+ var excitedGroup = tile.ExcitedGroup;
+ excitedGroup ??= enemyTile.ExcitedGroup;
+
+ if (excitedGroup == null)
+ {
+ excitedGroup = new ExcitedGroup();
+ gridAtmosphere.ExcitedGroups.Add(excitedGroup);
+ }
+
+ if (tile.ExcitedGroup == null)
+ ExcitedGroupAddTile(excitedGroup, tile);
+
+ if(enemyTile.ExcitedGroup == null)
+ ExcitedGroupAddTile(excitedGroup, enemyTile);
}
- if (tile.ExcitedGroup == null)
- ExcitedGroupAddTile(excitedGroup, tile);
-
- if(enemyTile.ExcitedGroup == null)
- ExcitedGroupAddTile(excitedGroup, enemyTile);
-
shouldShareAir = true;
}
@@ -106,17 +105,10 @@ namespace Content.Server.Atmos.EntitySystems
if (ConsiderSuperconductivity(gridAtmosphere, tile, true))
remove = false;
- if(tile.ExcitedGroup == null && remove)
+ if(ExcitedGroups && tile.ExcitedGroup == null && remove)
RemoveActiveTile(gridAtmosphere, tile);
}
- private void Archive(TileAtmosphere tile, int fireCount)
- {
- tile.Air?.Archive();
- tile.ArchivedCycle = fireCount;
- tile.TemperatureArchived = tile.Temperature;
- }
-
private void LastShareCheck(TileAtmosphere tile)
{
if (tile.Air == null || tile.ExcitedGroup == null)
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs
index 184e0bf9f5..db87ed7c10 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs
@@ -281,7 +281,8 @@ namespace Content.Server.Atmos.EntitySystems
}
atmosphere.ProcessingPaused = false;
- atmosphere.State = AtmosphereProcessingState.ExcitedGroups;
+ // Next state depends on whether excited groups are enabled or not.
+ atmosphere.State = ExcitedGroups ? AtmosphereProcessingState.ExcitedGroups : AtmosphereProcessingState.HighPressureDelta;
continue;
case AtmosphereProcessingState.ExcitedGroups:
if (!ProcessExcitedGroups(atmosphere))
diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs
index 2853a6934e..fe21db69d4 100644
--- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs
+++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs
@@ -21,9 +21,6 @@ namespace Content.Server.Atmos.EntitySystems
if (adjacent == null || adjacent.ThermalConductivity == 0f)
continue;
- if(adjacent.ArchivedCycle < gridAtmosphere.UpdateCounter)
- Archive(adjacent, gridAtmosphere.UpdateCounter);
-
NeighborConductWithSource(gridAtmosphere, adjacent, tile);
ConsiderSuperconductivity(gridAtmosphere, adjacent);
@@ -37,8 +34,6 @@ namespace Content.Server.Atmos.EntitySystems
{
if(tile.Air == null)
{
- if(tile.ArchivedCycle < gridAtmosphere.UpdateCounter)
- Archive(tile, gridAtmosphere.UpdateCounter);
return AtmosDirection.All;
}
@@ -128,7 +123,7 @@ namespace Content.Server.Atmos.EntitySystems
private void TemperatureShareMutualSolid(TileAtmosphere tile, TileAtmosphere other, float conductionCoefficient)
{
- var deltaTemperature = (tile.TemperatureArchived - other.TemperatureArchived);
+ var deltaTemperature = (tile.Temperature - other.Temperature);
if (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider
&& tile.HeatCapacity != 0f && other.HeatCapacity != 0f)
{
@@ -146,7 +141,7 @@ namespace Content.Server.Atmos.EntitySystems
if (tile.Temperature > Atmospherics.T0C)
{
// Hardcoded space temperature.
- var deltaTemperature = (tile.TemperatureArchived - Atmospherics.TCMB);
+ var deltaTemperature = (tile.Temperature - Atmospherics.TCMB);
if ((tile.HeatCapacity > 0) && (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider))
{
var heat = tile.ThermalConductivity * deltaTemperature * (tile.HeatCapacity *
diff --git a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs
index 2d3da529e9..0cebc10603 100644
--- a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs
+++ b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs
@@ -1,12 +1,15 @@
using Content.Server.Atmos.Components;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.Atmos.EntitySystems
{
[UsedImplicitly]
public class GasTankSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
private const float TimerDelay = 0.5f;
private float _timer = 0f;
@@ -19,11 +22,9 @@ namespace Content.Server.Atmos.EntitySystems
if (_timer < TimerDelay) return;
_timer -= TimerDelay;
- var atmosphereSystem = Get();
-
foreach (var gasTank in EntityManager.ComponentManager.EntityQuery())
{
- atmosphereSystem.React(gasTank.Air, gasTank);
+ _atmosphereSystem.React(gasTank.Air, gasTank);
gasTank.CheckStatus();
gasTank.UpdateUserInterface();
}
diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs
index 3a24573cc3..ee9d880ca7 100644
--- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs
+++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs
@@ -29,6 +29,7 @@ namespace Content.Server.Atmos.EntitySystems
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
///
/// The tiles that have had their atmos data updated since last tick
@@ -58,8 +59,6 @@ namespace Content.Server.Atmos.EntitySystems
///
private float _updateCooldown;
- private AtmosphereSystem _atmosphereSystem = default!;
-
private int _thresholds;
public override void Initialize()
@@ -68,7 +67,6 @@ namespace Content.Server.Atmos.EntitySystems
SubscribeLocalEvent(Reset);
- _atmosphereSystem = Get();
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
_mapManager.OnGridRemoved += OnGridRemoved;
var configManager = IoCManager.Resolve();
diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs
index dddad7366f..f4d013b2ab 100644
--- a/Content.Server/Atmos/GasMixture.cs
+++ b/Content.Server/Atmos/GasMixture.cs
@@ -26,9 +26,6 @@ namespace Content.Server.Atmos
[DataField("moles")] [ViewVariables]
public float[] Moles = new float[Atmospherics.AdjustedNumberOfGases];
- [DataField("molesArchived")] [ViewVariables]
- public float[] MolesArchived = new float[Atmospherics.AdjustedNumberOfGases];
-
[DataField("temperature")] [ViewVariables]
private float _temperature = Atmospherics.TCMB;
@@ -73,9 +70,6 @@ namespace Content.Server.Atmos
}
}
- [DataField("temperatureArchived")] [ViewVariables]
- public float TemperatureArchived { get; private set; }
-
[DataField("volume")] [ViewVariables]
public float Volume { get; set; }
@@ -96,13 +90,6 @@ namespace Content.Server.Atmos
Immutable = true;
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Archive()
- {
- Moles.AsSpan().CopyTo(MolesArchived.AsSpan());
- TemperatureArchived = Temperature;
- }
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float GetMoles(int gasId)
{
@@ -253,7 +240,6 @@ namespace Content.Server.Atmos
{
// The arrays MUST have a specific length.
Array.Resize(ref Moles, Atmospherics.AdjustedNumberOfGases);
- Array.Resize(ref MolesArchived, Atmospherics.AdjustedNumberOfGases);
}
public override bool Equals(object? obj)
@@ -268,12 +254,10 @@ namespace Content.Server.Atmos
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Moles.SequenceEqual(other.Moles)
- && MolesArchived.SequenceEqual(other.MolesArchived)
&& _temperature.Equals(other._temperature)
&& ReactionResults.SequenceEqual(other.ReactionResults)
&& Immutable == other.Immutable
&& LastShare.Equals(other.LastShare)
- && TemperatureArchived.Equals(other.TemperatureArchived)
&& Volume.Equals(other.Volume);
}
@@ -284,13 +268,10 @@ namespace Content.Server.Atmos
for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
{
var moles = Moles[i];
- var molesArchived = MolesArchived[i];
hashCode.Add(moles);
- hashCode.Add(molesArchived);
}
hashCode.Add(_temperature);
- hashCode.Add(TemperatureArchived);
hashCode.Add(Immutable);
hashCode.Add(LastShare);
hashCode.Add(Volume);
@@ -303,11 +284,9 @@ namespace Content.Server.Atmos
var newMixture = new GasMixture()
{
Moles = (float[])Moles.Clone(),
- MolesArchived = (float[])MolesArchived.Clone(),
_temperature = _temperature,
Immutable = Immutable,
LastShare = LastShare,
- TemperatureArchived = TemperatureArchived,
Volume = Volume,
};
return newMixture;
diff --git a/Content.Server/Atmos/Hotspot.cs b/Content.Server/Atmos/Hotspot.cs
index 4597813c6f..36d24c03b3 100644
--- a/Content.Server/Atmos/Hotspot.cs
+++ b/Content.Server/Atmos/Hotspot.cs
@@ -24,11 +24,5 @@ namespace Content.Server.Atmos
///
[ViewVariables]
public byte State;
-
- public void Start()
- {
- Valid = true;
- State = 1;
- }
}
}
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs
index 0782523559..78205ef201 100644
--- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs
@@ -10,12 +10,15 @@ using Content.Shared.Atmos.Visuals;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.Atmos.Piping.Binary.EntitySystems
{
[UsedImplicitly]
public class GasDualPortVentPumpSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -34,24 +37,23 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
return;
}
- appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
-
- if (!vent.Enabled)
- return;
-
- if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
- return;
-
- if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet)
+ if (!vent.Enabled
+ || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet)
|| !nodeContainer.TryGetNode(vent.OutletName, out PipeNode? outlet))
+ {
+ appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
return;
+ }
- var atmosphereSystem = Get();
- var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true);
+ var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true);
// We're in an air-blocked tile... Do nothing.
if (environment == null)
+ {
+ appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
return;
+ }
if (vent.PumpDirection == VentPumpDirection.Releasing)
{
@@ -68,7 +70,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
{
var transferMoles = pressureDelta * environment.Volume / inlet.Air.Temperature * Atmospherics.R;
var removed = inlet.Air.Remove(transferMoles);
- atmosphereSystem.Merge(environment, removed);
+ _atmosphereSystem.Merge(environment, removed);
}
}
else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0f)
@@ -89,7 +91,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
{
var removed = environment.Remove(molesDelta);
- Get().Merge(outlet.Air, removed);
+ _atmosphereSystem.Merge(outlet.Air, removed);
}
}
}
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
index dc38b4da76..3d2b9ca2ae 100644
--- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs
@@ -25,22 +25,23 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, AtmosDeviceUpdateEvent args)
{
var appearance = pump.Owner.GetComponentOrNull();
- appearance?.SetData(PressurePumpVisuals.Enabled, false);
- if (!pump.Enabled)
- return;
-
- if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
- return;
-
- if (!nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet)
+ if (!pump.Enabled
+ || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet)
|| !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet))
+ {
+ appearance?.SetData(PressurePumpVisuals.Enabled, false);
return;
+ }
var outputStartingPressure = outlet.Air.Pressure;
if (MathHelper.CloseTo(pump.TargetPressure, outputStartingPressure))
+ {
+ appearance?.SetData(PressurePumpVisuals.Enabled, false);
return; // No need to pump gas if target has been reached.
+ }
if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0)
{
diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
index ba4fd92866..555385d401 100644
--- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
+++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs
@@ -13,7 +13,8 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
[UsedImplicitly]
public class GasVolumePumpSystem : EntitySystem
{
- [Dependency] private IGameTiming _gameTiming = default!;
+ [Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
public override void Initialize()
{
@@ -56,13 +57,12 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems
// Some of the gas from the mixture leaks when overclocked.
if (pump.Overclocked)
{
- var atmosphereSystem = Get();
- var tile = atmosphereSystem.GetTileMixture(pump.Owner.Transform.Coordinates, true);
+ var tile = _atmosphereSystem.GetTileMixture(pump.Owner.Transform.Coordinates, true);
if (tile != null)
{
var leaked = removed.RemoveRatio(pump.LeakRatio);
- atmosphereSystem.Merge(tile, leaked);
+ _atmosphereSystem.Merge(tile, leaked);
}
}
diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
index 5c0d7826c6..166a4d07b8 100644
--- a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
+++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs
@@ -13,6 +13,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
public class AtmosDeviceSystem : EntitySystem
{
[Dependency] private IGameTiming _gameTiming = default!;
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
public override void Initialize()
{
@@ -35,7 +36,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
return;
// We try to add the device to a valid atmosphere.
- if (!Get().AddAtmosDevice(component))
+ if (!_atmosphereSystem.AddAtmosDevice(component))
return;
component.LastProcess = _gameTiming.CurTime;
@@ -45,7 +46,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
public void LeaveAtmosphere(AtmosDeviceComponent component)
{
- if (!Get().RemoveAtmosDevice(component))
+ if (!_atmosphereSystem.RemoveAtmosDevice(component))
return;
component.LastProcess = TimeSpan.Zero;
diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs
index c14fc7dafa..9e8935d0d3 100644
--- a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs
+++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs
@@ -8,6 +8,7 @@ using Content.Shared.Atmos;
using Content.Shared.Notification.Managers;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
using Robust.Shared.Localization;
namespace Content.Server.Atmos.Piping.EntitySystems
@@ -15,6 +16,8 @@ namespace Content.Server.Atmos.Piping.EntitySystems
[UsedImplicitly]
public class AtmosUnsafeUnanchorSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
SubscribeLocalEvent(OnBeforeUnanchored);
@@ -26,7 +29,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes))
return;
- if (Get().GetTileMixture(component.Owner.Transform.Coordinates) is not {} environment)
+ if (_atmosphereSystem.GetTileMixture(component.Owner.Transform.Coordinates) is not {} environment)
return;
foreach (var node in nodes.Nodes.Values)
@@ -47,9 +50,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems
if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes))
return;
- var atmosphereSystem = Get();
-
- if (atmosphereSystem.GetTileMixture(component.Owner.Transform.Coordinates, true) is not {} environment)
+ if (_atmosphereSystem.GetTileMixture(component.Owner.Transform.Coordinates, true) is not {} environment)
environment = GasMixture.SpaceGas;
var lost = 0f;
@@ -71,10 +72,10 @@ namespace Content.Server.Atmos.Piping.EntitySystems
{
if (node is not PipeNode pipe) continue;
- atmosphereSystem.Merge(buffer, pipe.Air.Remove(sharedLoss));
+ _atmosphereSystem.Merge(buffer, pipe.Air.Remove(sharedLoss));
}
- atmosphereSystem.Merge(environment, buffer);
+ _atmosphereSystem.Merge(environment, buffer);
}
}
}
diff --git a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs
index d1e61c7b98..0a4379d7f6 100644
--- a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs
+++ b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs
@@ -6,12 +6,15 @@ using Content.Server.Atmos.Piping.Other.Components;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.Atmos.Piping.Other.EntitySystems
{
[UsedImplicitly]
public class GasMinerSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -21,9 +24,7 @@ namespace Content.Server.Atmos.Piping.Other.EntitySystems
private void OnMinerUpdated(EntityUid uid, GasMinerComponent miner, AtmosDeviceUpdateEvent args)
{
- var atmosphereSystem = Get();
-
- if (!CheckMinerOperation(atmosphereSystem, miner, out var environment) || !miner.Enabled || !miner.SpawnGas.HasValue || miner.SpawnAmount <= 0f)
+ if (!CheckMinerOperation(miner, out var environment) || !miner.Enabled || !miner.SpawnGas.HasValue || miner.SpawnAmount <= 0f)
return;
// Time to mine some gas.
@@ -31,15 +32,15 @@ namespace Content.Server.Atmos.Piping.Other.EntitySystems
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
merger.SetMoles(miner.SpawnGas.Value, miner.SpawnAmount);
- atmosphereSystem.Merge(environment, merger);
+ _atmosphereSystem.Merge(environment, merger);
}
- private bool CheckMinerOperation(AtmosphereSystem atmosphereSystem, GasMinerComponent miner, [NotNullWhen(true)] out GasMixture? environment)
+ private bool CheckMinerOperation(GasMinerComponent miner, [NotNullWhen(true)] out GasMixture? environment)
{
- environment = atmosphereSystem.GetTileMixture(miner.Owner.Transform.Coordinates, true);
+ environment = _atmosphereSystem.GetTileMixture(miner.Owner.Transform.Coordinates, true);
// Space.
- if (atmosphereSystem.IsTileSpace(miner.Owner.Transform.Coordinates))
+ if (_atmosphereSystem.IsTileSpace(miner.Owner.Transform.Coordinates))
{
miner.Broken = true;
return false;
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs
index afc56ec96c..18b4c52433 100644
--- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs
@@ -19,6 +19,7 @@ using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
@@ -26,6 +27,8 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
[UsedImplicitly]
public class GasCanisterSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -131,23 +134,21 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
if (!nodeContainer.TryGetNode(canister.PortName, out PortablePipeNode? portNode))
return;
- var atmosphereSystem = Get();
-
- atmosphereSystem.React(canister.Air, portNode);
+ _atmosphereSystem.React(canister.Air, portNode);
if (portNode.NodeGroup is PipeNet {NodeCount: > 1} net)
{
var buffer = new GasMixture(net.Air.Volume + canister.Air.Volume);
- atmosphereSystem.Merge(buffer, net.Air);
- atmosphereSystem.Merge(buffer, canister.Air);
+ _atmosphereSystem.Merge(buffer, net.Air);
+ _atmosphereSystem.Merge(buffer, canister.Air);
net.Air.Clear();
- atmosphereSystem.Merge(net.Air, buffer);
+ _atmosphereSystem.Merge(net.Air, buffer);
net.Air.Multiply(net.Air.Volume / buffer.Volume);
canister.Air.Clear();
- atmosphereSystem.Merge(canister.Air, buffer);
+ _atmosphereSystem.Merge(canister.Air, buffer);
canister.Air.Multiply(canister.Air.Volume / buffer.Volume);
}
@@ -161,12 +162,12 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
if (container.ContainedEntities.Count > 0)
{
var gasTank = container.ContainedEntities[0].GetComponent();
- atmosphereSystem.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure);
+ _atmosphereSystem.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure);
}
else
{
- var environment = atmosphereSystem.GetTileMixture(canister.Owner.Transform.Coordinates, true);
- atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure);
+ var environment = _atmosphereSystem.GetTileMixture(canister.Owner.Transform.Coordinates, true);
+ _atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure);
}
}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs
index 63f9665d44..c716f72c04 100644
--- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs
@@ -6,12 +6,15 @@ using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
[UsedImplicitly]
public class GasOutletInjectorSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -32,8 +35,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet))
return;
- var atmosphereSystem = Get();
- var environment = atmosphereSystem.GetTileMixture(injector.Owner.Transform.Coordinates, true);
+ var environment = _atmosphereSystem.GetTileMixture(injector.Owner.Transform.Coordinates, true);
if (environment == null)
return;
@@ -44,7 +46,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
var removed = inlet.Air.Remove(transferMoles);
- atmosphereSystem.Merge(environment, removed);
+ _atmosphereSystem.Merge(environment, removed);
}
}
}
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs
index 5a61cbc350..e484e80da0 100644
--- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs
@@ -7,12 +7,15 @@ using Content.Server.NodeContainer.Nodes;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
[UsedImplicitly]
public class GasPassiveVentSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -22,8 +25,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, AtmosDeviceUpdateEvent args)
{
- var atmosphereSystem = Get();
- var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true);
+ var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true);
if (environment == null)
return;
@@ -44,7 +46,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
var airTemperature = environment.Temperature > 0 ? environment.Temperature : inlet.Air.Temperature;
var transferMoles = pressureDelta * environment.Volume / (airTemperature * Atmospherics.R);
var removed = inlet.Air.Remove(transferMoles);
- atmosphereSystem.Merge(environment, removed);
+ _atmosphereSystem.Merge(environment, removed);
}
else
{
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs
index 748700d13e..8706a22156 100644
--- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs
@@ -7,12 +7,15 @@ using Content.Shared.Atmos.Piping;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
[UsedImplicitly]
public class GasThermoMachineSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -24,18 +27,16 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, AtmosDeviceUpdateEvent args)
{
var appearance = thermoMachine.Owner.GetComponentOrNull();
- appearance?.SetData(ThermoMachineVisuals.Enabled, false);
- if (!thermoMachine.Enabled)
+ if (!thermoMachine.Enabled
+ || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet))
+ {
+ appearance?.SetData(ThermoMachineVisuals.Enabled, false);
return;
+ }
- if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
- return;
-
- if (!nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet))
- return;
-
- var airHeatCapacity = Get().GetHeatCapacity(inlet.Air);
+ var airHeatCapacity = _atmosphereSystem.GetHeatCapacity(inlet.Air);
var combinedHeatCapacity = airHeatCapacity + thermoMachine.HeatCapacity;
var oldTemperature = inlet.Air.Temperature;
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs
index 5e69a4f3b4..a008cde4ca 100644
--- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs
@@ -9,12 +9,15 @@ using Content.Shared.Atmos.Visuals;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
[UsedImplicitly]
public class GasVentPumpSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -33,23 +36,22 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
return;
}
- appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
-
- if (!vent.Enabled)
+ if (!vent.Enabled
+ || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe))
+ {
+ appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
return;
+ }
- if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
- return;
-
- if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe))
- return;
-
- var atmosphereSystem = Get();
- var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true);
+ var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true);
// We're in an air-blocked tile... Do nothing.
if (environment == null)
+ {
+ appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off);
return;
+ }
if (vent.PumpDirection == VentPumpDirection.Releasing)
{
@@ -66,7 +68,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
{
var transferMoles = pressureDelta * environment.Volume / (pipe.Air.Temperature * Atmospherics.R);
- atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles));
+ _atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles));
}
}
else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0)
diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
index 399ba29a38..9b6722411d 100644
--- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
+++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs
@@ -9,6 +9,7 @@ using Content.Shared.Atmos.Piping.Unary.Visuals;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
@@ -16,6 +17,8 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
[UsedImplicitly]
public class GasVentScrubberSystem : EntitySystem
{
+ [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -34,28 +37,24 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
return;
}
- appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
-
- if (!scrubber.Enabled)
+ if (!scrubber.Enabled
+ || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)
+ || !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
+ {
+ appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
return;
+ }
- if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer))
- return;
+ var environment = _atmosphereSystem.GetTileMixture(scrubber.Owner.Transform.Coordinates, true);
- if (!nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet))
- return;
-
- var atmosphereSystem = Get();
- var environment = atmosphereSystem.GetTileMixture(scrubber.Owner.Transform.Coordinates, true);
-
- Scrub(atmosphereSystem, scrubber, appearance, environment, outlet);
+ Scrub(_atmosphereSystem, scrubber, appearance, environment, outlet);
if (!scrubber.WideNet) return;
// Scrub adjacent tiles too.
- foreach (var adjacent in atmosphereSystem.GetAdjacentTileMixtures(scrubber.Owner.Transform.Coordinates, false, true))
+ foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(scrubber.Owner.Transform.Coordinates, false, true))
{
- Scrub(atmosphereSystem, scrubber, null, adjacent, outlet);
+ Scrub(_atmosphereSystem, scrubber, null, adjacent, outlet);
}
}
@@ -70,12 +69,12 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
private void Scrub(AtmosphereSystem atmosphereSystem, GasVentScrubberComponent scrubber, AppearanceComponent? appearance, GasMixture? tile, PipeNode outlet)
{
// Cannot scrub if tile is null or air-blocked.
- if (tile == null)
- return;
-
- // Cannot scrub if pressure too high.
- if (outlet.Air.Pressure >= 50 * Atmospherics.OneAtmosphere)
+ if (tile == null
+ || outlet.Air.Pressure >= 50 * Atmospherics.OneAtmosphere) // Cannot scrub if pressure too high.
+ {
+ appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off);
return;
+ }
if (scrubber.PumpDirection == ScrubberPumpDirection.Scrubbing)
{
diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs
index 5bcfc710b4..b90ced4c02 100644
--- a/Content.Server/Atmos/TileAtmosphere.cs
+++ b/Content.Server/Atmos/TileAtmosphere.cs
@@ -13,18 +13,12 @@ namespace Content.Server.Atmos
///
public class TileAtmosphere : IGasMixtureHolder
{
- [ViewVariables]
- public int ArchivedCycle;
-
[ViewVariables]
public int CurrentCycle;
[ViewVariables]
public float Temperature { get; set; } = Atmospherics.T20C;
- [ViewVariables]
- public float TemperatureArchived { get; set; } = Atmospherics.T20C;
-
[ViewVariables]
public TileAtmosphere? PressureSpecificTarget { get; set; }
diff --git a/Content.Server/Body/Surgery/Components/SurgeryToolSystem.cs b/Content.Server/Body/Surgery/Components/SurgeryToolSystem.cs
index b628e7f89c..5e95ace8be 100644
--- a/Content.Server/Body/Surgery/Components/SurgeryToolSystem.cs
+++ b/Content.Server/Body/Surgery/Components/SurgeryToolSystem.cs
@@ -6,12 +6,15 @@ using Content.Shared.Interaction.Events;
using Content.Shared.Interaction.Helpers;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
namespace Content.Server.Body.Surgery.Components
{
[UsedImplicitly]
public class SurgeryToolSystem : EntitySystem
{
+ [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
+
private readonly HashSet _openSurgeryUIs = new();
public override void Initialize()
@@ -54,7 +57,7 @@ namespace Content.Server.Body.Surgery.Components
continue;
}
- if (!Get().CanInteract(tool.PerformerCache) ||
+ if (!_actionBlockerSystem.CanInteract(tool.PerformerCache) ||
!tool.PerformerCache.InRangeUnobstructed(tool.BodyCache))
{
tool.CloseAllSurgeryUIs();
diff --git a/Content.Server/Construction/ConstructionSystem.cs b/Content.Server/Construction/ConstructionSystem.cs
index 11e7c41f72..f69cffd012 100644
--- a/Content.Server/Construction/ConstructionSystem.cs
+++ b/Content.Server/Construction/ConstructionSystem.cs
@@ -39,6 +39,8 @@ namespace Content.Server.Construction
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
+ [Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
+ [Dependency] private readonly StackSystem _stackSystem = default!;
private readonly Dictionary> _beingBuilt = new();
@@ -170,7 +172,7 @@ namespace Content.Server.Construction
if (!materialStep.EntityValid(entity, out var stack))
continue;
- var splitStack = Get().Split(entity.Uid, stack, materialStep.Amount, user.ToCoordinates());
+ var splitStack = _stackSystem.Split(entity.Uid, stack, materialStep.Amount, user.ToCoordinates());
if (splitStack == null)
continue;
@@ -226,8 +228,6 @@ namespace Content.Server.Construction
return null;
}
- var doAfterSystem = Get();
-
var doAfterArgs = new DoAfterEventArgs(user, doAfterTime)
{
BreakOnDamage = true,
@@ -237,7 +237,7 @@ namespace Content.Server.Construction
NeedHand = false,
};
- if (await doAfterSystem.WaitDoAfter(doAfterArgs) == DoAfterStatus.Cancelled)
+ if (await _doAfterSystem.WaitDoAfter(doAfterArgs) == DoAfterStatus.Cancelled)
{
FailCleanup();
return null;
diff --git a/Content.Server/Destructible/DestructibleSystem.cs b/Content.Server/Destructible/DestructibleSystem.cs
index f2ad5d4922..1be935c9f6 100644
--- a/Content.Server/Destructible/DestructibleSystem.cs
+++ b/Content.Server/Destructible/DestructibleSystem.cs
@@ -11,17 +11,7 @@ namespace Content.Server.Destructible
public class DestructibleSystem : EntitySystem
{
[Dependency] public readonly IRobustRandom Random = default!;
-
- public AudioSystem AudioSystem { get; private set; } = default!;
-
- public ActSystem ActSystem { get; private set; } = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- AudioSystem = Get();
- ActSystem = Get();
- }
+ [Dependency] public readonly AudioSystem AudioSystem = default!;
+ [Dependency] public readonly ActSystem ActSystem = default!;
}
}
diff --git a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs
index fcf4bb1d85..61bfad8791 100644
--- a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs
+++ b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs
@@ -16,6 +16,8 @@ namespace Content.Server.Engineering.EntitySystems
public class SpawnAfterInteractSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
+ [Dependency] private readonly StackSystem _stackSystem = default!;
public override void Initialize()
{
@@ -41,7 +43,7 @@ namespace Content.Server.Engineering.EntitySystems
if (!IsTileClear())
return;
- if (component.DoAfterTime > 0 && TryGet(out var doAfterSystem))
+ if (component.DoAfterTime > 0)
{
var doAfterArgs = new DoAfterEventArgs(args.User, component.DoAfterTime)
{
@@ -49,7 +51,7 @@ namespace Content.Server.Engineering.EntitySystems
BreakOnStun = true,
PostCheck = IsTileClear,
};
- var result = await doAfterSystem.WaitDoAfter(doAfterArgs);
+ var result = await _doAfterSystem.WaitDoAfter(doAfterArgs);
if (result != DoAfterStatus.Finished)
return;
@@ -59,7 +61,7 @@ namespace Content.Server.Engineering.EntitySystems
return;
if (component.Owner.TryGetComponent(out var stackComp)
- && component.RemoveOnInteract && !Get().Use(uid, stackComp, 1))
+ && component.RemoveOnInteract && !_stackSystem.Use(uid, stackComp, 1))
{
return;
}
diff --git a/Content.Server/Hands/HandsSystem.cs b/Content.Server/Hands/HandsSystem.cs
index 712c0867a6..4a76d07101 100644
--- a/Content.Server/Hands/HandsSystem.cs
+++ b/Content.Server/Hands/HandsSystem.cs
@@ -18,6 +18,7 @@ using Robust.Server.Player;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
using Robust.Shared.Input.Binding;
+using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Maths;
@@ -29,6 +30,9 @@ namespace Content.Server.Hands
[UsedImplicitly]
internal sealed class HandsSystem : SharedHandsSystem
{
+ [Dependency] private readonly InteractionSystem _interactionSystem = default!;
+ [Dependency] private readonly StackSystem _stackSystem = default!;
+
public override void Initialize()
{
base.Initialize();
@@ -113,12 +117,12 @@ namespace Content.Server.Hands
if (!hands.TryGetActiveHeldEntity(out var throwEnt))
return false;
- if (!Get().TryThrowInteraction(hands.Owner, throwEnt))
+ if (!_interactionSystem.TryThrowInteraction(hands.Owner, throwEnt))
return false;
if (throwEnt.TryGetComponent(out StackComponent? stack) && stack.Count > 1 && stack.ThrowIndividually)
{
- var splitStack = Get().Split(throwEnt.Uid, stack, 1, playerEnt.Transform.Coordinates);
+ var splitStack = _stackSystem.Split(throwEnt.Uid, stack, 1, playerEnt.Transform.Coordinates);
if (splitStack == null)
return false;
diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs
index efb01638c4..61a5ce724e 100644
--- a/Content.Server/Interaction/InteractionSystem.cs
+++ b/Content.Server/Interaction/InteractionSystem.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Content.Server.Buckle.Components;
using Content.Server.CombatMode;
+using Content.Server.DoAfter;
using Content.Server.Hands.Components;
using Content.Server.Items;
using Content.Server.Pulling;
@@ -46,6 +47,7 @@ namespace Content.Server.Interaction
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
+ [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
public override void Initialize()
{
@@ -175,9 +177,7 @@ namespace Content.Server.Interaction
private void InteractionActivate(IEntity user, IEntity used)
{
- var actionBlocker = Get();
-
- if (!actionBlocker.CanInteract(user) || ! actionBlocker.CanUse(user))
+ if (!_actionBlockerSystem.CanInteract(user) || ! _actionBlockerSystem.CanUse(user))
return;
// all activates should only fire when in range / unobstructed
@@ -275,7 +275,7 @@ namespace Content.Server.Interaction
if (!ValidateInteractAndFace(user, coordinates))
return;
- if (!Get().CanInteract(user))
+ if (!_actionBlockerSystem.CanInteract(user))
return;
// Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null
@@ -344,7 +344,7 @@ namespace Content.Server.Interaction
if (diff.LengthSquared <= 0.01f)
return;
var diffAngle = Angle.FromWorldVec(diff);
- if (Get().CanChangeDirection(user))
+ if (_actionBlockerSystem.CanChangeDirection(user))
{
user.Transform.WorldRotation = diffAngle;
}
@@ -394,7 +394,7 @@ namespace Content.Server.Interaction
///
public async Task InteractUsing(IEntity user, IEntity used, IEntity target, EntityCoordinates clickLocation)
{
- if (!Get().CanInteract(user))
+ if (!_actionBlockerSystem.CanInteract(user))
return;
// all interactions should only happen when in range / unobstructed, so no range check is needed
@@ -424,7 +424,7 @@ namespace Content.Server.Interaction
///
public void InteractHand(IEntity user, IEntity target)
{
- if (!Get().CanInteract(user))
+ if (!_actionBlockerSystem.CanInteract(user))
return;
// all interactions should only happen when in range / unobstructed, so no range check is needed
@@ -457,7 +457,7 @@ namespace Content.Server.Interaction
///
public void TryUseInteraction(IEntity user, IEntity used)
{
- if (user != null && used != null && Get().CanUse(user))
+ if (user != null && used != null && _actionBlockerSystem.CanUse(user))
{
UseInteraction(user, used);
}
@@ -501,7 +501,7 @@ namespace Content.Server.Interaction
///
public bool TryThrowInteraction(IEntity user, IEntity item)
{
- if (user == null || item == null || !Get().CanThrow(user)) return false;
+ if (user == null || item == null || !_actionBlockerSystem.CanThrow(user)) return false;
ThrownInteraction(user, item);
return true;
@@ -618,7 +618,7 @@ namespace Content.Server.Interaction
///
public bool TryDroppedInteraction(IEntity user, IEntity item, bool intentional)
{
- if (user == null || item == null || !Get().CanDrop(user)) return false;
+ if (user == null || item == null || !_actionBlockerSystem.CanDrop(user)) return false;
DroppedInteraction(user, item, intentional);
return true;
@@ -726,7 +726,7 @@ namespace Content.Server.Interaction
if (!ValidateInteractAndFace(user, coordinates))
return;
- if (!Get().CanAttack(user))
+ if (!_actionBlockerSystem.CanAttack(user))
return;
IEntity? targetEnt = null;
diff --git a/Content.Server/Inventory/Components/InventoryComponent.cs b/Content.Server/Inventory/Components/InventoryComponent.cs
index 6ba250d52d..8f1d0d7ad1 100644
--- a/Content.Server/Inventory/Components/InventoryComponent.cs
+++ b/Content.Server/Inventory/Components/InventoryComponent.cs
@@ -460,7 +460,7 @@ namespace Content.Server.Inventory.Components
{
if (!HasSlot(slot))
{
- throw new InvalidOperationException($"Slow '{slot}' does not exist.");
+ throw new InvalidOperationException($"Slot '{slot}' does not exist.");
}
ForceUnequip(slot);
diff --git a/Content.Server/Kitchen/Components/ReagentGrinderComponent.cs b/Content.Server/Kitchen/Components/ReagentGrinderComponent.cs
index 2f49df1945..5507978b53 100644
--- a/Content.Server/Kitchen/Components/ReagentGrinderComponent.cs
+++ b/Content.Server/Kitchen/Components/ReagentGrinderComponent.cs
@@ -1,24 +1,9 @@
-using System;
-using System.Linq;
-using System.Threading.Tasks;
using Content.Server.Chemistry.Components;
-using Content.Server.Hands.Components;
-using Content.Server.Items;
-using Content.Server.Power.Components;
-using Content.Server.UserInterface;
-using Content.Shared.Chemistry.Solution;
using Content.Shared.Interaction;
using Content.Shared.Kitchen.Components;
-using Content.Shared.Notification.Managers;
-using Content.Shared.Random.Helpers;
using Content.Shared.Sound;
-using Content.Shared.Tag;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
-using Robust.Shared.Localization;
-using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
@@ -32,343 +17,30 @@ namespace Content.Server.Kitchen.Components
/// it contained, juice an apple and get "apple juice".
///
[RegisterComponent]
- [ComponentReference(typeof(IActivate))]
- public class ReagentGrinderComponent : SharedReagentGrinderComponent, IActivate, IInteractUsing
+ public class ReagentGrinderComponent : SharedReagentGrinderComponent
{
- private AudioSystem _audioSystem = default!;
- [ViewVariables] private ContainerSlot _beakerContainer = default!;
+ [ViewVariables] public ContainerSlot BeakerContainer = default!;
///
/// Can be null since we won't always have a beaker in the grinder.
///
- [ViewVariables] private SolutionContainerComponent? _heldBeaker = default!;
+ [ViewVariables] public SolutionContainerComponent? HeldBeaker = default!;
///
/// Contains the things that are going to be ground or juiced.
///
- [ViewVariables] private Container _chamber = default!;
+ [ViewVariables] public Container Chamber = default!;
- [ViewVariables] private bool ChamberEmpty => _chamber.ContainedEntities.Count <= 0;
- [ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
- [ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ReagentGrinderUiKey.Key);
-
- private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
-
- ///
- /// Should the BoundUI be told to update?
- ///
- private bool _uiDirty = true;
///
/// Is the machine actively doing something and can't be used right now?
///
- private bool _busy = false;
+ public bool Busy;
//YAML serialization vars
- [ViewVariables(VVAccess.ReadWrite)] [DataField("chamberCapacity")] private int _storageCap = 16;
- [ViewVariables(VVAccess.ReadWrite)] [DataField("workTime")] private int _workTime = 3500; //3.5 seconds, completely arbitrary for now.
+ [ViewVariables(VVAccess.ReadWrite)] [DataField("chamberCapacity")] public int StorageCap = 16;
+ [ViewVariables(VVAccess.ReadWrite)] [DataField("workTime")] public int WorkTime = 3500; //3.5 seconds, completely arbitrary for now.
[DataField("clickSound")] private SoundSpecifier _clickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
[DataField("grindSound")] private SoundSpecifier _grindSound = new SoundPathSpecifier("/Audio/Machines/blender.ogg");
[DataField("juiceSound")] private SoundSpecifier _juiceSound = new SoundPathSpecifier("/Audio/Machines/juicer.ogg");
-
- protected override void Initialize()
- {
- base.Initialize();
- //A slot for the beaker where the grounds/juices will go.
- _beakerContainer =
- ContainerHelpers.EnsureContainer(Owner, $"{Name}-reagentContainerContainer");
-
- //A container for the things that WILL be ground/juiced. Useful for ejecting them instead of deleting them from the hands of the user.
- _chamber =
- ContainerHelpers.EnsureContainer(Owner, $"{Name}-entityContainerContainer");
-
- if (UserInterface != null)
- {
- UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
- }
-
- _audioSystem = EntitySystem.Get();
- }
-
- public override void HandleMessage(ComponentMessage message, IComponent? component)
- {
- base.HandleMessage(message, component);
- switch (message)
- {
- case PowerChangedMessage powerChanged:
- OnPowerStateChanged(powerChanged);
- break;
- }
- }
-
- protected override void OnRemove()
- {
- base.OnRemove();
- if (UserInterface != null)
- {
- UserInterface.OnReceiveMessage -= UserInterfaceOnReceiveMessage;
- }
- }
-
- private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage message)
- {
- if(_busy)
- {
- return;
- }
-
- switch(message.Message)
- {
- case ReagentGrinderGrindStartMessage msg:
- if (!Powered) break;
- ClickSound();
- DoWork(message.Session.AttachedEntity!, GrinderProgram.Grind);
- break;
-
- case ReagentGrinderJuiceStartMessage msg:
- if (!Powered) break;
- ClickSound();
- DoWork(message.Session.AttachedEntity!, GrinderProgram.Juice);
- break;
-
- case ReagentGrinderEjectChamberAllMessage msg:
- if(!ChamberEmpty)
- {
- ClickSound();
- for (var i = _chamber.ContainedEntities.Count - 1; i >= 0; i--)
- {
- EjectSolid(_chamber.ContainedEntities.ElementAt(i).Uid);
- }
- }
- break;
-
- case ReagentGrinderEjectChamberContentMessage msg:
- if (!ChamberEmpty)
- {
- EjectSolid(msg.EntityID);
- ClickSound();
- _uiDirty = true;
- }
- break;
-
- case ReagentGrinderEjectBeakerMessage msg:
- ClickSound();
- EjectBeaker(message.Session.AttachedEntity);
- //EjectBeaker will dirty the UI for us, we don't have to do it explicitly here.
- break;
- }
- }
-
- private void OnPowerStateChanged(PowerChangedMessage e)
- {
- _uiDirty = true;
- }
-
- private void ClickSound()
- {
- if(_clickSound.TryGetSound(out var sound))
- SoundSystem.Play(Filter.Pvs(Owner), sound, Owner, AudioParams.Default.WithVolume(-2f));
- }
-
- private void SetAppearance()
- {
- if (Owner.TryGetComponent(out AppearanceComponent? appearance))
- {
- appearance.SetData(ReagentGrinderVisualState.BeakerAttached, HasBeaker);
- }
- }
-
- public void OnUpdate()
- {
- if(_uiDirty)
- {
- UpdateInterface();
- _uiDirty = false;
- }
- }
-
- // This doesn't check for UI dirtiness so handle that when calling this.
- private void UpdateInterface()
- {
- bool canJuice = false;
- bool canGrind = false;
- if (HasBeaker)
- {
- foreach (var entity in _chamber.ContainedEntities)
- {
- if (!canJuice && entity.HasComponent()) canJuice = true;
- if (!canGrind && entity.HasTag("Grindable")) canGrind = true;
- if (canJuice && canGrind) break;
- }
- }
-
- UserInterface?.SetState(new ReagentGrinderInterfaceState
- (
- _busy,
- HasBeaker,
- Powered,
- canJuice,
- canGrind,
- _chamber.ContainedEntities.Select(item => item.Uid).ToArray(),
- //Remember the beaker can be null!
- _heldBeaker?.Solution.Contents.ToArray()
- ));
- _uiDirty = false;
- }
-
- private void EjectSolid(EntityUid entityID)
- {
- if (_busy)
- return;
-
- if (Owner.EntityManager.TryGetEntity(entityID, out var entity))
- {
- _chamber.Remove(entity);
-
- //Give the ejected entity a tiny bit of offset so each one is apparent in case of a big stack,
- //but (hopefully) not enough to clip it through a solid (wall).
- entity.RandomOffset(0.4f);
- }
- _uiDirty = true;
- }
-
- ///
- /// Tries to eject whatever is in the beaker slot. Puts the item in the user's hands or failing that on top
- /// of the grinder.
- ///
- private void EjectBeaker(IEntity? user)
- {
- if (!HasBeaker || _heldBeaker == null || _busy)
- return;
-
- var beaker = _beakerContainer.ContainedEntity;
- if(beaker is null)
- return;
-
- _beakerContainer.Remove(beaker);
-
- if (user == null || !user.TryGetComponent(out var hands) || !_heldBeaker.Owner.TryGetComponent(out var item))
- return;
- hands.PutInHandOrDrop(item);
-
- _heldBeaker = null;
- _uiDirty = true;
- SetAppearance();
- }
-
- void IActivate.Activate(ActivateEventArgs eventArgs)
- {
- if (!eventArgs.User.TryGetComponent(out ActorComponent? actor))
- {
- return;
- }
- _uiDirty = true;
- UserInterface?.Toggle(actor.PlayerSession);
- }
-
- async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
- {
- if (!eventArgs.User.TryGetComponent(out IHandsComponent? hands))
- {
- Owner.PopupMessage(eventArgs.User, Loc.GetString("reagent-grinder-component-interact-using-no-hands"));
- return true;
- }
-
- IEntity heldEnt = eventArgs.Using;
-
- //First, check if user is trying to insert a beaker.
- //No promise it will be a beaker right now, but whatever.
- //Maybe this should whitelist "beaker" in the prototype id of heldEnt?
- if(heldEnt.TryGetComponent(out SolutionContainerComponent? beaker) && beaker.Capabilities.HasFlag(SolutionContainerCaps.FitsInDispenser))
- {
- _beakerContainer.Insert(heldEnt);
- _heldBeaker = beaker;
- _uiDirty = true;
- //We are done, return. Insert the beaker and exit!
- SetAppearance();
- ClickSound();
- return true;
- }
-
- //Next, see if the user is trying to insert something they want to be ground/juiced.
- if(!heldEnt.HasTag("Grindable") && !heldEnt.TryGetComponent(out JuiceableComponent? juice))
- {
- //Entity did NOT pass the whitelist for grind/juice.
- //Wouldn't want the clown grinding up the Captain's ID card now would you?
- //Why am I asking you? You're biased.
- return false;
- }
-
- //Cap the chamber. Don't want someone putting in 500 entities and ejecting them all at once.
- //Maybe I should have done that for the microwave too?
- if (_chamber.ContainedEntities.Count >= _storageCap)
- {
- return false;
- }
-
- if (!_chamber.Insert(heldEnt))
- return false;
-
- _uiDirty = true;
- return true;
- }
-
- ///
- /// The wzhzhzh of the grinder. Processes the contents of the grinder and puts the output in the beaker.
- ///
- /// true for wanting to juice, false for wanting to grind.
- private async void DoWork(IEntity user, GrinderProgram program)
- {
- //Have power, are we busy, chamber has anything to grind, a beaker for the grounds to go?
- if(!Powered || _busy || ChamberEmpty || !HasBeaker || _heldBeaker == null)
- {
- return;
- }
-
- _busy = true;
-
- UserInterface?.SendMessage(new ReagentGrinderWorkStartedMessage(program));
- switch (program)
- {
- case GrinderProgram.Grind:
- if(_grindSound.TryGetSound(out var grindSound))
- SoundSystem.Play(Filter.Pvs(Owner), grindSound, Owner, AudioParams.Default);
- //Get each item inside the chamber and get the reagents it contains. Transfer those reagents to the beaker, given we have one in.
- Owner.SpawnTimer(_workTime, (Action) (() =>
- {
- foreach (var item in _chamber.ContainedEntities.ToList())
- {
- if (!item.HasTag("Grindable")) continue;
- if (!item.TryGetComponent(out var solution)) continue;
- if (_heldBeaker.CurrentVolume + solution.CurrentVolume > _heldBeaker.MaxVolume) continue;
- _heldBeaker.TryAddSolution(solution.Solution);
- solution.RemoveAllSolution();
- item.Delete();
- }
-
- _busy = false;
- _uiDirty = true;
- UserInterface?.SendMessage(new ReagentGrinderWorkCompleteMessage());
- }));
- break;
-
- case GrinderProgram.Juice:
- if(_juiceSound.TryGetSound(out var juiceSound))
- SoundSystem.Play(Filter.Pvs(Owner), juiceSound, Owner, AudioParams.Default);
- Owner.SpawnTimer(_workTime, (Action) (() =>
- {
- foreach (var item in _chamber.ContainedEntities.ToList())
- {
- if (!item.TryGetComponent(out var juiceMe)) continue;
- if (_heldBeaker.CurrentVolume + juiceMe.JuiceResultSolution.TotalVolume > _heldBeaker.MaxVolume) continue;
- _heldBeaker.TryAddSolution(juiceMe.JuiceResultSolution);
- item.Delete();
- }
- UserInterface?.SendMessage(new ReagentGrinderWorkCompleteMessage());
- _busy = false;
- _uiDirty = true;
- }));
- break;
- }
- }
}
}
diff --git a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs
index 95f3dbe5f8..c58c5b32ee 100644
--- a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs
+++ b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs
@@ -1,19 +1,314 @@
-using Content.Server.Kitchen.Components;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Content.Server.Chemistry.Components;
+using Content.Server.Hands.Components;
+using Content.Server.Items;
+using Content.Server.Kitchen.Components;
+using Content.Server.Power.Components;
+using Content.Server.UserInterface;
+using Content.Shared.Chemistry.Solution;
+using Content.Shared.Interaction;
+using Content.Shared.Kitchen.Components;
+using Content.Shared.Notification.Managers;
+using Content.Shared.Random.Helpers;
+using Content.Shared.Tag;
using JetBrains.Annotations;
+using Robust.Server.GameObjects;
+using Robust.Shared.Audio;
+using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
+using Robust.Shared.Player;
+using Robust.Shared.Utility;
namespace Content.Server.Kitchen.EntitySystems
{
[UsedImplicitly]
internal sealed class ReagentGrinderSystem : EntitySystem
{
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+
+ private Queue _uiUpdateQueue = new ();
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnComponentInit);
+ SubscribeLocalEvent((_, component, _) => EnqueueUiUpdate(component));
+ SubscribeLocalEvent(OnInteractHand);
+ SubscribeLocalEvent(OnInteractUsing);
+ }
+
+ private void OnInteractUsing(EntityUid uid, ReagentGrinderComponent component, InteractUsingEvent args)
+ {
+ if(args.Handled) return;
+
+ if (!args.User.TryGetComponent(out IHandsComponent? hands))
+ {
+ component.Owner.PopupMessage(args.User, Loc.GetString("reagent-grinder-component-interact-using-no-hands"));
+ args.Handled = true;
+ return;
+ }
+
+ IEntity heldEnt = args.Used;
+
+ //First, check if user is trying to insert a beaker.
+ //No promise it will be a beaker right now, but whatever.
+ //Maybe this should whitelist "beaker" in the prototype id of heldEnt?
+ if(heldEnt.TryGetComponent(out SolutionContainerComponent? beaker) && beaker.Capabilities.HasFlag(SolutionContainerCaps.FitsInDispenser))
+ {
+ component.BeakerContainer.Insert(heldEnt);
+ component.HeldBeaker = beaker;
+ EnqueueUiUpdate(component);
+ //We are done, return. Insert the beaker and exit!
+ if (component.Owner.TryGetComponent(out AppearanceComponent? appearance))
+ {
+ appearance.SetData(SharedReagentGrinderComponent.ReagentGrinderVisualState.BeakerAttached, component.BeakerContainer.ContainedEntity != null);
+ }
+ ClickSound(component);
+ args.Handled = true;
+ return;
+ }
+
+ //Next, see if the user is trying to insert something they want to be ground/juiced.
+ if(!heldEnt.HasTag("Grindable") && !heldEnt.TryGetComponent(out JuiceableComponent? juice))
+ {
+ //Entity did NOT pass the whitelist for grind/juice.
+ //Wouldn't want the clown grinding up the Captain's ID card now would you?
+ //Why am I asking you? You're biased.
+ return;
+ }
+
+ //Cap the chamber. Don't want someone putting in 500 entities and ejecting them all at once.
+ //Maybe I should have done that for the microwave too?
+ if (component.Chamber.ContainedEntities.Count >= component.StorageCap)
+ {
+ return;
+ }
+
+ if (!component.Chamber.Insert(heldEnt))
+ {
+ return;
+ }
+
+ EnqueueUiUpdate(component);
+ args.Handled = true;
+ }
+
+ private void OnInteractHand(EntityUid uid, ReagentGrinderComponent component, InteractHandEvent args)
+ {
+ if (args.Handled) return;
+
+ if (!args.User.TryGetComponent(out ActorComponent? actor))
+ {
+ return;
+ }
+ EnqueueUiUpdate(component);
+ component.Owner.GetUIOrNull(SharedReagentGrinderComponent.ReagentGrinderUiKey.Key)?.Toggle(actor.PlayerSession);
+ args.Handled = true;
+ }
+
+ private void EnqueueUiUpdate(ReagentGrinderComponent component)
+ {
+ if(!_uiUpdateQueue.Contains(component)) _uiUpdateQueue.Enqueue(component);
+ }
+
+ private void OnComponentInit(EntityUid uid, ReagentGrinderComponent component, ComponentInit args)
+ {
+ EnqueueUiUpdate(component);
+
+ //A slot for the beaker where the grounds/juices will go.
+ component.BeakerContainer =
+ ContainerHelpers.EnsureContainer(component.Owner, $"{component.Name}-reagentContainerContainer");
+
+ //A container for the things that WILL be ground/juiced. Useful for ejecting them instead of deleting them from the hands of the user.
+ component.Chamber =
+ ContainerHelpers.EnsureContainer(component.Owner, $"{component.Name}-entityContainerContainer");
+
+ var bui = component.Owner.GetUIOrNull(SharedReagentGrinderComponent.ReagentGrinderUiKey.Key);
+ if (bui != null)
+ {
+ bui.OnReceiveMessage += msg => OnUIMessageReceived(uid, component, msg);
+ }
+ }
+
+ private void OnUIMessageReceived(EntityUid uid, ReagentGrinderComponent component,
+ ServerBoundUserInterfaceMessage message)
+ {
+ if(component.Busy)
+ {
+ return;
+ }
+
+ switch(message.Message)
+ {
+ case SharedReagentGrinderComponent.ReagentGrinderGrindStartMessage msg:
+ if (!component.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || !receiver.Powered) break;
+ ClickSound(component);
+ DoWork(component, message.Session.AttachedEntity!, SharedReagentGrinderComponent.GrinderProgram.Grind);
+ break;
+
+ case SharedReagentGrinderComponent.ReagentGrinderJuiceStartMessage msg:
+ if (!component.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver2) || !receiver2.Powered) break;
+ ClickSound(component);
+ DoWork(component, message.Session.AttachedEntity!, SharedReagentGrinderComponent.GrinderProgram.Juice);
+ break;
+
+ case SharedReagentGrinderComponent.ReagentGrinderEjectChamberAllMessage msg:
+ if(component.Chamber.ContainedEntities.Count > 0)
+ {
+ ClickSound(component);
+ for (var i = component.Chamber.ContainedEntities.Count - 1; i >= 0; i--)
+ {
+ var entity = component.Chamber.ContainedEntities[i];
+ component.Chamber.Remove(entity);
+ entity.RandomOffset(0.4f);
+ }
+ EnqueueUiUpdate(component);
+ }
+ break;
+
+ case SharedReagentGrinderComponent.ReagentGrinderEjectChamberContentMessage msg:
+ if (component.Chamber.ContainedEntities.TryFirstOrDefault(x => x.Uid == msg.EntityID, out var ent))
+ {
+ component.Chamber.Remove(ent);
+ ent.RandomOffset(0.4f);
+ EnqueueUiUpdate(component);
+ ClickSound(component);
+ }
+ break;
+
+ case SharedReagentGrinderComponent.ReagentGrinderEjectBeakerMessage msg:
+ ClickSound(component);
+ EjectBeaker(component, message.Session.AttachedEntity);
+ EnqueueUiUpdate(component);
+ break;
+ }
+ }
+
public override void Update(float frameTime)
{
base.Update(frameTime);
- foreach (var comp in ComponentManager.EntityQuery(true))
+
+ while (_uiUpdateQueue.TryDequeue(out var comp))
{
- comp.OnUpdate();
+ bool canJuice = false;
+ bool canGrind = false;
+ if (comp.BeakerContainer.ContainedEntity != null)
+ {
+ foreach (var entity in comp.Chamber.ContainedEntities)
+ {
+ if (!canJuice && entity.HasComponent()) canJuice = true;
+ if (!canGrind && entity.HasTag("Grindable")) canGrind = true;
+ if (canJuice && canGrind) break;
+ }
+ }
+
+ comp.Owner.GetUIOrNull(SharedReagentGrinderComponent.ReagentGrinderUiKey.Key)?.SetState(new ReagentGrinderInterfaceState
+ (
+ comp.Busy,
+ comp.BeakerContainer.ContainedEntity != null,
+ comp.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) && receiver.Powered,
+ canJuice,
+ canGrind,
+ comp.Chamber.ContainedEntities.Select(item => item.Uid).ToArray(),
+ //Remember the beaker can be null!
+ comp.HeldBeaker?.Solution.Contents.ToArray()
+ ));
}
}
+
+ ///
+ /// Tries to eject whatever is in the beaker slot. Puts the item in the user's hands or failing that on top
+ /// of the grinder.
+ ///
+ private void EjectBeaker(ReagentGrinderComponent component, IEntity? user)
+ {
+ if (component.BeakerContainer.ContainedEntity == null || component.HeldBeaker == null || component.Busy)
+ return;
+
+ var beaker = component.BeakerContainer.ContainedEntity;
+ if(beaker is null)
+ return;
+
+ component.BeakerContainer.Remove(beaker);
+
+ if (user == null || !user.TryGetComponent(out var hands) || !component.HeldBeaker.Owner.TryGetComponent(out var item))
+ return;
+ hands.PutInHandOrDrop(item);
+
+ component.HeldBeaker = null;
+ EnqueueUiUpdate(component);
+ if (component.Owner.TryGetComponent(out AppearanceComponent? appearance))
+ {
+ appearance.SetData(SharedReagentGrinderComponent.ReagentGrinderVisualState.BeakerAttached, component.BeakerContainer.ContainedEntity != null);
+ }
+ }
+
+ ///
+ /// The wzhzhzh of the grinder. Processes the contents of the grinder and puts the output in the beaker.
+ ///
+ /// true for wanting to juice, false for wanting to grind.
+ private void DoWork(ReagentGrinderComponent component, IEntity user, SharedReagentGrinderComponent.GrinderProgram program)
+ {
+ //Have power, are we busy, chamber has anything to grind, a beaker for the grounds to go?
+ if(!component.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || !receiver.Powered || component.Busy || component.Chamber.ContainedEntities.Count <= 0 || component.BeakerContainer.ContainedEntity == null || component.HeldBeaker == null)
+ {
+ return;
+ }
+
+ component.Busy = true;
+
+ var bui = component.Owner.GetUIOrNull(SharedReagentGrinderComponent.ReagentGrinderUiKey.Key);
+ bui?.SendMessage(new SharedReagentGrinderComponent.ReagentGrinderWorkStartedMessage(program));
+ switch (program)
+ {
+ case SharedReagentGrinderComponent.GrinderProgram.Grind:
+ SoundSystem.Play(Filter.Pvs(component.Owner), "/Audio/Machines/blender.ogg", component.Owner, AudioParams.Default);
+ //Get each item inside the chamber and get the reagents it contains. Transfer those reagents to the beaker, given we have one in.
+ component.Owner.SpawnTimer(component.WorkTime, (Action) (() =>
+ {
+ foreach (var item in component.Chamber.ContainedEntities.ToList())
+ {
+ if (!item.HasTag("Grindable")) continue;
+ if (!item.TryGetComponent(out var solution)) continue;
+ if (component.HeldBeaker.CurrentVolume + solution.CurrentVolume > component.HeldBeaker.MaxVolume) continue;
+ component.HeldBeaker.TryAddSolution(solution.Solution);
+ solution.RemoveAllSolution();
+ item.Delete();
+ }
+
+ component.Busy = false;
+ EnqueueUiUpdate(component);
+ bui?.SendMessage(new SharedReagentGrinderComponent.ReagentGrinderWorkCompleteMessage());
+ }));
+ break;
+
+ case SharedReagentGrinderComponent.GrinderProgram.Juice:
+ SoundSystem.Play(Filter.Pvs(component.Owner), "/Audio/Machines/juicer.ogg", component.Owner, AudioParams.Default);
+ component.Owner.SpawnTimer(component.WorkTime, (Action) (() =>
+ {
+ foreach (var item in component.Chamber.ContainedEntities.ToList())
+ {
+ if (!item.TryGetComponent(out var juiceMe)) continue;
+ if (component.HeldBeaker.CurrentVolume + juiceMe.JuiceResultSolution.TotalVolume > component.HeldBeaker.MaxVolume) continue;
+ component.HeldBeaker.TryAddSolution(juiceMe.JuiceResultSolution);
+ item.Delete();
+ }
+ bui?.SendMessage(new SharedReagentGrinderComponent.ReagentGrinderWorkCompleteMessage());
+ component.Busy = false;
+ EnqueueUiUpdate(component);
+ }));
+ break;
+ }
+ }
+
+ private void ClickSound(ReagentGrinderComponent component)
+ {
+ SoundSystem.Play(Filter.Pvs(component.Owner), "/Audio/Machines/machine_switch.ogg", component.Owner, AudioParams.Default.WithVolume(-2f));
+ }
}
}
diff --git a/Content.Server/Light/Components/EmergencyLightComponent.cs b/Content.Server/Light/Components/EmergencyLightComponent.cs
index 5d7fd2a933..b5df55fb28 100644
--- a/Content.Server/Light/Components/EmergencyLightComponent.cs
+++ b/Content.Server/Light/Components/EmergencyLightComponent.cs
@@ -142,7 +142,7 @@ namespace Content.Server.Light.Components
void IExamine.Examine(FormattedMessage message, bool inDetailsRange)
{
- message.AddMarkup(Loc.GetString("emergency-light-component-on-examine",("batteryStateText", BatteryStateText[State])));
+ message.AddMarkup(Loc.GetString("emergency-light-component-on-examine",("batteryStateText", Loc.GetString(BatteryStateText[State]))));
}
public enum EmergencyLightState
diff --git a/Content.Server/Light/Components/ExpendableLightComponent.cs b/Content.Server/Light/Components/ExpendableLightComponent.cs
index 0a834773e1..39671b0e86 100644
--- a/Content.Server/Light/Components/ExpendableLightComponent.cs
+++ b/Content.Server/Light/Components/ExpendableLightComponent.cs
@@ -56,7 +56,7 @@ namespace Content.Server.Light.Components
///
private bool TryActivate()
{
- if (!Activated)
+ if (!Activated && CurrentState == ExpendableLightState.BrandNew)
{
if (Owner.TryGetComponent(out var item))
{
diff --git a/Content.Server/Lock/LockComponent.cs b/Content.Server/Lock/LockComponent.cs
new file mode 100644
index 0000000000..966548e607
--- /dev/null
+++ b/Content.Server/Lock/LockComponent.cs
@@ -0,0 +1,64 @@
+using Content.Server.Lock;
+using Content.Shared.ActionBlocker;
+using Content.Shared.Interaction;
+using Content.Shared.Interaction.Helpers;
+using Content.Shared.Sound;
+using Content.Shared.Verbs;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Localization;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.Storage.Components
+{
+ ///
+ /// Allows locking/unlocking, with access determined by AccessReader
+ ///
+ [RegisterComponent]
+ public class LockComponent : Component
+ {
+ public override string Name => "Lock";
+
+ [ViewVariables(VVAccess.ReadWrite)] [DataField("locked")] public bool Locked { get; set; } = true;
+ [ViewVariables(VVAccess.ReadWrite)] [DataField("unlockingSound")] public SoundSpecifier? UnlockSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg");
+ [ViewVariables(VVAccess.ReadWrite)] [DataField("lockingSound")] public SoundSpecifier? LockSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg");
+
+ [Verb]
+ private sealed class ToggleLockVerb : Verb
+ {
+ protected override void GetData(IEntity user, LockComponent component, VerbData data)
+ {
+ if (!EntitySystem.Get().CanInteract(user) ||
+ component.Owner.TryGetComponent(out EntityStorageComponent? entityStorageComponent) && entityStorageComponent.Open)
+ {
+ data.Visibility = VerbVisibility.Invisible;
+ return;
+ }
+
+ data.Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock");
+ }
+
+ protected override void Activate(IEntity user, LockComponent component)
+ {
+ // Do checks
+ if (!EntitySystem.Get().CanInteract(user) ||
+ !user.InRangeUnobstructed(component))
+ {
+ return;
+ }
+
+ // Call relevant entity system
+ var lockSystem = user.EntityManager.EntitySysManager.GetEntitySystem();
+ var eventData = new ActivateInWorldEvent(user, component.Owner);
+ if (component.Locked)
+ {
+ lockSystem.DoUnlock(component, eventData);
+ }
+ else
+ {
+ lockSystem.DoLock(component, eventData);
+ }
+ }
+ }
+ }
+}
diff --git a/Content.Server/Lock/LockSystem.cs b/Content.Server/Lock/LockSystem.cs
new file mode 100644
index 0000000000..063ac1656a
--- /dev/null
+++ b/Content.Server/Lock/LockSystem.cs
@@ -0,0 +1,116 @@
+using Content.Server.Access.Components;
+using Content.Server.Storage.Components;
+using Content.Shared.Examine;
+using Content.Shared.Interaction;
+using Content.Shared.Notification.Managers;
+using Content.Shared.Storage;
+using JetBrains.Annotations;
+using Robust.Server.GameObjects;
+using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Localization;
+using Robust.Shared.Player;
+
+namespace Content.Server.Lock
+{
+ ///
+ /// Handles (un)locking and examining of Lock components
+ ///
+ [UsedImplicitly]
+ public class LockSystem : EntitySystem
+ {
+ ///
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnStartup);
+ SubscribeLocalEvent(OnActivated);
+ SubscribeLocalEvent(OnExamined);
+ }
+
+ private void OnStartup(EntityUid eUI, LockComponent lockComp, ComponentStartup args)
+ {
+ if (lockComp.Owner.TryGetComponent(out AppearanceComponent? appearance))
+ {
+ appearance.SetData(StorageVisuals.CanLock, true);
+ }
+ }
+
+ private void OnActivated(EntityUid eUI, LockComponent lockComp, ActivateInWorldEvent args)
+ {
+ // Only attempt an unlock by default on Activate
+ if (lockComp.Locked)
+ {
+ DoUnlock(lockComp, args);
+ }
+ }
+
+ private void OnExamined(EntityUid eUI, LockComponent lockComp, ExaminedEvent args)
+ {
+ args.Message.AddText("\n");
+ args.Message.AddText(Loc.GetString(lockComp.Locked
+ ? "lock-comp-on-examined-is-locked"
+ : "lock-comp-on-examined-is-unlocked",
+ ("entityName", lockComp.Owner.Name)));
+ }
+
+ public void DoLock(LockComponent lockComp, ActivateInWorldEvent args)
+ {
+ if (!HasUserAccess(lockComp, args.User))
+ {
+ return;
+ }
+
+ lockComp.Owner.PopupMessage(args.User, Loc.GetString("lock-comp-do-lock-success", ("entityName",lockComp.Owner.Name)));
+ lockComp.Locked = true;
+ if(lockComp.LockSound != null)
+ {
+ SoundSystem.Play(Filter.Pvs(lockComp.Owner), lockComp.LockSound.GetSound(), lockComp.Owner, AudioParams.Default.WithVolume(-5));
+ }
+
+ if (lockComp.Owner.TryGetComponent(out AppearanceComponent? appearanceComp))
+ {
+ appearanceComp.SetData(StorageVisuals.Locked, true);
+ }
+
+ args.Handled = true;
+ }
+
+ public void DoUnlock(LockComponent lockComp, ActivateInWorldEvent args )
+ {
+ if (!HasUserAccess(lockComp, args.User))
+ {
+ return;
+ }
+
+ lockComp.Owner.PopupMessage(args.User, Loc.GetString("lock-comp-do-unlock-success", ("entityName", lockComp.Owner.Name)));
+ lockComp.Locked = false;
+ if(lockComp.UnlockSound != null)
+ {
+ SoundSystem.Play(Filter.Pvs(lockComp.Owner), lockComp.UnlockSound.GetSound(), lockComp.Owner, AudioParams.Default.WithVolume(-5));
+ }
+
+ if (lockComp.Owner.TryGetComponent(out AppearanceComponent? appearanceComp))
+ {
+ appearanceComp.SetData(StorageVisuals.Locked, false);
+ }
+
+ // To stop EntityStorageComponent from opening right after the container gets unlocked
+ args.Handled = true;
+ }
+
+ private static bool HasUserAccess(LockComponent lockComp, IEntity user)
+ {
+ if (lockComp.Owner.TryGetComponent(out AccessReader? reader))
+ {
+ if (!reader.IsAllowed(user))
+ {
+ lockComp.Owner.PopupMessage(user, Loc.GetString("lock-comp-has-user-access-fail"));
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/Content.Server/Nutrition/Components/FoodContainerComponent.cs b/Content.Server/Nutrition/Components/FoodContainerComponent.cs
deleted file mode 100644
index 3854928bca..0000000000
--- a/Content.Server/Nutrition/Components/FoodContainerComponent.cs
+++ /dev/null
@@ -1,103 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using Content.Server.Hands.Components;
-using Content.Server.Items;
-using Content.Shared.Interaction;
-using Content.Shared.Nutrition.Components;
-using Robust.Server.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-using Robust.Shared.Random;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.Utility;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.Nutrition.Components
-{
- ///
- /// This container acts as a master object for things like Pizza, which holds slices.
- ///
- /// TODO: Perhaps implement putting food back (pizza boxes) but that really isn't mandatory.
- /// This doesn't even need to have an actual Container for right now.
- [RegisterComponent]
- public sealed class FoodContainer : SharedFoodContainerComponent, IUse
- {
- [Dependency] private readonly IRobustRandom _random = default!;
- public override string Name => "FoodContainer";
-
- private AppearanceComponent? _appearance;
- [DataField("prototypes")]
- private Dictionary? _prototypes = default;
- [DataField("capacity")]
- private uint _capacity = 5;
-
- public int Capacity => (int)_capacity;
- [ViewVariables]
- public int Count => _count;
-
- private int _count = 0;
-
- protected override void Initialize()
- {
- base.Initialize();
- Owner.TryGetComponent(out _appearance);
- _count = Capacity;
- UpdateAppearance();
-
- }
-
- bool IUse.UseEntity(UseEntityEventArgs eventArgs)
- {
- if (!eventArgs.User.TryGetComponent(out HandsComponent? handsComponent))
- {
- return false;
- }
-
- var itemToSpawn = Owner.EntityManager.SpawnEntity(GetRandomPrototype(), Owner.Transform.Coordinates);
- handsComponent.PutInHandOrDrop(itemToSpawn.GetComponent());
- _count--;
- if (_count < 1)
- {
- Owner.Delete();
- return false;
- }
-
- return true;
- }
-
- private string? GetRandomPrototype()
- {
- var defaultProto = _prototypes?.Keys.FirstOrDefault();
-
- if (defaultProto == null)
- {
- return null;
- }
-
- DebugTools.AssertNotNull(_prototypes);
-
- if (_prototypes!.Count == 1)
- {
- return defaultProto;
- }
-
- var probResult = _random.Next(0, 100);
- var total = 0;
- foreach (var item in _prototypes)
- {
- total += item.Value;
- if (probResult < total)
- {
- return item.Key;
- }
- }
-
- return defaultProto;
- }
-
- private void UpdateAppearance()
- {
- _appearance?.SetData(FoodContainerVisuals.Current, Count);
- }
- }
-}
diff --git a/Content.Server/Pointing/EntitySystems/PointingSystem.cs b/Content.Server/Pointing/EntitySystems/PointingSystem.cs
index f31155ff11..e855c9270c 100644
--- a/Content.Server/Pointing/EntitySystems/PointingSystem.cs
+++ b/Content.Server/Pointing/EntitySystems/PointingSystem.cs
@@ -31,6 +31,7 @@ namespace Content.Server.Pointing.EntitySystems
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
+ [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
private static readonly TimeSpan PointDelay = TimeSpan.FromSeconds(0.5f);
@@ -112,7 +113,7 @@ namespace Content.Server.Pointing.EntitySystems
return false;
}
- if (EntitySystem.Get().CanChangeDirection(player))
+ if (_actionBlockerSystem.CanChangeDirection(player))
{
var diff = coords.ToMapPos(EntityManager) - player.Transform.MapPosition.Position;
if (diff.LengthSquared > 0.01f)
diff --git a/Content.Server/Power/EntitySystems/BatterySystem.cs b/Content.Server/Power/EntitySystems/BatterySystem.cs
index 44126d6810..e97b007861 100644
--- a/Content.Server/Power/EntitySystems/BatterySystem.cs
+++ b/Content.Server/Power/EntitySystems/BatterySystem.cs
@@ -11,23 +11,25 @@ namespace Content.Server.Power.EntitySystems
{
base.Initialize();
- SubscribeLocalEvent(PreSync);
- SubscribeLocalEvent(PostSync);
+ SubscribeLocalEvent(PreSync);
+ SubscribeLocalEvent(PostSync);
}
- private void PreSync(EntityUid uid, BatteryComponent component, NetworkBatteryPreSync args)
+ private void PreSync(NetworkBatteryPreSync ev)
{
- var networkBattery = ComponentManager.GetComponent(uid);
-
- networkBattery.NetworkBattery.Capacity = component.MaxCharge;
- networkBattery.NetworkBattery.CurrentStorage = component.CurrentCharge;
+ foreach (var (bat, netBat) in ComponentManager.EntityQuery())
+ {
+ netBat.NetworkBattery.Capacity = bat.MaxCharge;
+ netBat.NetworkBattery.CurrentStorage = bat.CurrentCharge;
+ }
}
- private void PostSync(EntityUid uid, BatteryComponent component, NetworkBatteryPostSync args)
+ private void PostSync(NetworkBatteryPostSync ev)
{
- var networkBattery = ComponentManager.GetComponent(uid);
-
- component.CurrentCharge = networkBattery.NetworkBattery.CurrentStorage;
+ foreach (var (bat, netBat) in ComponentManager.EntityQuery())
+ {
+ bat.CurrentCharge = netBat.NetworkBattery.CurrentStorage;
+ }
}
public override void Update(float frameTime)
diff --git a/Content.Server/Power/EntitySystems/PowerNetSystem.cs b/Content.Server/Power/EntitySystems/PowerNetSystem.cs
index 3b7f81fb25..84b65289b5 100644
--- a/Content.Server/Power/EntitySystems/PowerNetSystem.cs
+++ b/Content.Server/Power/EntitySystems/PowerNetSystem.cs
@@ -175,19 +175,13 @@ namespace Content.Server.Power.EntitySystems
}
// Synchronize batteries
- foreach (var battery in ComponentManager.EntityQuery())
- {
- RaiseLocalEvent(battery.Owner.Uid, new NetworkBatteryPreSync());
- }
+ RaiseLocalEvent(new NetworkBatteryPreSync());
// Run power solver.
_solver.Tick(frameTime, _powerState);
// Synchronize batteries, the other way around.
- foreach (var battery in ComponentManager.EntityQuery())
- {
- RaiseLocalEvent(battery.Owner.Uid, new NetworkBatteryPostSync());
- }
+ RaiseLocalEvent(new NetworkBatteryPostSync());
// Send events where necessary.
{
@@ -313,7 +307,7 @@ namespace Content.Server.Power.EntitySystems
/// Raised before power network simulation happens, to synchronize battery state from
/// components like into .
///
- public sealed class NetworkBatteryPreSync : EntityEventArgs
+ public struct NetworkBatteryPreSync
{
}
@@ -321,7 +315,7 @@ namespace Content.Server.Power.EntitySystems
/// Raised after power network simulation happens, to synchronize battery charge changes from
/// to components like .
///
- public sealed class NetworkBatteryPostSync : EntityEventArgs
+ public struct NetworkBatteryPostSync
{
}
diff --git a/Content.Server/Storage/Components/EntityStorageComponent.cs b/Content.Server/Storage/Components/EntityStorageComponent.cs
index 3ee411fd40..f8b63b6bbd 100644
--- a/Content.Server/Storage/Components/EntityStorageComponent.cs
+++ b/Content.Server/Storage/Components/EntityStorageComponent.cs
@@ -25,7 +25,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Physics;
-using Robust.Shared.Physics.Broadphase;
using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Timing;
@@ -132,7 +131,8 @@ namespace Content.Server.Storage.Components
private bool _beingWelded;
[ViewVariables(VVAccess.ReadWrite)]
- public bool CanWeldShut {
+ public bool CanWeldShut
+ {
get => _canWeldShut;
set
{
@@ -161,6 +161,13 @@ namespace Content.Server.Storage.Components
public virtual void Activate(ActivateEventArgs eventArgs)
{
+ // HACK until EntityStorageComponent gets refactored to the new ECS system
+ if (Owner.TryGetComponent(out var @lock) && @lock.Locked)
+ {
+ // Do nothing, LockSystem is responsible for handling this case
+ return;
+ }
+
ToggleOpen(eventArgs.User);
}
@@ -168,7 +175,7 @@ namespace Content.Server.Storage.Components
{
if (IsWeldedShut)
{
- if(!silent) Owner.PopupMessage(user, Loc.GetString("entity-storage-component-welded-shut-message"));
+ if (!silent) Owner.PopupMessage(user, Loc.GetString("entity-storage-component-welded-shut-message"));
return false;
}
return true;
@@ -468,7 +475,8 @@ namespace Content.Server.Storage.Components
protected virtual void OpenVerbGetData(IEntity user, EntityStorageComponent component, VerbData data)
{
- if (!EntitySystem.Get().CanInteract(user))
+ if (!EntitySystem.Get().CanInteract(user) ||
+ component.Owner.TryGetComponent(out LockComponent? lockComponent) && lockComponent.Locked) // HACK extra check, until EntityStorage gets refactored
{
data.Visibility = VerbVisibility.Invisible;
return;
@@ -478,7 +486,7 @@ namespace Content.Server.Storage.Components
{
data.Visibility = VerbVisibility.Disabled;
var verb = Loc.GetString(component.Open ? "open-toggle-verb-close" : "open-toggle-verb-open");
- data.Text = Loc.GetString("open-toggle-verb-welded-shut-message",("verb", verb));
+ data.Text = Loc.GetString("open-toggle-verb-welded-shut-message", ("verb", verb));
return;
}
diff --git a/Content.Server/Storage/Components/SecretStashComponent.cs b/Content.Server/Storage/Components/SecretStashComponent.cs
index b202ab19db..30af3865fc 100644
--- a/Content.Server/Storage/Components/SecretStashComponent.cs
+++ b/Content.Server/Storage/Components/SecretStashComponent.cs
@@ -81,7 +81,7 @@ namespace Content.Server.Storage.Components
if (_itemContainer.ContainedEntity == null)
return false;
- Owner.PopupMessage(user, Loc.GetString("There was something inside {0}!", ("stash", SecretPartName)));
+ Owner.PopupMessage(user, Loc.GetString("comp-secret-stash-action-get-item-found-something", ("stash", SecretPartName)));
if (user.TryGetComponent(out HandsComponent? hands))
{
diff --git a/Content.Server/Storage/Components/SecureEntityStorageComponent.cs b/Content.Server/Storage/Components/SecureEntityStorageComponent.cs
deleted file mode 100644
index 8c3df45b4a..0000000000
--- a/Content.Server/Storage/Components/SecureEntityStorageComponent.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-using Content.Server.Access.Components;
-using Content.Shared.ActionBlocker;
-using Content.Shared.Interaction;
-using Content.Shared.Notification.Managers;
-using Content.Shared.Sound;
-using Content.Shared.Storage;
-using Content.Shared.Verbs;
-using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Localization;
-using Robust.Shared.Player;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.Storage.Components
-{
- [RegisterComponent]
- [ComponentReference(typeof(EntityStorageComponent))]
- [ComponentReference(typeof(IActivate))]
- [ComponentReference(typeof(IStorageComponent))]
- public class SecureEntityStorageComponent : EntityStorageComponent
- {
- public override string Name => "SecureEntityStorage";
- [DataField("locked")]
- private bool _locked = true;
-
- [DataField("unlockSound")] private SoundSpecifier _unlockSound = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg");
- [DataField("lockSound")] private SoundSpecifier _lockSound = new SoundPathSpecifier("/Audio/Machines/door_lock_on.ogg");
-
- [ViewVariables(VVAccess.ReadWrite)]
- public bool Locked
- {
- get => _locked;
- set
- {
- _locked = value;
-
- if (Owner.TryGetComponent(out AppearanceComponent? appearance))
- {
- appearance.SetData(StorageVisuals.Locked, _locked);
- }
- }
- }
-
- protected override void Startup()
- {
- base.Startup();
-
- if (Owner.TryGetComponent(out AppearanceComponent? appearance))
- {
- appearance.SetData(StorageVisuals.CanLock, true);
- }
- }
-
- public override void Activate(ActivateEventArgs eventArgs)
- {
- if (Locked)
- {
- DoToggleLock(eventArgs.User);
- return;
- }
-
- base.Activate(eventArgs);
- }
-
- public override bool CanOpen(IEntity user, bool silent = false)
- {
- if (Locked)
- {
- Owner.PopupMessage(user, "It's locked!");
- return false;
- }
- return base.CanOpen(user, silent);
- }
-
- protected override void OpenVerbGetData(IEntity user, EntityStorageComponent component, VerbData data)
- {
- if (Locked)
- {
- data.Visibility = VerbVisibility.Invisible;
-
- return;
- }
-
- base.OpenVerbGetData(user, component, data);
- }
-
- private void DoToggleLock(IEntity user)
- {
- if (Locked)
- {
- DoUnlock(user);
- }
- else
- {
- DoLock(user);
- }
- }
-
- private void DoUnlock(IEntity user)
- {
- if (!CheckAccess(user)) return;
-
- Locked = false;
- if(_unlockSound.TryGetSound(out var unlockSound))
- SoundSystem.Play(Filter.Pvs(Owner), unlockSound, Owner, AudioParams.Default.WithVolume(-5));
- }
-
- private void DoLock(IEntity user)
- {
- if (!CheckAccess(user)) return;
-
- Locked = true;
- if(_lockSound.TryGetSound(out var lockSound))
- SoundSystem.Play(Filter.Pvs(Owner), lockSound, Owner, AudioParams.Default.WithVolume(-5));
- }
-
- private bool CheckAccess(IEntity user)
- {
- if (Owner.TryGetComponent(out AccessReader? reader))
- {
- if (!reader.IsAllowed(user))
- {
- Owner.PopupMessage(user, Loc.GetString("secure-entity-storage-component-not-allowed-message"));
- return false;
- }
- }
-
- return true;
- }
-
- [Verb]
- private sealed class ToggleLockVerb : Verb
- {
- protected override void GetData(IEntity user, SecureEntityStorageComponent component, VerbData data)
- {
- if (!EntitySystem.Get().CanInteract(user) || component.Open)
- {
- data.Visibility = VerbVisibility.Invisible;
- return;
- }
-
- data.Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock");
- }
-
- protected override void Activate(IEntity user, SecureEntityStorageComponent component)
- {
- component.DoToggleLock(user);
- }
- }
- }
-}
diff --git a/Content.Server/Storage/Components/ServerStorageComponent.cs b/Content.Server/Storage/Components/ServerStorageComponent.cs
index 9721b5f9e0..14654a38ac 100644
--- a/Content.Server/Storage/Components/ServerStorageComponent.cs
+++ b/Content.Server/Storage/Components/ServerStorageComponent.cs
@@ -16,6 +16,7 @@ using Content.Shared.Notification;
using Content.Shared.Notification.Managers;
using Content.Shared.Sound;
using Content.Shared.Storage;
+using Content.Shared.Whitelist;
using Robust.Server.GameObjects;
using Robust.Server.Player;
using Robust.Shared.Audio;
@@ -48,10 +49,16 @@ namespace Content.Server.Storage.Components
[DataField("occludesLight")]
private bool _occludesLight = true;
+
[DataField("quickInsert")]
- private bool _quickInsert; //Can insert storables by "attacking" them with the storage entity
+ private bool _quickInsert = false; // Can insert storables by "attacking" them with the storage entity
+
[DataField("areaInsert")]
- private bool _areaInsert; //"Attacking" with the storage entity causes it to insert all nearby storables after a delay
+ private bool _areaInsert = false; // "Attacking" with the storage entity causes it to insert all nearby storables after a delay
+
+ [DataField("whitelist")]
+ private EntityWhitelist? _whitelist = null;
+
private bool _storageInitialCalculated;
private int _storageUsed;
[DataField("capacity")]
@@ -124,6 +131,11 @@ namespace Content.Server.Storage.Components
return false;
}
+ if (_whitelist != null && !_whitelist.IsValid(entity))
+ {
+ return false;
+ }
+
return true;
}
diff --git a/Content.Server/Storage/Components/SpawnItemsOnUseComponent.cs b/Content.Server/Storage/Components/SpawnItemsOnUseComponent.cs
new file mode 100644
index 0000000000..0956e8a5f3
--- /dev/null
+++ b/Content.Server/Storage/Components/SpawnItemsOnUseComponent.cs
@@ -0,0 +1,36 @@
+using System.Collections.Generic;
+using Content.Shared.Sound;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+
+namespace Content.Server.Storage.Components
+{
+ ///
+ /// Spawns items when used in hand.
+ ///
+ [RegisterComponent]
+ public class SpawnItemsOnUseComponent : Component
+ {
+ public override string Name => "SpawnItemsOnUse";
+
+ ///
+ /// The list of entities to spawn, with amounts and orGroups.
+ ///
+ ///
+ [DataField("items", required: true)]
+ public List Items = new List();
+
+ ///
+ /// A sound to play when the items are spawned. For example, gift boxes being unwrapped.
+ ///
+ [DataField("sound")]
+ public SoundSpecifier? Sound = null;
+
+ ///
+ /// How many uses before the item should delete itself.
+ ///
+ ///
+ [DataField("uses")]
+ public int Uses = 1;
+ }
+}
diff --git a/Content.Server/Storage/Components/StorageFillComponent.cs b/Content.Server/Storage/Components/StorageFillComponent.cs
index 788a1727bb..ed56832fb8 100644
--- a/Content.Server/Storage/Components/StorageFillComponent.cs
+++ b/Content.Server/Storage/Components/StorageFillComponent.cs
@@ -17,9 +17,9 @@ namespace Content.Server.Storage.Components
{
public override string Name => "StorageFill";
- [DataField("contents")] private List _contents = new();
+ [DataField("contents")] private List _contents = new();
- public IReadOnlyList Contents => _contents;
+ public IReadOnlyList Contents => _contents;
void IMapInit.MapInit()
{
@@ -39,7 +39,6 @@ namespace Content.Server.Storage.Components
var alreadySpawnedGroups = new List();
foreach (var storageItem in _contents)
{
- if (string.IsNullOrEmpty(storageItem.PrototypeId)) continue;
if (!string.IsNullOrEmpty(storageItem.GroupId) &&
alreadySpawnedGroups.Contains(storageItem.GroupId)) continue;
@@ -58,50 +57,5 @@ namespace Content.Server.Storage.Components
if (!string.IsNullOrEmpty(storageItem.GroupId)) alreadySpawnedGroups.Add(storageItem.GroupId);
}
}
-
- [Serializable]
- [DataDefinition]
- public struct StorageFillEntry : IPopulateDefaultValues
- {
- [DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer))]
- public string? PrototypeId;
-
- [DataField("prob")] public float SpawnProbability;
-
- ///
- /// The probability that an item will spawn. Takes decimal form so 0.05 is 5%, 0.50 is 50% etc.
- ///
- [DataField("orGroup")] public string GroupId;
-
- ///
- /// orGroup signifies to pick between entities designated with an ID.
- ///
- ///
- /// To define an orGroup in a StorageFill component you
- /// need to add it to the entities you want to choose between and
- /// add a prob field. In this example there is a 50% chance the storage
- /// spawns with Y or Z.
- ///
- ///
- ///
- /// - type: StorageFill
- /// contents:
- /// - name: X
- /// - name: Y
- /// prob: 0.50
- /// orGroup: YOrZ
- /// - name: Z
- /// orGroup: YOrZ
- ///
- ///
- ///
- [DataField("amount")] public int Amount;
-
- public void PopulateDefaultValues()
- {
- Amount = 1;
- SpawnProbability = 1;
- }
- }
}
}
diff --git a/Content.Server/Storage/EntitySpawnEntry.cs b/Content.Server/Storage/EntitySpawnEntry.cs
new file mode 100644
index 0000000000..99080980c0
--- /dev/null
+++ b/Content.Server/Storage/EntitySpawnEntry.cs
@@ -0,0 +1,59 @@
+using System;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.Manager;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Storage
+{
+ ///
+ /// Dictates a list of items that can be spawned.
+ ///
+ [Serializable]
+ [DataDefinition]
+ public struct EntitySpawnEntry : IPopulateDefaultValues
+ {
+ [DataField("id", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))]
+ public string PrototypeId;
+
+ ///
+ /// The probability that an item will spawn. Takes decimal form so 0.05 is 5%, 0.50 is 50% etc.
+ ///
+ [DataField("prob")]
+ public float SpawnProbability;
+
+ ///
+ /// orGroup signifies to pick between entities designated with an ID.
+ ///
+ ///
+ /// To define an orGroup in a StorageFill component you
+ /// need to add it to the entities you want to choose between and
+ /// add a prob field. In this example there is a 50% chance the storage
+ /// spawns with Y or Z.
+ ///
+ ///
+ ///
+ /// - type: StorageFill
+ /// contents:
+ /// - name: X
+ /// - name: Y
+ /// prob: 0.50
+ /// orGroup: YOrZ
+ /// - name: Z
+ /// orGroup: YOrZ
+ ///
+ ///
+ ///
+ [DataField("orGroup")]
+ public string? GroupId;
+
+ [DataField("amount")]
+ public int Amount;
+
+ public void PopulateDefaultValues()
+ {
+ Amount = 1;
+ SpawnProbability = 1;
+ }
+ }
+}
diff --git a/Content.Server/Storage/ItemCounterSystem.cs b/Content.Server/Storage/EntitySystems/ItemCounterSystem.cs
similarity index 96%
rename from Content.Server/Storage/ItemCounterSystem.cs
rename to Content.Server/Storage/EntitySystems/ItemCounterSystem.cs
index 9e79ab984f..cdd53e335c 100644
--- a/Content.Server/Storage/ItemCounterSystem.cs
+++ b/Content.Server/Storage/EntitySystems/ItemCounterSystem.cs
@@ -5,7 +5,7 @@ using JetBrains.Annotations;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
-namespace Content.Server.Storage
+namespace Content.Server.Storage.EntitySystems
{
[UsedImplicitly]
public class ItemCounterSystem : SharedItemCounterSystem
diff --git a/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs b/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs
new file mode 100644
index 0000000000..e694aa237a
--- /dev/null
+++ b/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs
@@ -0,0 +1,68 @@
+using System.Collections.Generic;
+using Content.Server.Storage.Components;
+using Content.Shared.Hands.Components;
+using Content.Shared.Interaction;
+using Robust.Shared.Audio;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Player;
+using Robust.Shared.Random;
+
+namespace Content.Server.Storage.EntitySystems
+{
+ public class SpawnItemsOnUseSystem : EntitySystem
+ {
+ [Dependency] private readonly IRobustRandom _random = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnUseInHand);
+ }
+
+ private void OnUseInHand(EntityUid uid, SpawnItemsOnUseComponent component, UseInHandEvent args)
+ {
+ if (args.Handled)
+ return;
+
+ var owner = EntityManager.GetEntity(uid);
+ var alreadySpawnedGroups = new List();
+ IEntity? entityToPlaceInHands = null;
+ foreach (var storageItem in component.Items)
+ {
+ if (!string.IsNullOrEmpty(storageItem.GroupId) &&
+ alreadySpawnedGroups.Contains(storageItem.GroupId)) continue;
+
+ if (storageItem.SpawnProbability != 1f &&
+ !_random.Prob(storageItem.SpawnProbability))
+ {
+ continue;
+ }
+
+ for (var i = 0; i < storageItem.Amount; i++)
+ {
+ entityToPlaceInHands = EntityManager.SpawnEntity(storageItem.PrototypeId, args.User.Transform.Coordinates);
+ }
+
+ if (!string.IsNullOrEmpty(storageItem.GroupId)) alreadySpawnedGroups.Add(storageItem.GroupId);
+ }
+
+ if (component.Sound != null)
+ SoundSystem.Play(Filter.Pvs(owner), component.Sound.GetSound());
+
+ component.Uses--;
+ if (component.Uses == 0)
+ {
+ args.Handled = true;
+ owner.Delete();
+ }
+
+ if (entityToPlaceInHands != null
+ && args.User.TryGetComponent(out var hands))
+ {
+ hands.TryPutInAnyHand(entityToPlaceInHands);
+ }
+ }
+ }
+}
diff --git a/Content.Server/Storage/StorageSystem.cs b/Content.Server/Storage/EntitySystems/StorageSystem.cs
similarity index 98%
rename from Content.Server/Storage/StorageSystem.cs
rename to Content.Server/Storage/EntitySystems/StorageSystem.cs
index 73cf367254..d80a8e32a9 100644
--- a/Content.Server/Storage/StorageSystem.cs
+++ b/Content.Server/Storage/EntitySystems/StorageSystem.cs
@@ -6,7 +6,7 @@ using Robust.Server.Player;
using Robust.Shared.Containers;
using Robust.Shared.GameObjects;
-namespace Content.Server.Storage
+namespace Content.Server.Storage.EntitySystems
{
[UsedImplicitly]
internal sealed class StorageSystem : EntitySystem
@@ -54,7 +54,7 @@ namespace Content.Server.Storage
{
storageComp.HandleEntityMaybeInserted(message);
}
-
+
if (oldParentEntity.TryGetComponent(out var newStorageComp))
{
newStorageComp.ContainerUpdateAppearance(message.Container);
diff --git a/Content.Shared/Atmos/AtmosDirection.cs b/Content.Shared/Atmos/AtmosDirection.cs
index 96023a55e8..5093b5245b 100644
--- a/Content.Shared/Atmos/AtmosDirection.cs
+++ b/Content.Shared/Atmos/AtmosDirection.cs
@@ -142,6 +142,28 @@ namespace Content.Shared.Atmos
{
return (direction & other) == other;
}
+
+ public static Vector2i CardinalToIntVec(this Direction dir)
+ {
+ switch (dir)
+ {
+ case Direction.North:
+ return new Vector2i(0, 1);
+ case Direction.East:
+ return new Vector2i(1, 0);
+ case Direction.South:
+ return new Vector2i(0, -1);
+ case Direction.West:
+ return new Vector2i(-1, 0);
+ default:
+ throw new ArgumentException($"Direction dir {dir} is not a cardinal direction", nameof(dir));
+ }
+ }
+
+ public static Vector2i Offset(this Vector2i pos, Direction dir)
+ {
+ return pos + dir.CardinalToIntVec();
+ }
}
public sealed class AtmosDirectionFlags { }
diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs
index b2736ebf68..53d34fa40c 100644
--- a/Content.Shared/Atmos/Atmospherics.cs
+++ b/Content.Shared/Atmos/Atmospherics.cs
@@ -1,6 +1,7 @@
using Robust.Shared.Maths;
using Robust.Shared.Serialization;
using System;
+// ReSharper disable InconsistentNaming
namespace Content.Shared.Atmos
{
diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs
index 3656505a4e..3b2091492c 100644
--- a/Content.Shared/CCVar/CCVars.cs
+++ b/Content.Shared/CCVar/CCVars.cs
@@ -175,6 +175,12 @@ namespace Content.Shared.CCVar
* Physics
*/
+ ///
+ /// When a mob is walking should its X / Y movement be relative to its parent (true) or the map (false).
+ ///
+ public static readonly CVarDef RelativeMovement =
+ CVarDef.Create("physics.relative_movement", true, CVar.ARCHIVE | CVar.REPLICATED);
+
public static readonly CVarDef TileFrictionModifier =
CVarDef.Create("physics.tile_friction", 40.0f);
@@ -285,7 +291,6 @@ namespace Content.Shared.CCVar
public static readonly CVarDef AtmosGridImpulse =
CVarDef.Create("atmos.grid_impulse", false, CVar.SERVERONLY);
-
///
/// Whether atmos superconduction is enabled.
///
@@ -293,10 +298,17 @@ namespace Content.Shared.CCVar
public static readonly CVarDef Superconduction =
CVarDef.Create("atmos.superconduction", false, CVar.SERVERONLY);
+ ///
+ /// Whether excited groups will be processed and created.
+ ///
+ public static readonly CVarDef ExcitedGroups =
+ CVarDef.Create("atmos.excited_groups", true, CVar.SERVERONLY);
+
///
/// Whether all tiles in an excited group will clear themselves once being exposed to space.
/// Similar to , without none of the tile ripping or
/// things being thrown around very violently.
+ /// Needs to be enabled to work.
///
public static readonly CVarDef ExcitedGroupsSpaceIsAllConsuming =
CVarDef.Create("atmos.excited_groups_space_is_all_consuming", false, CVar.SERVERONLY);
diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs
index 7f50cf0063..0d02792593 100644
--- a/Content.Shared/Interaction/SharedInteractionSystem.cs
+++ b/Content.Shared/Interaction/SharedInteractionSystem.cs
@@ -4,6 +4,7 @@ using Content.Shared.Notification.Managers;
using Content.Shared.Physics;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Physics;
@@ -17,6 +18,8 @@ namespace Content.Shared.Interaction
[UsedImplicitly]
public class SharedInteractionSystem : EntitySystem
{
+ [Dependency] private readonly SharedBroadphaseSystem _sharedBroadphaseSystem = default!;
+
public const float InteractionRange = 2;
public const float InteractionRangeSquared = InteractionRange * InteractionRange;
@@ -46,7 +49,7 @@ namespace Content.Shared.Interaction
predicate ??= _ => false;
var ray = new CollisionRay(origin.Position, dir.Normalized, collisionMask);
- var rayResults = Get().IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();
+ var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();
if (rayResults.Count == 0) return dir.Length;
return (rayResults[0].HitPos - origin.Position).Length;
@@ -122,7 +125,7 @@ namespace Content.Shared.Interaction
predicate ??= _ => false;
var ray = new CollisionRay(origin.Position, dir.Normalized, (int) collisionMask);
- var rayResults = Get().IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();
+ var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList();
if (rayResults.Count == 0) return true;
diff --git a/Content.Shared/Kitchen/Components/SharedReagentGrinderComponent.cs b/Content.Shared/Kitchen/Components/SharedReagentGrinderComponent.cs
index ca1eae6923..0effbe15db 100644
--- a/Content.Shared/Kitchen/Components/SharedReagentGrinderComponent.cs
+++ b/Content.Shared/Kitchen/Components/SharedReagentGrinderComponent.cs
@@ -51,16 +51,6 @@ namespace Content.Shared.Kitchen.Components
}
}
- [Serializable, NetSerializable]
- public class ReagentGrinderVaporizeReagentIndexedMessage : BoundUserInterfaceMessage
- {
- public Solution.ReagentQuantity ReagentQuantity;
- public ReagentGrinderVaporizeReagentIndexedMessage(Solution.ReagentQuantity reagentQuantity)
- {
- ReagentQuantity = reagentQuantity;
- }
- }
-
[Serializable, NetSerializable]
public class ReagentGrinderWorkStartedMessage : BoundUserInterfaceMessage
{
diff --git a/Content.Shared/Movement/SharedMoverController.cs b/Content.Shared/Movement/SharedMoverController.cs
index d48d7ff3b9..0c1bc416a9 100644
--- a/Content.Shared/Movement/SharedMoverController.cs
+++ b/Content.Shared/Movement/SharedMoverController.cs
@@ -1,7 +1,9 @@
using Content.Shared.ActionBlocker;
+using Content.Shared.CCVar;
using Content.Shared.MobState;
using Content.Shared.Movement.Components;
using Content.Shared.Pulling.Components;
+using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
@@ -9,6 +11,7 @@ using Robust.Shared.Maths;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Broadphase;
using Robust.Shared.Physics.Controllers;
+using Robust.Shared.Utility;
namespace Content.Shared.Movement
{
@@ -22,10 +25,14 @@ namespace Content.Shared.Movement
private SharedBroadphaseSystem _broadPhaseSystem = default!;
+ private bool _relativeMovement;
+
public override void Initialize()
{
base.Initialize();
_broadPhaseSystem = EntitySystem.Get();
+ var configManager = IoCManager.Resolve();
+ configManager.OnValueChanged(CCVars.RelativeMovement, value => _relativeMovement = value, true);
}
///
@@ -39,12 +46,14 @@ namespace Content.Shared.Movement
// Target velocity.
var total = (walkDir * mover.CurrentWalkSpeed + sprintDir * mover.CurrentSprintSpeed);
- if (total != Vector2.Zero)
+ var worldTotal = _relativeMovement ? new Angle(mover.Owner.Transform.Parent!.WorldRotation.Theta).RotateVec(total) : total;
+
+ if (worldTotal != Vector2.Zero)
{
- mover.Owner.Transform.LocalRotation = total.GetDir().ToAngle();
+ mover.Owner.Transform.WorldRotation = worldTotal.GetDir().ToAngle();
}
- physicsComponent.LinearVelocity = total;
+ physicsComponent.LinearVelocity = worldTotal;
}
///
@@ -53,7 +62,8 @@ namespace Content.Shared.Movement
///
///
///
- protected void HandleMobMovement(IMoverComponent mover, PhysicsComponent physicsComponent, IMobMoverComponent mobMover)
+ protected void HandleMobMovement(IMoverComponent mover, PhysicsComponent physicsComponent,
+ IMobMoverComponent mobMover)
{
// TODO: Look at https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/CharacterControllers.html?highlight=controller as it has some adviceo n kinematic controllersx
if (!UseMobMovement(_broadPhaseSystem, physicsComponent, _mapManager))
@@ -74,30 +84,37 @@ namespace Content.Shared.Movement
if (!touching)
{
- transform.LocalRotation = physicsComponent.LinearVelocity.GetDir().ToAngle();
+ transform.WorldRotation = physicsComponent.LinearVelocity.GetDir().ToAngle();
return;
}
}
// Regular movement.
// Target velocity.
+ // This is relative to the map / grid we're on.
var total = (walkDir * mover.CurrentWalkSpeed + sprintDir * mover.CurrentSprintSpeed);
+ var worldTotal = _relativeMovement ?
+ new Angle(transform.Parent!.WorldRotation.Theta).RotateVec(total) :
+ total;
+
+ DebugTools.Assert(MathHelper.CloseTo(total.Length, worldTotal.Length));
+
if (weightless)
{
- total *= mobMover.WeightlessStrength;
+ worldTotal *= mobMover.WeightlessStrength;
}
- if (total != Vector2.Zero)
+ if (worldTotal != Vector2.Zero)
{
// This should have its event run during island solver soooo
transform.DeferUpdates = true;
- transform.LocalRotation = total.GetDir().ToAngle();
+ transform.WorldRotation = worldTotal.GetDir().ToAngle();
transform.DeferUpdates = false;
HandleFootsteps(mover, mobMover);
}
- physicsComponent.LinearVelocity = total;
+ physicsComponent.LinearVelocity = worldTotal;
}
public static bool UseMobMovement(SharedBroadphaseSystem broadPhaseSystem, PhysicsComponent body, IMapManager mapManager)
diff --git a/Content.Shared/Nutrition/Components/SharedDrinkFoodContainerComponent.cs b/Content.Shared/Nutrition/Components/SharedDrinkFoodContainerComponent.cs
deleted file mode 100644
index a4fb1d0288..0000000000
--- a/Content.Shared/Nutrition/Components/SharedDrinkFoodContainerComponent.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using System;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.Nutrition.Components
-{
- public abstract class SharedFoodContainerComponent : Component
- {
- }
-
- [NetSerializable, Serializable]
- public enum FoodContainerVisualMode
- {
- ///
- /// Discrete: 50 eggs in a carton -> down to 25, will show 12/12 until it gets below max
- /// Rounded: 50 eggs in a carton -> down to 25, will round it to 6 of 12
- ///
- Discrete,
- Rounded,
- }
-
- [NetSerializable, Serializable]
- public enum FoodContainerVisuals
- {
- Capacity,
- Current,
- }
-}
diff --git a/Content.Shared/SubFloor/SubFloorHideComponent.cs b/Content.Shared/SubFloor/SubFloorHideComponent.cs
index a76c73473e..93587e6f8c 100644
--- a/Content.Shared/SubFloor/SubFloorHideComponent.cs
+++ b/Content.Shared/SubFloor/SubFloorHideComponent.cs
@@ -1,4 +1,6 @@
using Robust.Shared.GameObjects;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
namespace Content.Shared.SubFloor
{
@@ -13,5 +15,12 @@ namespace Content.Shared.SubFloor
{
///
public override string Name => "SubFloorHide";
+
+ ///
+ /// This entity needs to be anchored to be hid in the subfloor.
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("requireAnchored")]
+ public bool RequireAnchored { get; set; } = true;
}
}
diff --git a/Content.Shared/SubFloor/SubFloorHideSystem.cs b/Content.Shared/SubFloor/SubFloorHideSystem.cs
index 5dd30a86a3..6f3f5bd9f2 100644
--- a/Content.Shared/SubFloor/SubFloorHideSystem.cs
+++ b/Content.Shared/SubFloor/SubFloorHideSystem.cs
@@ -68,8 +68,7 @@ namespace Content.Shared.SubFloor
var transform = ComponentManager.GetComponent(uid);
// We do this directly instead of calling UpdateEntity.
- if(_mapManager.TryGetGrid(transform.GridID, out var grid))
- UpdateTile(grid, grid.TileIndicesFor(transform.Coordinates));
+ UpdateEntity(uid);
}
private void MapManagerOnTileChanged(object? sender, TileChangedEventArgs e)
@@ -113,6 +112,7 @@ namespace Content.Shared.SubFloor
private void UpdateEntity(EntityUid uid)
{
var transform = ComponentManager.GetComponent(uid);
+
if (!_mapManager.TryGetGrid(transform.GridID, out var grid))
{
// Not being on a grid counts as no subfloor, unhide this.
@@ -134,6 +134,18 @@ namespace Content.Shared.SubFloor
if (subFloorHideEvent.Handled)
return;
+ // This might look weird, but basically we only need to query the SubFloorHide and Transform components
+ // if we are gonna hide the entity and we require it to be anchored to be hidden. Because getting components
+ // is "expensive", we have a slow path where we query them, and a fast path where we don't.
+ if (!subFloor
+ && ComponentManager.TryGetComponent(uid, out SubFloorHideComponent? subFloorHideComponent) &&
+ subFloorHideComponent.RequireAnchored
+ && ComponentManager.TryGetComponent(uid, out ITransformComponent? transformComponent))
+ {
+ // If we require the entity to be anchored but it's not, this will set subfloor to true, unhiding it.
+ subFloor = !transformComponent.Anchored;
+ }
+
// Show sprite
if (ComponentManager.TryGetComponent(uid, out SharedSpriteComponent? spriteComponent))
{
diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml
index 95ed321f80..62bb69b3ae 100644
--- a/Resources/Changelog/Changelog.yml
+++ b/Resources/Changelog/Changelog.yml
@@ -1588,3 +1588,28 @@ Entries:
- {message: Items with missing inhand sprites no longer show a giant ERROR, type: Fix}
id: 282
time: '2021-07-25T10:02:48.0000000+00:00'
+- author: Seth
+ changes:
+ - {message: Added Makeshift Handcuffs into the construction list, type: Add}
+ id: 283
+ time: '2021-07-25T15:30:42.0000000+00:00'
+- author: metalgearsloth
+ changes:
+ - {message: Shuttle-relative movement for when we get shuttle rotation., type: Add}
+ id: 284
+ time: '2021-07-25T15:48:22.0000000+00:00'
+- author: Seth
+ changes:
+ - {message: Added Storage Room to Coats, type: Add}
+ id: 285
+ time: '2021-07-26T05:36:27.0000000+00:00'
+- author: Seth
+ changes:
+ - {message: Added a hardsuit into research directors locker, type: Add}
+ id: 286
+ time: '2021-07-26T22:14:10.0000000+00:00'
+- author: Seth
+ changes:
+ - {message: Added bio suits into bio lockers, type: Add}
+ id: 287
+ time: '2021-07-28T17:36:06.0000000+00:00'
diff --git a/Resources/Locale/en-US/chat/managers/chat-manager.ftl b/Resources/Locale/en-US/chat/managers/chat-manager.ftl
index 02b71db263..01b43a67c6 100644
--- a/Resources/Locale/en-US/chat/managers/chat-manager.ftl
+++ b/Resources/Locale/en-US/chat/managers/chat-manager.ftl
@@ -13,7 +13,7 @@ chat-manager-sender-announcement-wrap-message = {$sender} Announcement:
chat-manager-entity-say-wrap-message = {$entityName} says: "{"{0}"}"
chat-manager-entity-me-wrap-message = {$entityName} {"{0}"}
chat-manager-send-ooc-wrap-message = OOC: {$playerName}: {"{0}"}
-chat-manager-send-ooc-patron-wrap-message = OOC: [color={$patronColor}]{$playerName}[/color]: {"{0}"}:
+chat-manager-send-ooc-patron-wrap-message = OOC: [color={$patronColor}]{$playerName}[/color]: {"{0}"}
chat-manager-send-dead-chat-wrap-message = {$deadChannelName}: {$playerName}: {"{0}"}
chat-manager-send-admin-dead-chat-wrap-message = {$adminChannelName}:({$userName}): {"{0}"}
chat-manager-send-admin-chat-wrap-message = {$adminChannelName}: {$playerName}: {"{0}"}
@@ -21,4 +21,4 @@ chat-manager-send-admin-announcement-wrap-message = {$adminChannelName}: {"{0}"}
chat-manager-send-hook-ooc-wrap-message = OOC: (D){$senderName}: {"{0}"}
chat-manager-dead-channel-name = DEAD
-chat-manager-admin-channel-name = ADMIN
\ No newline at end of file
+chat-manager-admin-channel-name = ADMIN
diff --git a/Resources/Locale/en-US/lock/lock-component.ftl b/Resources/Locale/en-US/lock/lock-component.ftl
new file mode 100644
index 0000000000..f9f975c96e
--- /dev/null
+++ b/Resources/Locale/en-US/lock/lock-component.ftl
@@ -0,0 +1,10 @@
+lock-comp-on-examined-is-locked = The {$entityName} seems to be locked.
+lock-comp-on-examined-is-unlocked = The {$entityName} seems to be unlocked.
+lock-comp-do-lock-success = You lock the {$entityName}.
+lock-comp-do-unlock-success = You unlock the {$entityName}.
+lock-comp-has-user-access-fail = Access denied
+
+## ToggleLockVerb
+
+toggle-lock-verb-unlock = Unlock
+toggle-lock-verb-lock = Lock
\ No newline at end of file
diff --git a/Resources/Locale/en-US/storage/components/secure-entity-storage-component.ftl b/Resources/Locale/en-US/storage/components/secure-entity-storage-component.ftl
deleted file mode 100644
index 02082f2dcc..0000000000
--- a/Resources/Locale/en-US/storage/components/secure-entity-storage-component.ftl
+++ /dev/null
@@ -1,6 +0,0 @@
-secure-entity-storage-component-not-allowed-message = Access denied
-
-## ToggleLockVerb
-
-toggle-lock-verb-unlock = Unlock
-toggle-lock-verb-lock = Lock
\ No newline at end of file
diff --git a/Resources/Maps/saltern.yml b/Resources/Maps/saltern.yml
index 2c0fd2c5ac..8ca177e8e3 100644
--- a/Resources/Maps/saltern.yml
+++ b/Resources/Maps/saltern.yml
@@ -12318,15 +12318,6 @@ entities:
uniqueMixes:
- volume: 2500
temperature: 293.15
- molesArchived:
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
- - 0
moles:
- 21.824879
- 82.10312
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/biohazard.yml b/Resources/Prototypes/Catalog/Fills/Lockers/biohazard.yml
index b9a6ce5322..79b38ef7cc 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/biohazard.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/biohazard.yml
@@ -1,24 +1,59 @@
-# - type: entity
-# id: ClosetL3Filled
-# suffix: Filled, Generic
-# parent: ClosetL3
+ - type: entity
+ id: ClosetL3Filled
+ suffix: Filled, Generic
+ parent: ClosetL3
+ components:
+ - type: StorageFill
+ contents:
+ - id: ClothingOuterBioGeneral
+ prob: 1
+ - id: ClothingHeadHatHoodBioGeneral
+ prob: 1
- type: entity
id: ClosetL3VirologyFilled
suffix: Filled, Virology
parent: ClosetL3Virology
+ components:
+ - type: StorageFill
+ contents:
+ - id: ClothingOuterBioVirology
+ prob: 1
+ - id: ClothingHeadHatHoodBioVirology
+ prob: 1
- type: entity
id: ClosetL3SecurityFilled
suffix: Filled, Security
parent: ClosetL3Security
+ components:
+ - type: StorageFill
+ contents:
+ - id: ClothingOuterBioSecurity
+ prob: 1
+ - id: ClothingHeadHatHoodBioSecurity
+ prob: 1
- type: entity
id: ClosetL3JanitorFilled
suffix: Filled, Janitor
parent: ClosetL3Janitor
+ components:
+ - type: StorageFill
+ contents:
+ - id: ClothingOuterBioJanitor
+ prob: 1
+ - id: ClothingHeadHatHoodBioJanitor
+ prob: 1
-# - type: entity
-# id: ClosetL3ScienceFilled
-# suffix: Filled, Science
-# parent: ClosetL3Virology
+ - type: entity
+ id: ClosetL3ScienceFilled
+ suffix: Filled, Science
+ parent: ClosetL3Virology
+ components:
+ - type: StorageFill
+ contents:
+ - id: ClothingOuterBioScientist
+ prob: 1
+ - id: ClothingHeadHatHoodBioScientist
+ prob: 1
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
index f8df3df691..415db3246d 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml
@@ -147,6 +147,10 @@
prob: 1
- id: ClothingHeadsetMedicalScience
prob: 1
+ - id: ClothingHeadHelmetHardsuitRd
+ prob: 1
+ - id: ClothingOuterHardsuitRd
+ prob: 1
- id: PlushieSlime
prob: 0.1
diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/service.yml b/Resources/Prototypes/Catalog/Fills/Lockers/service.yml
index b753048f50..d2e13f35e9 100644
--- a/Resources/Prototypes/Catalog/Fills/Lockers/service.yml
+++ b/Resources/Prototypes/Catalog/Fills/Lockers/service.yml
@@ -72,6 +72,8 @@
prob: 1
- id: ClothingOuterApronBotanist
prob: 0.8
+ - id: ClothingBeltPlant
+ prob: 1
- id: TowercapSeeds
prob: 1
- id: BananaSeeds
diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
index b6654eec1b..e8662570c4 100644
--- a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
+++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml
@@ -8,6 +8,8 @@
sprite: Clothing/OuterClothing/Coats/bomber.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/bomber.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -19,6 +21,8 @@
sprite: Clothing/OuterClothing/Coats/detective.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/detective.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -30,6 +34,8 @@
sprite: Clothing/OuterClothing/Coats/gentlecoat.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/gentlecoat.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -41,6 +47,8 @@
sprite: Clothing/OuterClothing/Coats/hos_trenchcoat.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/hos_trenchcoat.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -52,6 +60,8 @@
sprite: Clothing/OuterClothing/Coats/insp_coat.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/insp_coat.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -63,6 +73,8 @@
sprite: Clothing/OuterClothing/Coats/jensencoat.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/jensencoat.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -74,6 +86,8 @@
sprite: Clothing/OuterClothing/Coats/labcoat.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/labcoat.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -85,6 +99,8 @@
sprite: Clothing/OuterClothing/Coats/labcoat_chem.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/labcoat_chem.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -96,6 +112,8 @@
sprite: Clothing/OuterClothing/Coats/labcoat_cmo.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/labcoat_cmo.rsi
+ - type: Storage
+ capacity: 10
- type: entity
parent: ClothingOuterBase
@@ -107,3 +125,5 @@
sprite: Clothing/OuterClothing/Coats/pirate.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Coats/pirate.rsi
+ - type: Storage
+ capacity: 10
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml
index 32623c81ea..25b22164db 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml
@@ -1,8 +1,5 @@
# Base
-- type: Tag
- id: Donut
-
- type: entity
parent: BaseItem
id: FoodDonutBase
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml
index 87bfb0cd8c..c5d94a8ded 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml
@@ -21,6 +21,9 @@
count: 8
- type: Item
size: 8
+ - type: Tag
+ tags:
+ - Pizza
- type: entity
parent: FoodPizzaBase
@@ -37,6 +40,9 @@
Quantity: 5
- type: Item
size: 1
+ - type: Tag
+ tags:
+ - Pizza
# Pizza
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml
index b3264ef81e..da91d4b718 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml
@@ -8,7 +8,7 @@
- type: entity
parent: BaseItem
id: FoodBoxDonut
- name: donutbox
+ name: donut box
description: Mmm, Donuts.
components:
- type: Sprite
@@ -17,6 +17,9 @@
state: box
- type: Storage
capacity: 6
+ whitelist:
+ tags:
+ - Donut
- type: Item
sprite: Objects/Consumable/Food/Baked/donut.rsi
size: 6
@@ -48,7 +51,7 @@
- type: entity
parent: BaseItem
id: FoodContainerEgg
- name: eggbox
+ name: egg carton
description: Don't drop 'em!
components:
- type: Sprite
@@ -57,6 +60,9 @@
state: box-closed
- type: Storage
capacity: 12
+ whitelist:
+ tags:
+ - Egg
- type: Item
sprite: Objects/Consumable/Food/egg.rsi
size: 12
@@ -114,6 +120,7 @@
- type: entity
parent: FoodContainerEgg
id: EggBoxBroken
+ suffix: Broken
components:
- type: StorageFill
contents:
@@ -261,6 +268,9 @@
sprite: Objects/Consumable/Food/Baked/donkpocket.rsi
state: box
- type: Storage
+ whitelist:
+ tags:
+ - DonkPocket
capacity: 6
- type: Item
sprite: Objects/Consumable/Food/Baked/donkpocket.rsi
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml
index f2896a2ba0..886827dcd8 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml
@@ -1,8 +1,5 @@
# Base
-- type: Tag
- id: Egg
-
- type: entity
parent: BaseItem
id: FoodEggBase
@@ -66,7 +63,7 @@
- type: Puddle
variants: 4
state: egg
-
+
- type: entity
name: eggshells
parent: BaseItem
@@ -86,6 +83,9 @@
reagents:
- ReagentId: Egg
Quantity: 1
+ - type: Tag
+ tags:
+ - Egg
# Egg
diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml
index 9a55077392..7308ac01ce 100644
--- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml
+++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml
@@ -4,10 +4,15 @@
id: PackPaperRolling
description: "A pack of thin pieces of paper used to make fine smokeables."
components:
- # I know but it just works.
- - type: FoodContainer
- prototypes:
- PaperRolling: 100
+ - type: Storage
+ whitelist:
+ tags:
+ - RollingPaper
+ capacity: 16
+ - type: StorageFill
+ contents:
+ - id: PaperRolling
+ amount: 8
- type: Sprite
sprite: Objects/Consumable/Smokeables/Cigarettes/paper.rsi
state: cigpapers
@@ -29,6 +34,10 @@
state: cigpaper
- type: Item
sprite: Objects/Consumable/Smokeables/Cigarettes/paper.rsi
+ size: 2
+ - type: Tag
+ tags:
+ - RollingPaper
- type: entity
id: CigaretteFilter
diff --git a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml
index 675f7e2642..23229182c1 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml
@@ -42,6 +42,9 @@
startUncuffSound: /Audio/Items/Handcuffs/rope_start.ogg
endUncuffSound: /Audio/Items/Handcuffs/rope_breakout.ogg
startBreakoutSound: /Audio/Items/Handcuffs/rope_takeoff.ogg
+ - type: Construction
+ graph: makeshifthandcuffs
+ node: cuffscable
- type: Sprite
sprite: Objects/Misc/cablecuffs.rsi
diff --git a/Resources/Prototypes/Entities/Objects/Misc/monkeycube.yml b/Resources/Prototypes/Entities/Objects/Misc/monkeycube.yml
index 396e7ae7fe..263d026607 100644
--- a/Resources/Prototypes/Entities/Objects/Misc/monkeycube.yml
+++ b/Resources/Prototypes/Entities/Objects/Misc/monkeycube.yml
@@ -4,9 +4,15 @@
id: MonkeyCubeBox
description: Drymate brand monkey cubes. Just add water!
components:
- - type: FoodContainer
- prototypes:
- MonkeyCubeWrapper: 100
+ - type: Storage
+ whitelist:
+ tags:
+ - MonkeyCube
+ capacity: 30
+ - type: StorageFill
+ contents:
+ - id: MonkeyCubeWrapped
+ amount: 6
- type: Sprite
sprite: Objects/Misc/monkeycube.rsi
state: box
@@ -14,13 +20,18 @@
- type: entity
parent: BaseItem
name: monkey cube
- id: MonkeyCubeWrapper
+ suffix: Wrapped
+ id: MonkeyCubeWrapped
description: Unwrap this to get a monkey cube.
components:
- - type: FoodContainer
- capacity: 1
- prototypes:
- MonkeyCube: 100
+ - type: SpawnItemsOnUse
+ items:
+ - id: MonkeyCube
+ sound:
+ path: /Audio/Effects/unwrap.ogg
- type: Sprite
sprite: Objects/Misc/monkeycube.rsi
state: wrapper
+ - type: Tag
+ tags:
+ - MonkeyCube
diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml
index a53113ae72..abc6ffceea 100644
--- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml
+++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml
@@ -50,7 +50,7 @@
name: pest spray
id: PestSpray
parent: WeedSpray
- description: Objects/Tools/Hydroponics/sprays.rsi
+ description: It's some pest eliminator spray! Do not inhale!
suffix: "Filled"
components:
- type: Sprite
diff --git a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml
index 9646bdce26..be03c43997 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml
@@ -12,6 +12,7 @@
sprite: Objects/Tools/bucket.rsi
state: icon
- type: Clothing
+ size: 100
sprite: Objects/Tools/bucket.rsi
Slots:
- Helmet
diff --git a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml
index 4c93eab341..48b667a26d 100644
--- a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml
+++ b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml
@@ -11,6 +11,7 @@
- key: enum.SharedGasTankUiKey.Key
type: GasTankBoundUserInterface
- type: Clothing
+ size: 15
sprite: Objects/Tanks/generic.rsi
QuickEquip: false
- type: GasTank
@@ -80,6 +81,7 @@
volume: 2
temperature: 293.15
- type: Clothing
+ size: 10
sprite: Objects/Tanks/emergency.rsi
Slots:
- Pocket
@@ -100,6 +102,7 @@
volume: 6
temperature: 293.15
- type: Clothing
+ size: 10
sprite: Objects/Tanks/emergency_yellow.rsi
Slots:
- Pocket
@@ -118,6 +121,7 @@
volume: 10
temperature: 293.15
- type: Clothing
+ size: 10
sprite: Objects/Tanks/emergency_double.rsi
Slots:
- Pocket
@@ -157,6 +161,7 @@
volume: 70
temperature: 293.15
- type: Clothing
+ size: 10
sprite: Objects/Tanks/plasma.rsi
Slots:
- Belt
diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base.yml
index 1b33400a9f..a8fe9b1a7e 100644
--- a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base.yml
+++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base.yml
@@ -4,7 +4,7 @@
abstract: true
components:
- type: AccessReader
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
netsync: false
sprite: Structures/Storage/closet.rsi
diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml
index dae7bc4c1c..70e4f09b5d 100644
--- a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml
+++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml
@@ -261,7 +261,7 @@
components:
- type: AccessReader
access: [["Security"]]
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/sec_gear.rsi
layers:
@@ -290,7 +290,7 @@
components:
- type: AccessReader
access: [["Engineering"]]
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/engicrate_secure.rsi
layers:
@@ -319,7 +319,7 @@
components:
- type: AccessReader
access: [["Medical"]]
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/medicalcrate_secure.rsi
layers:
@@ -347,7 +347,7 @@
parent: CrateGeneric
components:
- type: AccessReader
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/privatecrate_secure.rsi
layers:
@@ -376,7 +376,7 @@
components:
- type: AccessReader
access: [["Research"]]
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/scicrate_secure.rsi
layers:
@@ -405,7 +405,7 @@
components:
- type: AccessReader
access: [["Engineering"]]
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/plasma.rsi
layers:
@@ -433,7 +433,7 @@
parent: CrateGeneric
components:
- type: AccessReader
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/secure.rsi
layers:
@@ -462,7 +462,7 @@
components:
- type: AccessReader
access: [["Service"]]
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/hydro_secure.rsi
layers:
@@ -491,7 +491,7 @@
components:
- type: AccessReader
access: [["Security"]]
- - type: SecureEntityStorage
+ - type: Lock
- type: Sprite
sprite: Structures/Storage/Crates/weapon.rsi
layers:
diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/makeshifthandcuffs.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/makeshifthandcuffs.yml
new file mode 100644
index 0000000000..08d6d57fb9
--- /dev/null
+++ b/Resources/Prototypes/Recipes/Crafting/Graphs/makeshifthandcuffs.yml
@@ -0,0 +1,14 @@
+- type: constructionGraph
+ id: makeshifthandcuffs
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: cuffscable
+ steps:
+ - material: Cable
+ amount: 15
+ doAfter: 5
+ - node: cuffscable
+ entity: Cablecuffs
+
diff --git a/Resources/Prototypes/Recipes/Crafting/makeshifthandcuffs.yml b/Resources/Prototypes/Recipes/Crafting/makeshifthandcuffs.yml
new file mode 100644
index 0000000000..b7b0344f11
--- /dev/null
+++ b/Resources/Prototypes/Recipes/Crafting/makeshifthandcuffs.yml
@@ -0,0 +1,11 @@
+- type: construction
+ name: makeshift handcuffs
+ id: makeshifthandcuffs
+ graph: makeshifthandcuffs
+ startNode: start
+ targetNode: cuffscable
+ category: Utility
+ description: "Homemade handcuffs crafted from spare cables."
+ icon: Objects/Misc/cablecuffs.rsi/cuff.png
+ objectType: Item
+
diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml
index 07adc2a9fc..3b4028d5e7 100644
--- a/Resources/Prototypes/tags.yml
+++ b/Resources/Prototypes/tags.yml
@@ -58,6 +58,12 @@
- type: Tag
id: DoorElectronics
+- type: Tag
+ id: Donut
+
+- type: Tag
+ id: Egg
+
- type: Tag
id: ExplosivePassable
@@ -84,13 +90,19 @@
- type: Tag
id: JawsOfLife
-
+
+- type: Tag
+ id: MonkeyCube
+
- type: Tag
id: NoSpinOnThrow
- type: Tag
id: Ore
+- type: Tag
+ id: Pizza
+
- type: Tag
id: PlantAnalyzer
@@ -103,6 +115,9 @@
- type: Tag
id: Powerdrill
+- type: Tag
+ id: RollingPaper
+
- type: Tag
id: Screwdriver
diff --git a/RobustToolbox b/RobustToolbox
index 3a86c827ea..e93c0f76a9 160000
--- a/RobustToolbox
+++ b/RobustToolbox
@@ -1 +1 @@
-Subproject commit 3a86c827ea02f46b213f473f6479fbfaed35095e
+Subproject commit e93c0f76a9ea5021754b6c9b5f1819e0a46b8f4b
diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings
index 5ff7f8d1e5..692912bc33 100644
--- a/SpaceStation14.sln.DotSettings
+++ b/SpaceStation14.sln.DotSettings
@@ -264,6 +264,7 @@
True
True
True
+ True
True
True
True
@@ -284,6 +285,7 @@
True
True
True
+ True
True
True
True