diff --git a/Content.Client/Configurable/ConfigurationSystem.cs b/Content.Client/Configurable/ConfigurationSystem.cs new file mode 100644 index 0000000000..6594375ba2 --- /dev/null +++ b/Content.Client/Configurable/ConfigurationSystem.cs @@ -0,0 +1,25 @@ +using Content.Client.Configurable.UI; +using Content.Shared.Configurable; + +namespace Content.Client.Configurable; + +public sealed class ConfigurationSystem : SharedConfigurationSystem +{ + [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnConfigurationState); + } + + private void OnConfigurationState(Entity ent, ref AfterAutoHandleStateEvent args) + { + if (_uiSystem.TryGetOpenUi(ent.Owner, + ConfigurationComponent.ConfigurationUiKey.Key, + out var bui)) + { + bui.Refresh(ent); + } + } +} diff --git a/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs b/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs index e4966f1ec4..a3845ba1eb 100644 --- a/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs +++ b/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs @@ -1,6 +1,8 @@ -using System.Text.RegularExpressions; -using Robust.Client.GameObjects; +using System.Numerics; +using System.Text.RegularExpressions; +using Content.Shared.Configurable; using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; using static Content.Shared.Configurable.ConfigurationComponent; namespace Content.Client.Configurable.UI @@ -19,16 +21,53 @@ namespace Content.Client.Configurable.UI base.Open(); _menu = this.CreateWindow(); _menu.OnConfiguration += SendConfiguration; + if (EntMan.TryGetComponent(Owner, out ConfigurationComponent? component)) + Refresh((Owner, component)); } - protected override void UpdateState(BoundUserInterfaceState state) + public void Refresh(Entity entity) { - base.UpdateState(state); - - if (state is not ConfigurationBoundUserInterfaceState configurationState) + if (_menu == null) return; - _menu?.Populate(configurationState); + _menu.Column.Children.Clear(); + _menu.Inputs.Clear(); + + foreach (var field in entity.Comp.Config) + { + var label = new Label + { + Margin = new Thickness(0, 0, 8, 0), + Name = field.Key, + Text = field.Key + ":", + VerticalAlignment = Control.VAlignment.Center, + HorizontalExpand = true, + SizeFlagsStretchRatio = .2f, + MinSize = new Vector2(60, 0) + }; + + var input = new LineEdit + { + Name = field.Key + "-input", + Text = field.Value ?? "", + IsValid = _menu.Validate, + HorizontalExpand = true, + SizeFlagsStretchRatio = .8f + }; + + _menu.Inputs.Add((field.Key, input)); + + var row = new BoxContainer + { + Orientation = BoxContainer.LayoutOrientation.Horizontal + }; + + ConfigurationMenu.CopyProperties(_menu.Row, row); + + row.AddChild(label); + row.AddChild(input); + _menu.Column.AddChild(row); + } } protected override void ReceiveMessage(BoundUserInterfaceMessage message) diff --git a/Content.Client/Configurable/UI/ConfigurationMenu.cs b/Content.Client/Configurable/UI/ConfigurationMenu.cs index 29217eef7b..4ca68c5fa0 100644 --- a/Content.Client/Configurable/UI/ConfigurationMenu.cs +++ b/Content.Client/Configurable/UI/ConfigurationMenu.cs @@ -1,12 +1,8 @@ -using System.Collections.Generic; -using System.Numerics; +using System.Numerics; using System.Text.RegularExpressions; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; -using Robust.Shared.Localization; -using Robust.Shared.Maths; -using static Content.Shared.Configurable.ConfigurationComponent; using static Robust.Client.UserInterface.Controls.BaseButton; using static Robust.Client.UserInterface.Controls.BoxContainer; @@ -14,10 +10,10 @@ namespace Content.Client.Configurable.UI { public sealed class ConfigurationMenu : DefaultWindow { - private readonly BoxContainer _column; - private readonly BoxContainer _row; + public readonly BoxContainer Column; + public readonly BoxContainer Row; - private readonly List<(string name, LineEdit input)> _inputs; + public readonly List<(string name, LineEdit input)> Inputs; [ViewVariables] public Regex? Validation { get; internal set; } @@ -28,7 +24,7 @@ namespace Content.Client.Configurable.UI { MinSize = SetSize = new Vector2(300, 250); - _inputs = new List<(string name, LineEdit input)>(); + Inputs = new List<(string name, LineEdit input)>(); Title = Loc.GetString("configuration-menu-device-title"); @@ -39,14 +35,14 @@ namespace Content.Client.Configurable.UI HorizontalExpand = true }; - _column = new BoxContainer + Column = new BoxContainer { Orientation = LayoutOrientation.Vertical, Margin = new Thickness(8), SeparationOverride = 16, }; - _row = new BoxContainer + Row = new BoxContainer { Orientation = LayoutOrientation.Horizontal, SeparationOverride = 16, @@ -69,61 +65,20 @@ namespace Content.Client.Configurable.UI ModulateSelfOverride = Color.FromHex("#202025") }; - outerColumn.AddChild(_column); + outerColumn.AddChild(Column); baseContainer.AddChild(outerColumn); baseContainer.AddChild(confirmButton); Contents.AddChild(baseContainer); } - public void Populate(ConfigurationBoundUserInterfaceState state) - { - _column.Children.Clear(); - _inputs.Clear(); - - foreach (var field in state.Config) - { - var label = new Label - { - Margin = new Thickness(0, 0, 8, 0), - Name = field.Key, - Text = field.Key + ":", - VerticalAlignment = VAlignment.Center, - HorizontalExpand = true, - SizeFlagsStretchRatio = .2f, - MinSize = new Vector2(60, 0) - }; - - var input = new LineEdit - { - Name = field.Key + "-input", - Text = field.Value ?? "", - IsValid = Validate, - HorizontalExpand = true, - SizeFlagsStretchRatio = .8f - }; - - _inputs.Add((field.Key, input)); - - var row = new BoxContainer - { - Orientation = LayoutOrientation.Horizontal - }; - CopyProperties(_row, row); - - row.AddChild(label); - row.AddChild(input); - _column.AddChild(row); - } - } - private void OnConfirm(ButtonEventArgs args) { - var config = GenerateDictionary(_inputs, "Text"); + var config = GenerateDictionary(Inputs, "Text"); OnConfiguration?.Invoke(config); Close(); } - private bool Validate(string value) + public bool Validate(string value) { return Validation?.IsMatch(value) != false; } @@ -140,7 +95,7 @@ namespace Content.Client.Configurable.UI return dictionary; } - private static void CopyProperties(T from, T to) where T : Control + public static void CopyProperties(T from, T to) where T : Control { foreach (var property in from.AllAttachedProperties) { diff --git a/Content.Client/Decals/DecalSystem.cs b/Content.Client/Decals/DecalSystem.cs index 41e5f39c28..172a06c4cd 100644 --- a/Content.Client/Decals/DecalSystem.cs +++ b/Content.Client/Decals/DecalSystem.cs @@ -13,7 +13,7 @@ namespace Content.Client.Decals [Dependency] private readonly IOverlayManager _overlayManager = default!; [Dependency] private readonly SpriteSystem _sprites = default!; - private DecalOverlay _overlay = default!; + private DecalOverlay? _overlay; private HashSet _removedUids = new(); private readonly List _removedChunks = new(); @@ -31,6 +31,9 @@ namespace Content.Client.Decals public void ToggleOverlay() { + if (_overlay == null) + return; + if (_overlayManager.HasOverlay()) { _overlayManager.RemoveOverlay(_overlay); @@ -44,6 +47,10 @@ namespace Content.Client.Decals public override void Shutdown() { base.Shutdown(); + + if (_overlay == null) + return; + _overlayManager.RemoveOverlay(_overlay); } diff --git a/Content.Client/DeviceNetwork/Systems/DeviceNetworkSystem.cs b/Content.Client/DeviceNetwork/Systems/DeviceNetworkSystem.cs new file mode 100644 index 0000000000..5b11b2bfe7 --- /dev/null +++ b/Content.Client/DeviceNetwork/Systems/DeviceNetworkSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.DeviceNetwork.Systems; + +namespace Content.Client.DeviceNetwork.Systems; + +public sealed class DeviceNetworkSystem : SharedDeviceNetworkSystem +{ + +} diff --git a/Content.Client/Disposal/DisposalUnitComponent.cs b/Content.Client/Disposal/DisposalUnitComponent.cs deleted file mode 100644 index e63a3fd45e..0000000000 --- a/Content.Client/Disposal/DisposalUnitComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Content.Shared.Disposal.Components; - -namespace Content.Client.Disposal; - -[RegisterComponent] -public sealed partial class DisposalUnitComponent : SharedDisposalUnitComponent -{ - -} diff --git a/Content.Client/Disposal/Mailing/MailingUnitBoundUserInterface.cs b/Content.Client/Disposal/Mailing/MailingUnitBoundUserInterface.cs new file mode 100644 index 0000000000..013c4eaa1b --- /dev/null +++ b/Content.Client/Disposal/Mailing/MailingUnitBoundUserInterface.cs @@ -0,0 +1,79 @@ +using Content.Client.Disposal.Unit; +using Content.Client.Power.EntitySystems; +using Content.Shared.Disposal; +using Content.Shared.Disposal.Components; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; + +namespace Content.Client.Disposal.Mailing; + +public sealed class MailingUnitBoundUserInterface : BoundUserInterface +{ + [ViewVariables] + public MailingUnitWindow? MailingUnitWindow; + + public MailingUnitBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + private void ButtonPressed(DisposalUnitComponent.UiButton button) + { + SendMessage(new DisposalUnitComponent.UiButtonPressedMessage(button)); + // If we get client-side power stuff then we can predict the button presses but for now we won't as it stuffs + // the pressure lerp up. + } + + private void TargetSelected(ItemList.ItemListSelectedEventArgs args) + { + var item = args.ItemList[args.ItemIndex]; + SendMessage(new TargetSelectedMessage(item.Text)); + } + + protected override void Open() + { + base.Open(); + + MailingUnitWindow = this.CreateWindow(); + MailingUnitWindow.OpenCenteredRight(); + + MailingUnitWindow.Eject.OnPressed += _ => ButtonPressed(DisposalUnitComponent.UiButton.Eject); + MailingUnitWindow.Engage.OnPressed += _ => ButtonPressed(DisposalUnitComponent.UiButton.Engage); + MailingUnitWindow.Power.OnPressed += _ => ButtonPressed(DisposalUnitComponent.UiButton.Power); + + MailingUnitWindow.TargetListContainer.OnItemSelected += TargetSelected; + + if (EntMan.TryGetComponent(Owner, out MailingUnitComponent? component)) + Refresh((Owner, component)); + } + + public void Refresh(Entity entity) + { + if (MailingUnitWindow == null) + return; + + // TODO: This should be decoupled from disposals + if (EntMan.TryGetComponent(entity.Owner, out DisposalUnitComponent? disposals)) + { + var disposalSystem = EntMan.System(); + + var disposalState = disposalSystem.GetState(Owner, disposals); + var fullPressure = disposalSystem.EstimatedFullPressure(Owner, disposals); + + MailingUnitWindow.UnitState.Text = Loc.GetString($"disposal-unit-state-{disposalState}"); + MailingUnitWindow.FullPressure = fullPressure; + MailingUnitWindow.PressureBar.UpdatePressure(fullPressure); + MailingUnitWindow.Power.Pressed = EntMan.System().IsPowered(Owner); + MailingUnitWindow.Engage.Pressed = disposals.Engaged; + } + + MailingUnitWindow.Title = Loc.GetString("ui-mailing-unit-window-title", ("tag", entity.Comp.Tag ?? " ")); + //UnitTag.Text = state.Tag; + MailingUnitWindow.Target.Text = entity.Comp.Target; + + MailingUnitWindow.TargetListContainer.Clear(); + foreach (var target in entity.Comp.TargetList) + { + MailingUnitWindow.TargetListContainer.AddItem(target); + } + } +} diff --git a/Content.Client/Disposal/Mailing/MailingUnitSystem.cs b/Content.Client/Disposal/Mailing/MailingUnitSystem.cs new file mode 100644 index 0000000000..780656b4f0 --- /dev/null +++ b/Content.Client/Disposal/Mailing/MailingUnitSystem.cs @@ -0,0 +1,22 @@ +using Content.Shared.Disposal; +using Content.Shared.Disposal.Components; +using Content.Shared.Disposal.Mailing; + +namespace Content.Client.Disposal.Mailing; + +public sealed class MailingUnitSystem : SharedMailingUnitSystem +{ + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMailingState); + } + + private void OnMailingState(Entity ent, ref AfterAutoHandleStateEvent args) + { + if (UserInterfaceSystem.TryGetOpenUi(ent.Owner, MailingUnitUiKey.Key, out var bui)) + { + bui.Refresh(ent); + } + } +} diff --git a/Content.Client/Disposal/UI/MailingUnitWindow.xaml b/Content.Client/Disposal/Mailing/MailingUnitWindow.xaml similarity index 80% rename from Content.Client/Disposal/UI/MailingUnitWindow.xaml rename to Content.Client/Disposal/Mailing/MailingUnitWindow.xaml index c57ca7b4c1..0acd300895 100644 --- a/Content.Client/Disposal/UI/MailingUnitWindow.xaml +++ b/Content.Client/Disposal/Mailing/MailingUnitWindow.xaml @@ -1,12 +1,14 @@ - - + diff --git a/Content.Client/Disposal/Mailing/MailingUnitWindow.xaml.cs b/Content.Client/Disposal/Mailing/MailingUnitWindow.xaml.cs new file mode 100644 index 0000000000..8f1dcaf7dc --- /dev/null +++ b/Content.Client/Disposal/Mailing/MailingUnitWindow.xaml.cs @@ -0,0 +1,27 @@ +using Content.Client.UserInterface.Controls; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Timing; + +namespace Content.Client.Disposal.Mailing +{ + /// + /// Client-side UI used to control a + /// + [GenerateTypedNameReferences] + public sealed partial class MailingUnitWindow : FancyWindow + { + public TimeSpan FullPressure; + + public MailingUnitWindow() + { + RobustXamlLoader.Load(this); + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + PressureBar.UpdatePressure(FullPressure); + } + } +} diff --git a/Content.Client/Disposal/UI/PressureBar.cs b/Content.Client/Disposal/PressureBar.cs similarity index 96% rename from Content.Client/Disposal/UI/PressureBar.cs rename to Content.Client/Disposal/PressureBar.cs index bff95ca430..7b2ebacaf7 100644 --- a/Content.Client/Disposal/UI/PressureBar.cs +++ b/Content.Client/Disposal/PressureBar.cs @@ -1,9 +1,10 @@ using Content.Shared.Disposal; +using Content.Shared.Disposal.Unit; using Robust.Client.Graphics; using Robust.Client.UserInterface.Controls; using Robust.Shared.Timing; -namespace Content.Client.Disposal.UI; +namespace Content.Client.Disposal; public sealed class PressureBar : ProgressBar { diff --git a/Content.Client/Disposal/Systems/DisposalUnitSystem.cs b/Content.Client/Disposal/Systems/DisposalUnitSystem.cs deleted file mode 100644 index da548c1e54..0000000000 --- a/Content.Client/Disposal/Systems/DisposalUnitSystem.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Shared.Disposal; -using Content.Shared.Disposal.Components; -using Content.Shared.DragDrop; -using Content.Shared.Emag.Systems; -using Robust.Client.GameObjects; -using Robust.Client.Animations; -using Robust.Client.Graphics; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.GameStates; -using Robust.Shared.Physics.Events; -using static Content.Shared.Disposal.Components.SharedDisposalUnitComponent; - -namespace Content.Client.Disposal.Systems; - -public sealed class DisposalUnitSystem : SharedDisposalUnitSystem -{ - [Dependency] private readonly AppearanceSystem _appearanceSystem = default!; - [Dependency] private readonly AnimationPlayerSystem _animationSystem = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; - - private const string AnimationKey = "disposal_unit_animation"; - - private const string DefaultFlushState = "disposal-flush"; - private const string DefaultChargeState = "disposal-charging"; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnHandleState); - SubscribeLocalEvent(OnPreventCollide); - SubscribeLocalEvent(OnCanDragDropOn); - SubscribeLocalEvent(OnEmagged); - - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnAppearanceChange); - } - - private void OnHandleState(EntityUid uid, DisposalUnitComponent component, ref ComponentHandleState args) - { - if (args.Current is not DisposalUnitComponentState state) - return; - - component.FlushSound = state.FlushSound; - component.State = state.State; - component.NextPressurized = state.NextPressurized; - component.AutomaticEngageTime = state.AutomaticEngageTime; - component.NextFlush = state.NextFlush; - component.Powered = state.Powered; - component.Engaged = state.Engaged; - component.RecentlyEjected.Clear(); - component.RecentlyEjected.AddRange(EnsureEntityList(state.RecentlyEjected, uid)); - } - - public override bool HasDisposals(EntityUid? uid) - { - return HasComp(uid); - } - - public override bool ResolveDisposals(EntityUid uid, [NotNullWhen(true)] ref SharedDisposalUnitComponent? component) - { - if (component != null) - return true; - - TryComp(uid, out var storage); - component = storage; - return component != null; - } - - public override void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null) - { - return; - } - - private void OnComponentInit(EntityUid uid, SharedDisposalUnitComponent sharedDisposalUnit, ComponentInit args) - { - if (!TryComp(uid, out var sprite) || !TryComp(uid, out var appearance)) - return; - - UpdateState(uid, sharedDisposalUnit, sprite, appearance); - } - - private void OnAppearanceChange(EntityUid uid, SharedDisposalUnitComponent unit, ref AppearanceChangeEvent args) - { - if (args.Sprite == null) - return; - - UpdateState(uid, unit, args.Sprite, args.Component); - } - - /// - /// Update visuals and tick animation - /// - private void UpdateState(EntityUid uid, SharedDisposalUnitComponent unit, SpriteComponent sprite, AppearanceComponent appearance) - { - if (!_appearanceSystem.TryGetData(uid, Visuals.VisualState, out var state, appearance)) - return; - - sprite.LayerSetVisible(DisposalUnitVisualLayers.Unanchored, state == VisualState.UnAnchored); - sprite.LayerSetVisible(DisposalUnitVisualLayers.Base, state == VisualState.Anchored); - sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFlush, state is VisualState.OverlayFlushing or VisualState.OverlayCharging); - - var chargingState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.BaseCharging, out var chargingLayer) - ? sprite.LayerGetState(chargingLayer) - : new RSI.StateId(DefaultChargeState); - - // This is a transient state so not too worried about replaying in range. - if (state == VisualState.OverlayFlushing) - { - if (!_animationSystem.HasRunningAnimation(uid, AnimationKey)) - { - var flushState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.OverlayFlush, out var flushLayer) - ? sprite.LayerGetState(flushLayer) - : new RSI.StateId(DefaultFlushState); - - // Setup the flush animation to play - var anim = new Animation - { - Length = unit.FlushDelay, - AnimationTracks = - { - new AnimationTrackSpriteFlick - { - LayerKey = DisposalUnitVisualLayers.OverlayFlush, - KeyFrames = - { - // Play the flush animation - new AnimationTrackSpriteFlick.KeyFrame(flushState, 0), - // Return to base state (though, depending on how the unit is - // configured we might get an appearance change event telling - // us to go to charging state) - new AnimationTrackSpriteFlick.KeyFrame(chargingState, (float) unit.FlushDelay.TotalSeconds) - } - }, - } - }; - - if (unit.FlushSound != null) - { - anim.AnimationTracks.Add( - new AnimationTrackPlaySound - { - KeyFrames = - { - new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(unit.FlushSound), 0) - } - }); - } - - _animationSystem.Play(uid, anim, AnimationKey); - } - } - else if (state == VisualState.OverlayCharging) - sprite.LayerSetState(DisposalUnitVisualLayers.OverlayFlush, chargingState); - else - _animationSystem.Stop(uid, AnimationKey); - - if (!_appearanceSystem.TryGetData(uid, Visuals.Handle, out var handleState, appearance)) - handleState = HandleState.Normal; - - sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayEngaged, handleState != HandleState.Normal); - - if (!_appearanceSystem.TryGetData(uid, Visuals.Light, out var lightState, appearance)) - lightState = LightStates.Off; - - sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayCharging, - (lightState & LightStates.Charging) != 0); - sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayReady, - (lightState & LightStates.Ready) != 0); - sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFull, - (lightState & LightStates.Full) != 0); - } -} - -public enum DisposalUnitVisualLayers : byte -{ - Unanchored, - Base, - BaseCharging, - OverlayFlush, - OverlayCharging, - OverlayReady, - OverlayFull, - OverlayEngaged -} diff --git a/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs b/Content.Client/Disposal/Tube/DisposalRouterBoundUserInterface.cs similarity index 95% rename from Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs rename to Content.Client/Disposal/Tube/DisposalRouterBoundUserInterface.cs index 296e71d3a9..1116dc7257 100644 --- a/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs +++ b/Content.Client/Disposal/Tube/DisposalRouterBoundUserInterface.cs @@ -1,9 +1,8 @@ using JetBrains.Annotations; -using Robust.Client.GameObjects; using Robust.Client.UserInterface; using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; -namespace Content.Client.Disposal.UI +namespace Content.Client.Disposal.Tube { /// /// Initializes a and updates it when new server messages are received. diff --git a/Content.Client/Disposal/UI/DisposalRouterWindow.xaml b/Content.Client/Disposal/Tube/DisposalRouterWindow.xaml similarity index 100% rename from Content.Client/Disposal/UI/DisposalRouterWindow.xaml rename to Content.Client/Disposal/Tube/DisposalRouterWindow.xaml diff --git a/Content.Client/Disposal/UI/DisposalRouterWindow.xaml.cs b/Content.Client/Disposal/Tube/DisposalRouterWindow.xaml.cs similarity index 90% rename from Content.Client/Disposal/UI/DisposalRouterWindow.xaml.cs rename to Content.Client/Disposal/Tube/DisposalRouterWindow.xaml.cs index 39ee9fbe23..c9d7d286eb 100644 --- a/Content.Client/Disposal/UI/DisposalRouterWindow.xaml.cs +++ b/Content.Client/Disposal/Tube/DisposalRouterWindow.xaml.cs @@ -1,11 +1,10 @@ using Content.Shared.Disposal.Components; using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; -namespace Content.Client.Disposal.UI +namespace Content.Client.Disposal.Tube { /// /// Client-side UI used to control a diff --git a/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs b/Content.Client/Disposal/Tube/DisposalTaggerBoundUserInterface.cs similarity index 95% rename from Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs rename to Content.Client/Disposal/Tube/DisposalTaggerBoundUserInterface.cs index 7fc0eb8540..5618e83ecf 100644 --- a/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs +++ b/Content.Client/Disposal/Tube/DisposalTaggerBoundUserInterface.cs @@ -1,9 +1,8 @@ using JetBrains.Annotations; -using Robust.Client.GameObjects; using Robust.Client.UserInterface; using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; -namespace Content.Client.Disposal.UI +namespace Content.Client.Disposal.Tube { /// /// Initializes a and updates it when new server messages are received. diff --git a/Content.Client/Disposal/UI/DisposalTaggerWindow.xaml b/Content.Client/Disposal/Tube/DisposalTaggerWindow.xaml similarity index 100% rename from Content.Client/Disposal/UI/DisposalTaggerWindow.xaml rename to Content.Client/Disposal/Tube/DisposalTaggerWindow.xaml diff --git a/Content.Client/Disposal/UI/DisposalTaggerWindow.xaml.cs b/Content.Client/Disposal/Tube/DisposalTaggerWindow.xaml.cs similarity index 90% rename from Content.Client/Disposal/UI/DisposalTaggerWindow.xaml.cs rename to Content.Client/Disposal/Tube/DisposalTaggerWindow.xaml.cs index b49d5d997b..ae8286cf14 100644 --- a/Content.Client/Disposal/UI/DisposalTaggerWindow.xaml.cs +++ b/Content.Client/Disposal/Tube/DisposalTaggerWindow.xaml.cs @@ -1,11 +1,10 @@ using Content.Shared.Disposal.Components; using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; -namespace Content.Client.Disposal.UI +namespace Content.Client.Disposal.Tube { /// /// Client-side UI used to control a diff --git a/Content.Client/Disposal/Tube/DisposalTubeSystem.cs b/Content.Client/Disposal/Tube/DisposalTubeSystem.cs new file mode 100644 index 0000000000..fd86f7ec88 --- /dev/null +++ b/Content.Client/Disposal/Tube/DisposalTubeSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.Disposal.Unit; + +namespace Content.Client.Disposal.Tube; + +public sealed class DisposalTubeSystem : SharedDisposalTubeSystem +{ + +} diff --git a/Content.Client/Disposal/UI/DisposalUnitBoundUserInterface.cs b/Content.Client/Disposal/UI/DisposalUnitBoundUserInterface.cs deleted file mode 100644 index d2bec6e94f..0000000000 --- a/Content.Client/Disposal/UI/DisposalUnitBoundUserInterface.cs +++ /dev/null @@ -1,103 +0,0 @@ -using Content.Client.Disposal.Systems; -using Content.Shared.Disposal; -using Content.Shared.Disposal.Components; -using JetBrains.Annotations; -using Robust.Client.GameObjects; -using Robust.Client.UserInterface.Controls; -using static Content.Shared.Disposal.Components.SharedDisposalUnitComponent; - -namespace Content.Client.Disposal.UI -{ - /// - /// Initializes a or a and updates it when new server messages are received. - /// - [UsedImplicitly] - public sealed class DisposalUnitBoundUserInterface : BoundUserInterface - { - // What are you doing here - [ViewVariables] - public MailingUnitWindow? MailingUnitWindow; - - [ViewVariables] - public DisposalUnitWindow? DisposalUnitWindow; - - public DisposalUnitBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) - { - } - - private void ButtonPressed(UiButton button) - { - SendMessage(new UiButtonPressedMessage(button)); - // If we get client-side power stuff then we can predict the button presses but for now we won't as it stuffs - // the pressure lerp up. - } - - private void TargetSelected(ItemList.ItemListSelectedEventArgs args) - { - var item = args.ItemList[args.ItemIndex]; - SendMessage(new TargetSelectedMessage(item.Text)); - } - - protected override void Open() - { - base.Open(); - - if (UiKey is MailingUnitUiKey) - { - MailingUnitWindow = new MailingUnitWindow(); - - MailingUnitWindow.OpenCenteredRight(); - MailingUnitWindow.OnClose += Close; - - MailingUnitWindow.Eject.OnPressed += _ => ButtonPressed(UiButton.Eject); - MailingUnitWindow.Engage.OnPressed += _ => ButtonPressed(UiButton.Engage); - MailingUnitWindow.Power.OnPressed += _ => ButtonPressed(UiButton.Power); - - MailingUnitWindow.TargetListContainer.OnItemSelected += TargetSelected; - } - else if (UiKey is DisposalUnitUiKey) - { - DisposalUnitWindow = new DisposalUnitWindow(); - - DisposalUnitWindow.OpenCenteredRight(); - DisposalUnitWindow.OnClose += Close; - - DisposalUnitWindow.Eject.OnPressed += _ => ButtonPressed(UiButton.Eject); - DisposalUnitWindow.Engage.OnPressed += _ => ButtonPressed(UiButton.Engage); - DisposalUnitWindow.Power.OnPressed += _ => ButtonPressed(UiButton.Power); - } - } - - protected override void UpdateState(BoundUserInterfaceState state) - { - base.UpdateState(state); - - if (state is not MailingUnitBoundUserInterfaceState && state is not DisposalUnitBoundUserInterfaceState) - { - return; - } - - switch (state) - { - case MailingUnitBoundUserInterfaceState mailingUnitState: - MailingUnitWindow?.UpdateState(mailingUnitState); - break; - - case DisposalUnitBoundUserInterfaceState disposalUnitState: - DisposalUnitWindow?.UpdateState(disposalUnitState); - break; - } - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (!disposing) - return; - - MailingUnitWindow?.Dispose(); - DisposalUnitWindow?.Dispose(); - } - } -} diff --git a/Content.Client/Disposal/UI/DisposalUnitWindow.xaml.cs b/Content.Client/Disposal/UI/DisposalUnitWindow.xaml.cs deleted file mode 100644 index 3440fe208a..0000000000 --- a/Content.Client/Disposal/UI/DisposalUnitWindow.xaml.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Content.Shared.Disposal.Components; -using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface.CustomControls; -using Robust.Client.UserInterface.XAML; -using Robust.Shared.Timing; -using static Content.Shared.Disposal.Components.SharedDisposalUnitComponent; - -namespace Content.Client.Disposal.UI -{ - /// - /// Client-side UI used to control a - /// - [GenerateTypedNameReferences] - public sealed partial class DisposalUnitWindow : DefaultWindow - { - public TimeSpan FullPressure; - - public DisposalUnitWindow() - { - IoCManager.InjectDependencies(this); - RobustXamlLoader.Load(this); - } - - /// - /// Update the interface state for the disposals window. - /// - /// true if we should stop updating every frame. - public void UpdateState(DisposalUnitBoundUserInterfaceState state) - { - Title = state.UnitName; - UnitState.Text = state.UnitState; - Power.Pressed = state.Powered; - Engage.Pressed = state.Engaged; - FullPressure = state.FullPressureTime; - } - - protected override void FrameUpdate(FrameEventArgs args) - { - base.FrameUpdate(args); - PressureBar.UpdatePressure(FullPressure); - } - } -} diff --git a/Content.Client/Disposal/UI/MailingUnitWindow.xaml.cs b/Content.Client/Disposal/UI/MailingUnitWindow.xaml.cs deleted file mode 100644 index 489d749a0c..0000000000 --- a/Content.Client/Disposal/UI/MailingUnitWindow.xaml.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Content.Shared.Disposal; -using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface.CustomControls; -using Robust.Client.UserInterface.XAML; -using Robust.Shared.Timing; - -namespace Content.Client.Disposal.UI -{ - /// - /// Client-side UI used to control a - /// - [GenerateTypedNameReferences] - public sealed partial class MailingUnitWindow : DefaultWindow - { - public TimeSpan FullPressure; - - public MailingUnitWindow() - { - RobustXamlLoader.Load(this); - } - - /// - /// Update the interface state for the disposals window. - /// - /// true if we should stop updating every frame. - public bool UpdateState(MailingUnitBoundUserInterfaceState state) - { - var disposalState = state.DisposalState; - - Title = Loc.GetString("ui-mailing-unit-window-title", ("tag", state.Tag ?? " ")); - UnitState.Text = disposalState.UnitState; - FullPressure = disposalState.FullPressureTime; - var pressureReached = PressureBar.UpdatePressure(disposalState.FullPressureTime); - Power.Pressed = disposalState.Powered; - Engage.Pressed = disposalState.Engaged; - - //UnitTag.Text = state.Tag; - Target.Text = state.Target; - - TargetListContainer.Clear(); - foreach (var target in state.TargetList) - { - TargetListContainer.AddItem(target); - } - - return !disposalState.Powered || pressureReached; - } - - protected override void FrameUpdate(FrameEventArgs args) - { - base.FrameUpdate(args); - PressureBar.UpdatePressure(FullPressure); - } - } -} diff --git a/Content.Client/Disposal/Unit/DisposalUnitBoundUserInterface.cs b/Content.Client/Disposal/Unit/DisposalUnitBoundUserInterface.cs new file mode 100644 index 0000000000..62386291a4 --- /dev/null +++ b/Content.Client/Disposal/Unit/DisposalUnitBoundUserInterface.cs @@ -0,0 +1,63 @@ +using Content.Client.Disposal.Mailing; +using Content.Client.Power.EntitySystems; +using Content.Shared.Disposal.Components; +using JetBrains.Annotations; +using Robust.Client.UserInterface; + +namespace Content.Client.Disposal.Unit +{ + /// + /// Initializes a or a and updates it when new server messages are received. + /// + [UsedImplicitly] + public sealed class DisposalUnitBoundUserInterface : BoundUserInterface + { + [ViewVariables] private DisposalUnitWindow? _disposalUnitWindow; + + public DisposalUnitBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + } + + private void ButtonPressed(DisposalUnitComponent.UiButton button) + { + SendPredictedMessage(new DisposalUnitComponent.UiButtonPressedMessage(button)); + // If we get client-side power stuff then we can predict the button presses but for now we won't as it stuffs + // the pressure lerp up. + } + + protected override void Open() + { + base.Open(); + + _disposalUnitWindow = this.CreateWindow(); + + _disposalUnitWindow.OpenCenteredRight(); + + _disposalUnitWindow.Eject.OnPressed += _ => ButtonPressed(DisposalUnitComponent.UiButton.Eject); + _disposalUnitWindow.Engage.OnPressed += _ => ButtonPressed(DisposalUnitComponent.UiButton.Engage); + _disposalUnitWindow.Power.OnPressed += _ => ButtonPressed(DisposalUnitComponent.UiButton.Power); + + if (EntMan.TryGetComponent(Owner, out DisposalUnitComponent? component)) + { + Refresh((Owner, component)); + } + } + + public void Refresh(Entity entity) + { + if (_disposalUnitWindow == null) + return; + + var disposalSystem = EntMan.System(); + + _disposalUnitWindow.Title = EntMan.GetComponent(entity.Owner).EntityName; + + var state = disposalSystem.GetState(entity.Owner, entity.Comp); + + _disposalUnitWindow.UnitState.Text = Loc.GetString($"disposal-unit-state-{state}"); + _disposalUnitWindow.Power.Pressed = EntMan.System().IsPowered(Owner); + _disposalUnitWindow.Engage.Pressed = entity.Comp.Engaged; + _disposalUnitWindow.FullPressure = disposalSystem.EstimatedFullPressure(entity.Owner, entity.Comp); + } + } +} diff --git a/Content.Client/Disposal/Unit/DisposalUnitSystem.cs b/Content.Client/Disposal/Unit/DisposalUnitSystem.cs new file mode 100644 index 0000000000..30ca320a2a --- /dev/null +++ b/Content.Client/Disposal/Unit/DisposalUnitSystem.cs @@ -0,0 +1,156 @@ +using Content.Shared.Disposal.Components; +using Content.Shared.Disposal.Unit; +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Shared.Audio.Systems; + +namespace Content.Client.Disposal.Unit; + +public sealed class DisposalUnitSystem : SharedDisposalUnitSystem +{ + [Dependency] private readonly AppearanceSystem _appearanceSystem = default!; + [Dependency] private readonly AnimationPlayerSystem _animationSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; + + private const string AnimationKey = "disposal_unit_animation"; + + private const string DefaultFlushState = "disposal-flush"; + private const string DefaultChargeState = "disposal-charging"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHandleState); + + SubscribeLocalEvent(OnAppearanceChange); + } + + private void OnHandleState(EntityUid uid, DisposalUnitComponent component, ref AfterAutoHandleStateEvent args) + { + UpdateUI((uid, component)); + } + + protected override void UpdateUI(Entity entity) + { + if (_uiSystem.TryGetOpenUi(entity.Owner, DisposalUnitComponent.DisposalUnitUiKey.Key, out var bui)) + { + bui.Refresh(entity); + } + } + + protected override void OnDisposalInit(Entity ent, ref ComponentInit args) + { + base.OnDisposalInit(ent, ref args); + + if (!TryComp(ent, out var sprite) || !TryComp(ent, out var appearance)) + return; + + UpdateState(ent, sprite, appearance); + } + + private void OnAppearanceChange(Entity ent, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + return; + + UpdateState(ent, args.Sprite, args.Component); + } + + /// + /// Update visuals and tick animation + /// + private void UpdateState(Entity ent, SpriteComponent sprite, AppearanceComponent appearance) + { + if (!_appearanceSystem.TryGetData(ent, DisposalUnitComponent.Visuals.VisualState, out var state, appearance)) + return; + + sprite.LayerSetVisible(DisposalUnitVisualLayers.Unanchored, state == DisposalUnitComponent.VisualState.UnAnchored); + sprite.LayerSetVisible(DisposalUnitVisualLayers.Base, state == DisposalUnitComponent.VisualState.Anchored); + sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFlush, state is DisposalUnitComponent.VisualState.OverlayFlushing or DisposalUnitComponent.VisualState.OverlayCharging); + + var chargingState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.BaseCharging, out var chargingLayer) + ? sprite.LayerGetState(chargingLayer) + : new RSI.StateId(DefaultChargeState); + + // This is a transient state so not too worried about replaying in range. + if (state == DisposalUnitComponent.VisualState.OverlayFlushing) + { + if (!_animationSystem.HasRunningAnimation(ent, AnimationKey)) + { + var flushState = sprite.LayerMapTryGet(DisposalUnitVisualLayers.OverlayFlush, out var flushLayer) + ? sprite.LayerGetState(flushLayer) + : new RSI.StateId(DefaultFlushState); + + // Setup the flush animation to play + var anim = new Animation + { + Length = ent.Comp.FlushDelay, + AnimationTracks = + { + new AnimationTrackSpriteFlick + { + LayerKey = DisposalUnitVisualLayers.OverlayFlush, + KeyFrames = + { + // Play the flush animation + new AnimationTrackSpriteFlick.KeyFrame(flushState, 0), + // Return to base state (though, depending on how the unit is + // configured we might get an appearance change event telling + // us to go to charging state) + new AnimationTrackSpriteFlick.KeyFrame(chargingState, (float) ent.Comp.FlushDelay.TotalSeconds) + } + }, + } + }; + + if (ent.Comp.FlushSound != null) + { + anim.AnimationTracks.Add( + new AnimationTrackPlaySound + { + KeyFrames = + { + new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(ent.Comp.FlushSound), 0) + } + }); + } + + _animationSystem.Play(ent, anim, AnimationKey); + } + } + else if (state == DisposalUnitComponent.VisualState.OverlayCharging) + sprite.LayerSetState(DisposalUnitVisualLayers.OverlayFlush, chargingState); + else + _animationSystem.Stop(ent.Owner, AnimationKey); + + if (!_appearanceSystem.TryGetData(ent, DisposalUnitComponent.Visuals.Handle, out var handleState, appearance)) + handleState = DisposalUnitComponent.HandleState.Normal; + + sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayEngaged, handleState != DisposalUnitComponent.HandleState.Normal); + + if (!_appearanceSystem.TryGetData(ent, DisposalUnitComponent.Visuals.Light, out var lightState, appearance)) + lightState = DisposalUnitComponent.LightStates.Off; + + sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayCharging, + (lightState & DisposalUnitComponent.LightStates.Charging) != 0); + sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayReady, + (lightState & DisposalUnitComponent.LightStates.Ready) != 0); + sprite.LayerSetVisible(DisposalUnitVisualLayers.OverlayFull, + (lightState & DisposalUnitComponent.LightStates.Full) != 0); + } +} + +public enum DisposalUnitVisualLayers : byte +{ + Unanchored, + Base, + BaseCharging, + OverlayFlush, + OverlayCharging, + OverlayReady, + OverlayFull, + OverlayEngaged +} diff --git a/Content.Client/Disposal/UI/DisposalUnitWindow.xaml b/Content.Client/Disposal/Unit/DisposalUnitWindow.xaml similarity index 72% rename from Content.Client/Disposal/UI/DisposalUnitWindow.xaml rename to Content.Client/Disposal/Unit/DisposalUnitWindow.xaml index c8acef98ea..60ca7ba0db 100644 --- a/Content.Client/Disposal/UI/DisposalUnitWindow.xaml +++ b/Content.Client/Disposal/Unit/DisposalUnitWindow.xaml @@ -1,20 +1,21 @@ - - + - + [UsedImplicitly] - public sealed class DeviceNetworkSystem : EntitySystem + public sealed class DeviceNetworkSystem : SharedDeviceNetworkSystem { [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IPrototypeManager _protoMan = default!; @@ -60,16 +60,7 @@ namespace Content.Server.DeviceNetwork.Systems SwapQueues(); } - /// - /// Sends the given payload as a device network packet to the entity with the given address and frequency. - /// Addresses are given to the DeviceNetworkComponent of an entity when connecting. - /// - /// The EntityUid of the sending entity - /// The address of the entity that the packet gets sent to. If null, the message is broadcast to all devices on that frequency (except the sender) - /// The frequency to send on - /// The data to be sent - /// Returns true when the packet was successfully enqueued. - public bool QueuePacket(EntityUid uid, string? address, NetworkPayload data, uint? frequency = null, int? network = null, DeviceNetworkComponent? device = null) + public override bool QueuePacket(EntityUid uid, string? address, NetworkPayload data, uint? frequency = null, int? network = null, DeviceNetworkComponent? device = null) { if (!Resolve(uid, ref device, false)) return false; @@ -368,96 +359,4 @@ namespace Content.Server.DeviceNetwork.Systems } } } - - /// - /// Event raised before a device network packet is send. - /// Subscribed to by other systems to prevent the packet from being sent. - /// - public sealed class BeforePacketSentEvent : CancellableEntityEventArgs - { - /// - /// The EntityUid of the entity the packet was sent from. - /// - public readonly EntityUid Sender; - - public readonly TransformComponent SenderTransform; - - /// - /// The senders current position in world coordinates. - /// - public readonly Vector2 SenderPosition; - - /// - /// The network the packet will be sent to. - /// - public readonly string NetworkId; - - public BeforePacketSentEvent(EntityUid sender, TransformComponent xform, Vector2 senderPosition, string networkId) - { - Sender = sender; - SenderTransform = xform; - SenderPosition = senderPosition; - NetworkId = networkId; - } - } - - /// - /// Sent to the sending entity before broadcasting network packets to recipients - /// - public sealed class BeforeBroadcastAttemptEvent : CancellableEntityEventArgs - { - public readonly IReadOnlySet Recipients; - public HashSet? ModifiedRecipients; - - public BeforeBroadcastAttemptEvent(IReadOnlySet recipients) - { - Recipients = recipients; - } - } - - /// - /// Event raised when a device network packet gets sent. - /// - public sealed class DeviceNetworkPacketEvent : EntityEventArgs - { - /// - /// The id of the network that this packet is being sent on. - /// - public int NetId; - - /// - /// The frequency the packet is sent on. - /// - public readonly uint Frequency; - - /// - /// Address of the intended recipient. Null if the message was broadcast. - /// - public string? Address; - - /// - /// The device network address of the sending entity. - /// - public readonly string SenderAddress; - - /// - /// The entity that sent the packet. - /// - public EntityUid Sender; - - /// - /// The data that is being sent. - /// - public readonly NetworkPayload Data; - - public DeviceNetworkPacketEvent(int netId, string? address, uint frequency, string senderAddress, EntityUid sender, NetworkPayload data) - { - NetId = netId; - Address = address; - Frequency = frequency; - SenderAddress = senderAddress; - Sender = sender; - Data = data; - } - } } diff --git a/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs b/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs index 9a4a81a4c0..588020a963 100644 --- a/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs @@ -1,7 +1,8 @@ -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Components.Devices; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Interaction; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.DeviceNetwork.Systems.Devices { diff --git a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs index 645d28f6d2..6bcbe30456 100644 --- a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs @@ -1,7 +1,6 @@ using System.Linq; using Content.Server.Administration.Logs; using Content.Server.DeviceLinking.Systems; -using Content.Server.DeviceNetwork.Components; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Database; diff --git a/Content.Server/DeviceNetwork/Systems/SingletonDeviceNetServerSystem.cs b/Content.Server/DeviceNetwork/Systems/SingletonDeviceNetServerSystem.cs index 6c997828fa..8c1f48e93f 100644 --- a/Content.Server/DeviceNetwork/Systems/SingletonDeviceNetServerSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/SingletonDeviceNetServerSystem.cs @@ -1,9 +1,9 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.DeviceNetwork.Components; using Content.Server.Medical.CrewMonitoring; -using Content.Server.Power.Components; using Content.Server.Station.Systems; using Content.Shared.Power; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.DeviceNetwork.Systems; diff --git a/Content.Server/DeviceNetwork/Systems/StationLimitedNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/StationLimitedNetworkSystem.cs index 675cacc4d7..cebe1a3b9d 100644 --- a/Content.Server/DeviceNetwork/Systems/StationLimitedNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/StationLimitedNetworkSystem.cs @@ -1,5 +1,6 @@ using Content.Server.DeviceNetwork.Components; using Content.Server.Station.Systems; +using Content.Shared.DeviceNetwork.Events; using JetBrains.Annotations; using Robust.Shared.Map; diff --git a/Content.Server/DeviceNetwork/Systems/WiredNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/WiredNetworkSystem.cs index 758a333c7a..54bd5256c7 100644 --- a/Content.Server/DeviceNetwork/Systems/WiredNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/WiredNetworkSystem.cs @@ -1,4 +1,5 @@ using Content.Server.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; using JetBrains.Annotations; namespace Content.Server.DeviceNetwork.Systems diff --git a/Content.Server/DeviceNetwork/Systems/WirelessNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/WirelessNetworkSystem.cs index 1741afd4ce..8bca47e041 100644 --- a/Content.Server/DeviceNetwork/Systems/WirelessNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/WirelessNetworkSystem.cs @@ -1,4 +1,5 @@ using Content.Server.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; using JetBrains.Annotations; namespace Content.Server.DeviceNetwork.Systems diff --git a/Content.Server/Disposal/Mailing/MailingUnitSystem.cs b/Content.Server/Disposal/Mailing/MailingUnitSystem.cs index 6249b9497d..6ee282a310 100644 --- a/Content.Server/Disposal/Mailing/MailingUnitSystem.cs +++ b/Content.Server/Disposal/Mailing/MailingUnitSystem.cs @@ -1,204 +1,8 @@ -using Content.Server.Configurable; -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; -using Content.Server.DeviceNetwork.Systems; -using Content.Server.Disposal.Unit.EntitySystems; -using Content.Server.Power.Components; -using Content.Shared.DeviceNetwork; -using Content.Shared.Disposal; -using Content.Shared.Interaction; -using Robust.Server.GameObjects; -using Robust.Shared.Player; -using Robust.Shared.Utility; +using Content.Shared.Disposal.Mailing; namespace Content.Server.Disposal.Mailing; -public sealed class MailingUnitSystem : EntitySystem +public sealed class MailingUnitSystem : SharedMailingUnitSystem { - [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; - [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; - private const string MailTag = "mail"; - - private const string TagConfigurationKey = "tag"; - - private const string NetTag = "tag"; - private const string NetSrc = "src"; - private const string NetTarget = "target"; - private const string NetCmdSent = "mail_sent"; - private const string NetCmdRequest = "get_mailer_tag"; - private const string NetCmdResponse = "mailer_tag"; - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnPacketReceived); - SubscribeLocalEvent(OnBeforeFlush); - SubscribeLocalEvent(OnConfigurationUpdated); - SubscribeLocalEvent(HandleActivate, before: new[] { typeof(DisposalUnitSystem) }); - SubscribeLocalEvent(OnDisposalUnitUIStateChange); - SubscribeLocalEvent(OnTargetSelected); - } - - - private void OnComponentInit(EntityUid uid, MailingUnitComponent component, ComponentInit args) - { - UpdateTargetList(uid, component); - } - - private void OnPacketReceived(EntityUid uid, MailingUnitComponent component, DeviceNetworkPacketEvent args) - { - if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command) || !IsPowered(uid)) - return; - - switch (command) - { - case NetCmdRequest: - SendTagRequestResponse(uid, args, component.Tag); - break; - case NetCmdResponse when args.Data.TryGetValue(NetTag, out string? tag): - //Add the received tag request response to the list of targets - component.TargetList.Add(tag); - UpdateUserInterface(uid, component); - break; - } - } - - /// - /// Sends the given tag as a response to a if it's not null - /// - private void SendTagRequestResponse(EntityUid uid, DeviceNetworkPacketEvent args, string? tag) - { - if (tag == null) - return; - - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = NetCmdResponse, - [NetTag] = tag - }; - - _deviceNetworkSystem.QueuePacket(uid, args.Address, payload, args.Frequency); - } - - /// - /// Prevents the unit from flushing if no target is selected - /// - private void OnBeforeFlush(EntityUid uid, MailingUnitComponent component, BeforeDisposalFlushEvent args) - { - if (string.IsNullOrEmpty(component.Target)) - { - args.Cancel(); - return; - } - - args.Tags.Add(MailTag); - args.Tags.Add(component.Target); - - BroadcastSentMessage(uid, component); - } - - /// - /// Broadcast that a mail was sent including the src and target tags - /// - private void BroadcastSentMessage(EntityUid uid, MailingUnitComponent component, DeviceNetworkComponent? device = null) - { - if (string.IsNullOrEmpty(component.Tag) || string.IsNullOrEmpty(component.Target) || !Resolve(uid, ref device)) - return; - - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = NetCmdSent, - [NetSrc] = component.Tag, - [NetTarget] = component.Target - }; - - _deviceNetworkSystem.QueuePacket(uid, null, payload, null, null, device); - } - - /// - /// Clears the units target list and broadcasts a . - /// The target list will then get populated with responses from all active mailing units on the same grid - /// - private void UpdateTargetList(EntityUid uid, MailingUnitComponent component, DeviceNetworkComponent? device = null) - { - if (!Resolve(uid, ref device, false)) - return; - - var payload = new NetworkPayload - { - [DeviceNetworkConstants.Command] = NetCmdRequest - }; - - component.TargetList.Clear(); - _deviceNetworkSystem.QueuePacket(uid, null, payload, null, null, device); - } - - /// - /// Gets called when the units tag got updated - /// - private void OnConfigurationUpdated(EntityUid uid, MailingUnitComponent component, ConfigurationSystem.ConfigurationUpdatedEvent args) - { - var configuration = args.Configuration.Config; - if (!configuration.ContainsKey(TagConfigurationKey) || configuration[TagConfigurationKey] == string.Empty) - { - component.Tag = null; - return; - } - - component.Tag = configuration[TagConfigurationKey]; - UpdateUserInterface(uid, component); - } - - private void HandleActivate(EntityUid uid, MailingUnitComponent component, ActivateInWorldEvent args) - { - if (args.Handled || !args.Complex) - return; - - if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor)) - { - return; - } - - args.Handled = true; - UpdateTargetList(uid, component); - _userInterfaceSystem.OpenUi(uid, MailingUnitUiKey.Key, actor.PlayerSession); - } - - /// - /// Gets called when the disposal unit components ui state changes. This is required because the mailing unit requires a disposal unit component and overrides its ui - /// - private void OnDisposalUnitUIStateChange(EntityUid uid, MailingUnitComponent component, DisposalUnitUIStateUpdatedEvent args) - { - component.DisposalUnitInterfaceState = args.State; - UpdateUserInterface(uid, component); - } - - private void UpdateUserInterface(EntityUid uid, MailingUnitComponent component) - { - if (component.DisposalUnitInterfaceState == null) - return; - - var state = new MailingUnitBoundUserInterfaceState(component.DisposalUnitInterfaceState, component.Target, component.TargetList.ShallowClone(), component.Tag); - _userInterfaceSystem.SetUiState(uid, MailingUnitUiKey.Key, state); - } - - private void OnTargetSelected(EntityUid uid, MailingUnitComponent component, TargetSelectedMessage args) - { - component.Target = args.Target; - UpdateUserInterface(uid, component); - } - - /// - /// Checks if the unit is powered if an is present - /// - /// True if the power receiver component is powered or not present - private bool IsPowered(EntityUid uid, ApcPowerReceiverComponent? powerReceiver = null) - { - if (Resolve(uid, ref powerReceiver) && !powerReceiver.Powered) - return false; - - return true; - } } diff --git a/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs b/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs deleted file mode 100644 index e4b8955c9c..0000000000 --- a/Content.Server/Disposal/Tube/Components/DisposalEntryComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Content.Server.Disposal.Unit.EntitySystems; - -namespace Content.Server.Disposal.Tube.Components -{ - [RegisterComponent] - [Access(typeof(DisposalTubeSystem), typeof(DisposalUnitSystem))] - public sealed partial class DisposalEntryComponent : Component - { - public const string HolderPrototypeId = "DisposalHolder"; - } -} diff --git a/Content.Server/Disposal/Tube/Components/DisposalBendComponent.cs b/Content.Server/Disposal/Tube/DisposalBendComponent.cs similarity index 70% rename from Content.Server/Disposal/Tube/Components/DisposalBendComponent.cs rename to Content.Server/Disposal/Tube/DisposalBendComponent.cs index ace8a68462..7aa48f4bd3 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalBendComponent.cs +++ b/Content.Server/Disposal/Tube/DisposalBendComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Disposal.Tube.Components; +namespace Content.Server.Disposal.Tube; [RegisterComponent] [Access(typeof(DisposalTubeSystem))] diff --git a/Content.Server/Disposal/Tube/Components/DisposalJunctionComponent.cs b/Content.Server/Disposal/Tube/DisposalJunctionComponent.cs similarity index 84% rename from Content.Server/Disposal/Tube/Components/DisposalJunctionComponent.cs rename to Content.Server/Disposal/Tube/DisposalJunctionComponent.cs index d929dd16bf..af0d7eda68 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalJunctionComponent.cs +++ b/Content.Server/Disposal/Tube/DisposalJunctionComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Disposal.Tube.Components; +namespace Content.Server.Disposal.Tube; [RegisterComponent] [Access(typeof(DisposalTubeSystem))] diff --git a/Content.Server/Disposal/Tube/Components/DisposalRouterComponent.cs b/Content.Server/Disposal/Tube/DisposalRouterComponent.cs similarity index 57% rename from Content.Server/Disposal/Tube/Components/DisposalRouterComponent.cs rename to Content.Server/Disposal/Tube/DisposalRouterComponent.cs index 18c0945cef..2446cf27f7 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalRouterComponent.cs +++ b/Content.Server/Disposal/Tube/DisposalRouterComponent.cs @@ -1,12 +1,6 @@ -using Content.Server.UserInterface; -using Robust.Server.GameObjects; using Robust.Shared.Audio; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Player; -using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; -namespace Content.Server.Disposal.Tube.Components +namespace Content.Server.Disposal.Tube { [RegisterComponent] [Access(typeof(DisposalTubeSystem))] diff --git a/Content.Server/Disposal/Tube/Components/DisposalSignalRouterComponent.cs b/Content.Server/Disposal/Tube/DisposalSignalRouterComponent.cs similarity index 91% rename from Content.Server/Disposal/Tube/Components/DisposalSignalRouterComponent.cs rename to Content.Server/Disposal/Tube/DisposalSignalRouterComponent.cs index b4ef81d898..bee8293f58 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalSignalRouterComponent.cs +++ b/Content.Server/Disposal/Tube/DisposalSignalRouterComponent.cs @@ -1,8 +1,7 @@ -using Content.Server.Disposal.Tube.Systems; using Content.Shared.DeviceLinking; using Robust.Shared.Prototypes; -namespace Content.Server.Disposal.Tube.Components; +namespace Content.Server.Disposal.Tube; /// /// Requires to function. diff --git a/Content.Server/Disposal/Tube/Systems/DisposalSignalRouterSystem.cs b/Content.Server/Disposal/Tube/DisposalSignalRouterSystem.cs similarity index 94% rename from Content.Server/Disposal/Tube/Systems/DisposalSignalRouterSystem.cs rename to Content.Server/Disposal/Tube/DisposalSignalRouterSystem.cs index f1fdedb522..0d6c03b8c5 100644 --- a/Content.Server/Disposal/Tube/Systems/DisposalSignalRouterSystem.cs +++ b/Content.Server/Disposal/Tube/DisposalSignalRouterSystem.cs @@ -1,8 +1,7 @@ using Content.Server.DeviceLinking.Systems; -using Content.Server.Disposal.Tube.Components; using Content.Shared.DeviceLinking.Events; -namespace Content.Server.Disposal.Tube.Systems; +namespace Content.Server.Disposal.Tube; /// /// Handles signals and the routing get next direction event. diff --git a/Content.Server/Disposal/Tube/Components/DisposalTaggerComponent.cs b/Content.Server/Disposal/Tube/DisposalTaggerComponent.cs similarity index 53% rename from Content.Server/Disposal/Tube/Components/DisposalTaggerComponent.cs rename to Content.Server/Disposal/Tube/DisposalTaggerComponent.cs index a291f4a941..3f072a80c7 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalTaggerComponent.cs +++ b/Content.Server/Disposal/Tube/DisposalTaggerComponent.cs @@ -1,13 +1,6 @@ -using Content.Server.Disposal.Unit.Components; -using Content.Server.UserInterface; -using Robust.Server.GameObjects; using Robust.Shared.Audio; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Player; -using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; -namespace Content.Server.Disposal.Tube.Components +namespace Content.Server.Disposal.Tube { [RegisterComponent] public sealed partial class DisposalTaggerComponent : DisposalTransitComponent diff --git a/Content.Server/Disposal/Tube/Components/DisposalTransitComponent.cs b/Content.Server/Disposal/Tube/DisposalTransitComponent.cs similarity index 82% rename from Content.Server/Disposal/Tube/Components/DisposalTransitComponent.cs rename to Content.Server/Disposal/Tube/DisposalTransitComponent.cs index e916327516..10bc7d5df7 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalTransitComponent.cs +++ b/Content.Server/Disposal/Tube/DisposalTransitComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Disposal.Tube.Components +namespace Content.Server.Disposal.Tube { // TODO: Different types of tubes eject in random direction with no exit point [RegisterComponent] diff --git a/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs b/Content.Server/Disposal/Tube/DisposalTubeComponent.cs similarity index 90% rename from Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs rename to Content.Server/Disposal/Tube/DisposalTubeComponent.cs index c16f1fcc22..15d02ad1ef 100644 --- a/Content.Server/Disposal/Tube/Components/DisposalTubeComponent.cs +++ b/Content.Server/Disposal/Tube/DisposalTubeComponent.cs @@ -1,9 +1,9 @@ -using Content.Server.Disposal.Unit.EntitySystems; +using Content.Server.Disposal.Unit; using Content.Shared.Damage; using Robust.Shared.Audio; using Robust.Shared.Containers; -namespace Content.Server.Disposal.Tube.Components; +namespace Content.Server.Disposal.Tube; [RegisterComponent] [Access(typeof(DisposalTubeSystem), typeof(DisposableSystem))] diff --git a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs index 20626a5eee..f1e094db20 100644 --- a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs +++ b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs @@ -2,12 +2,12 @@ using System.Linq; using System.Text; using Content.Server.Atmos.EntitySystems; using Content.Server.Construction.Completions; -using Content.Server.Disposal.Tube.Components; -using Content.Server.Disposal.Unit.Components; -using Content.Server.Disposal.Unit.EntitySystems; +using Content.Server.Disposal.Unit; using Content.Server.Popups; using Content.Shared.Destructible; using Content.Shared.Disposal.Components; +using Content.Shared.Disposal.Tube; +using Content.Shared.Disposal.Unit; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; @@ -16,12 +16,10 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Random; -using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; -using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; namespace Content.Server.Disposal.Tube { - public sealed class DisposalTubeSystem : EntitySystem + public sealed class DisposalTubeSystem : SharedDisposalTubeSystem { [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; @@ -49,8 +47,8 @@ namespace Content.Server.Disposal.Tube SubscribeLocalEvent(OnGetBendConnectableDirections); SubscribeLocalEvent(OnGetBendNextDirection); - SubscribeLocalEvent(OnGetEntryConnectableDirections); - SubscribeLocalEvent(OnGetEntryNextDirection); + SubscribeLocalEvent(OnGetEntryConnectableDirections); + SubscribeLocalEvent(OnGetEntryNextDirection); SubscribeLocalEvent(OnGetJunctionConnectableDirections); SubscribeLocalEvent(OnGetJunctionNextDirection); @@ -64,13 +62,13 @@ namespace Content.Server.Disposal.Tube SubscribeLocalEvent(OnGetTaggerConnectableDirections); SubscribeLocalEvent(OnGetTaggerNextDirection); - Subs.BuiEvents(DisposalRouterUiKey.Key, subs => + Subs.BuiEvents(SharedDisposalRouterComponent.DisposalRouterUiKey.Key, subs => { subs.Event(OnOpenRouterUI); subs.Event(OnUiAction); }); - Subs.BuiEvents(DisposalTaggerUiKey.Key, subs => + Subs.BuiEvents(SharedDisposalTaggerComponent.DisposalTaggerUiKey.Key, subs => { subs.Event(OnOpenTaggerUI); subs.Event(OnUiAction); @@ -161,12 +159,12 @@ namespace Content.Server.Disposal.Tube args.Next = previousDF == ev.Connectable[0] ? ev.Connectable[1] : ev.Connectable[0]; } - private void OnGetEntryConnectableDirections(EntityUid uid, DisposalEntryComponent component, ref GetDisposalsConnectableDirectionsEvent args) + private void OnGetEntryConnectableDirections(EntityUid uid, Shared.Disposal.Tube.DisposalEntryComponent component, ref GetDisposalsConnectableDirectionsEvent args) { args.Connectable = new[] { Transform(uid).LocalRotation.GetDir() }; } - private void OnGetEntryNextDirection(EntityUid uid, DisposalEntryComponent component, ref GetDisposalsNextDirectionEvent args) + private void OnGetEntryNextDirection(EntityUid uid, Shared.Disposal.Tube.DisposalEntryComponent component, ref GetDisposalsNextDirectionEvent args) { // Ejects contents when they come from the same direction the entry is facing. if (args.Holder.PreviousDirectionFrom != Direction.Invalid) @@ -283,10 +281,10 @@ namespace Content.Server.Disposal.Tube private void OnOpenTaggerUI(EntityUid uid, DisposalTaggerComponent tagger, BoundUIOpenedEvent args) { - if (_uiSystem.HasUi(uid, DisposalTaggerUiKey.Key)) + if (_uiSystem.HasUi(uid, SharedDisposalTaggerComponent.DisposalTaggerUiKey.Key)) { - _uiSystem.SetUiState(uid, DisposalTaggerUiKey.Key, - new DisposalTaggerUserInterfaceState(tagger.Tag)); + _uiSystem.SetUiState(uid, SharedDisposalTaggerComponent.DisposalTaggerUiKey.Key, + new SharedDisposalTaggerComponent.DisposalTaggerUserInterfaceState(tagger.Tag)); } } @@ -298,7 +296,7 @@ namespace Content.Server.Disposal.Tube { if (router.Tags.Count <= 0) { - _uiSystem.SetUiState(uid, DisposalRouterUiKey.Key, new DisposalRouterUserInterfaceState("")); + _uiSystem.SetUiState(uid, SharedDisposalRouterComponent.DisposalRouterUiKey.Key, new SharedDisposalRouterComponent.DisposalRouterUserInterfaceState("")); return; } @@ -312,7 +310,7 @@ namespace Content.Server.Disposal.Tube taglist.Remove(taglist.Length - 2, 2); - _uiSystem.SetUiState(uid, DisposalRouterUiKey.Key, new DisposalRouterUserInterfaceState(taglist.ToString())); + _uiSystem.SetUiState(uid, SharedDisposalRouterComponent.DisposalRouterUiKey.Key, new SharedDisposalRouterComponent.DisposalRouterUserInterfaceState(taglist.ToString())); } private void OnAnchorChange(EntityUid uid, DisposalTubeComponent component, ref AnchorStateChangedEvent args) @@ -419,13 +417,13 @@ namespace Content.Server.Disposal.Tube _popups.PopupEntity(Loc.GetString("disposal-tube-component-popup-directions-text", ("directions", directions)), tubeId, recipient); } - public bool TryInsert(EntityUid uid, DisposalUnitComponent from, IEnumerable? tags = default, DisposalEntryComponent? entry = null) + public override bool TryInsert(EntityUid uid, DisposalUnitComponent from, IEnumerable? tags = default, DisposalEntryComponent? entry = null) { if (!Resolve(uid, ref entry)) return false; var xform = Transform(uid); - var holder = Spawn(DisposalEntryComponent.HolderPrototypeId, _transform.GetMapCoordinates(uid, xform: xform)); + var holder = Spawn(entry.HolderPrototypeId, _transform.GetMapCoordinates(uid, xform: xform)); var holderComponent = Comp(holder); foreach (var entity in from.Container.ContainedEntities.ToArray()) @@ -436,7 +434,7 @@ namespace Content.Server.Disposal.Tube _atmosSystem.Merge(holderComponent.Air, from.Air); from.Air.Clear(); - if (tags != default) + if (tags != null) holderComponent.Tags.UnionWith(tags); return _disposableSystem.EnterTube(holder, uid, holderComponent); diff --git a/Content.Server/Disposal/Tube/GetDisposalsNextDirectionEvent.cs b/Content.Server/Disposal/Tube/GetDisposalsNextDirectionEvent.cs index 2872a0e6d0..30dd1c3769 100644 --- a/Content.Server/Disposal/Tube/GetDisposalsNextDirectionEvent.cs +++ b/Content.Server/Disposal/Tube/GetDisposalsNextDirectionEvent.cs @@ -1,4 +1,4 @@ -using Content.Server.Disposal.Unit.Components; +using Content.Server.Disposal.Unit; namespace Content.Server.Disposal.Tube; diff --git a/Content.Server/Disposal/TubeConnectionsCommand.cs b/Content.Server/Disposal/TubeConnectionsCommand.cs index 564c46be7a..6719a9a2ab 100644 --- a/Content.Server/Disposal/TubeConnectionsCommand.cs +++ b/Content.Server/Disposal/TubeConnectionsCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Administration; using Content.Server.Disposal.Tube; -using Content.Server.Disposal.Tube.Components; using Content.Shared.Administration; using Robust.Shared.Console; diff --git a/Content.Server/Disposal/Unit/Components/BeingDisposedComponent.cs b/Content.Server/Disposal/Unit/BeingDisposedComponent.cs similarity index 81% rename from Content.Server/Disposal/Unit/Components/BeingDisposedComponent.cs rename to Content.Server/Disposal/Unit/BeingDisposedComponent.cs index 060c7c98bd..3cff669855 100644 --- a/Content.Server/Disposal/Unit/Components/BeingDisposedComponent.cs +++ b/Content.Server/Disposal/Unit/BeingDisposedComponent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Disposal.Unit.Components; +namespace Content.Server.Disposal.Unit; /// /// A component added to entities that are currently in disposals. diff --git a/Content.Server/Disposal/Unit/EntitySystems/BeingDisposedSystem.cs b/Content.Server/Disposal/Unit/BeingDisposedSystem.cs similarity index 92% rename from Content.Server/Disposal/Unit/EntitySystems/BeingDisposedSystem.cs rename to Content.Server/Disposal/Unit/BeingDisposedSystem.cs index 6fbfb1523a..fcff4ba3b5 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/BeingDisposedSystem.cs +++ b/Content.Server/Disposal/Unit/BeingDisposedSystem.cs @@ -1,8 +1,7 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Systems; -using Content.Server.Disposal.Unit.Components; -namespace Content.Server.Disposal.Unit.EntitySystems; +namespace Content.Server.Disposal.Unit; public sealed class BeingDisposedSystem : EntitySystem { diff --git a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs deleted file mode 100644 index 548af039da..0000000000 --- a/Content.Server/Disposal/Unit/Components/DisposalUnitComponent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Content.Server.Atmos; -using Content.Shared.Atmos; -using Content.Shared.Disposal.Components; - -namespace Content.Server.Disposal.Unit.Components; - -// GasMixture life. -[RegisterComponent] -public sealed partial class DisposalUnitComponent : SharedDisposalUnitComponent -{ - [DataField("air")] - public GasMixture Air = new(Atmospherics.CellVolume); -} diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs b/Content.Server/Disposal/Unit/DisposableSystem.cs similarity index 98% rename from Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs rename to Content.Server/Disposal/Unit/DisposableSystem.cs index 0e624ca6f5..a94176246c 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposableSystem.cs +++ b/Content.Server/Disposal/Unit/DisposableSystem.cs @@ -1,9 +1,8 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Disposal.Tube; -using Content.Server.Disposal.Tube.Components; -using Content.Server.Disposal.Unit.Components; using Content.Shared.Body.Components; using Content.Shared.Damage; +using Content.Shared.Disposal.Components; using Content.Shared.Item; using Content.Shared.Throwing; using Robust.Shared.Audio.Systems; @@ -12,7 +11,7 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; -namespace Content.Server.Disposal.Unit.EntitySystems +namespace Content.Server.Disposal.Unit { public sealed class DisposableSystem : EntitySystem { diff --git a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs b/Content.Server/Disposal/Unit/DisposalHolderComponent.cs similarity index 94% rename from Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs rename to Content.Server/Disposal/Unit/DisposalHolderComponent.cs index 690b33968b..be90ae9f9c 100644 --- a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs +++ b/Content.Server/Disposal/Unit/DisposalHolderComponent.cs @@ -1,9 +1,8 @@ using Content.Server.Atmos; -using Content.Server.Disposal.Tube.Components; using Content.Shared.Atmos; using Robust.Shared.Containers; -namespace Content.Server.Disposal.Unit.Components +namespace Content.Server.Disposal.Unit { [RegisterComponent] public sealed partial class DisposalHolderComponent : Component, IGasMixtureHolder diff --git a/Content.Server/Disposal/Unit/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/DisposalUnitSystem.cs new file mode 100644 index 0000000000..4c6436c6c9 --- /dev/null +++ b/Content.Server/Disposal/Unit/DisposalUnitSystem.cs @@ -0,0 +1,44 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Destructible; +using Content.Shared.Disposal.Components; +using Content.Shared.Disposal.Unit; +using Content.Shared.Explosion; + +namespace Content.Server.Disposal.Unit; + +public sealed class DisposalUnitSystem : SharedDisposalUnitSystem +{ + [Dependency] private readonly AtmosphereSystem _atmosSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDestruction); + SubscribeLocalEvent(OnExploded); + } + + protected override void HandleAir(EntityUid uid, DisposalUnitComponent component, TransformComponent xform) + { + var air = component.Air; + var indices = TransformSystem.GetGridTilePositionOrDefault((uid, xform)); + + if (_atmosSystem.GetTileMixture(xform.GridUid, xform.MapUid, indices, true) is { Temperature: > 0f } environment) + { + var transferMoles = 0.1f * (0.25f * Atmospherics.OneAtmosphere * 1.01f - air.Pressure) * air.Volume / (environment.Temperature * Atmospherics.R); + + component.Air = environment.Remove(transferMoles); + } + } + + private void OnDestruction(EntityUid uid, DisposalUnitComponent component, DestructionEventArgs args) + { + TryEjectContents(uid, component); + } + + private void OnExploded(Entity ent, ref BeforeExplodeEvent args) + { + args.Contents.AddRange(ent.Comp.Container.ContainedEntities); + } +} diff --git a/Content.Server/Disposal/Unit/EntitySystems/DoInsertDisposalUnitEvent.cs b/Content.Server/Disposal/Unit/DoInsertDisposalUnitEvent.cs similarity index 65% rename from Content.Server/Disposal/Unit/EntitySystems/DoInsertDisposalUnitEvent.cs rename to Content.Server/Disposal/Unit/DoInsertDisposalUnitEvent.cs index 6fdfce61da..3f3fee9785 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DoInsertDisposalUnitEvent.cs +++ b/Content.Server/Disposal/Unit/DoInsertDisposalUnitEvent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Disposal.Unit.EntitySystems +namespace Content.Server.Disposal.Unit { public record DoInsertDisposalUnitEvent(EntityUid? User, EntityUid ToInsert, EntityUid Unit); } diff --git a/Content.Server/Fax/AdminUI/AdminFaxEui.cs b/Content.Server/Fax/AdminUI/AdminFaxEui.cs index fe6b03fab7..2921bd5ef6 100644 --- a/Content.Server/Fax/AdminUI/AdminFaxEui.cs +++ b/Content.Server/Fax/AdminUI/AdminFaxEui.cs @@ -7,6 +7,7 @@ using Content.Shared.Fax; using Content.Shared.Follower; using Content.Shared.Ghost; using Content.Shared.Paper; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Fax.AdminUI; diff --git a/Content.Server/Fax/FaxSystem.cs b/Content.Server/Fax/FaxSystem.cs index 1ac7bd23ca..79710e3f97 100644 --- a/Content.Server/Fax/FaxSystem.cs +++ b/Content.Server/Fax/FaxSystem.cs @@ -1,8 +1,6 @@ using Content.Server.Administration; using Content.Server.Administration.Managers; using Content.Server.Chat.Managers; -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Server.Popups; using Content.Server.Power.Components; @@ -12,7 +10,7 @@ using Content.Shared.Administration.Logs; using Content.Shared.Containers.ItemSlots; using Content.Shared.Database; using Content.Shared.DeviceNetwork; -using Content.Shared.Emag.Components; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Emag.Systems; using Content.Shared.Fax; using Content.Shared.Fax.Systems; @@ -27,9 +25,9 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.Player; -using Robust.Shared.Prototypes; using Content.Shared.NameModifier.Components; using Content.Shared.Power; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Fax; diff --git a/Content.Server/GameTicking/GameTicker.GamePreset.cs b/Content.Server/GameTicking/GameTicker.GamePreset.cs index 14985051e7..c062b95361 100644 --- a/Content.Server/GameTicking/GameTicker.GamePreset.cs +++ b/Content.Server/GameTicking/GameTicker.GamePreset.cs @@ -109,7 +109,11 @@ public sealed partial class GameTicker // Reset counter is checked and changed at the end of each round // So if the game is in the lobby, the first requested round will happen before the check, and we need one less check if (CurrentPreset is null) - ResetCountdown = resetDelay.Value -1; + ResetCountdown = resetDelay.Value - 1; + } + else + { + ResetCountdown = null; } Preset = preset; diff --git a/Content.Server/Item/MultiHandedItemSystem.cs b/Content.Server/Item/MultiHandedItemSystem.cs deleted file mode 100644 index 9146c7c982..0000000000 --- a/Content.Server/Item/MultiHandedItemSystem.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Content.Server.Hands.Systems; -using Content.Server.Inventory; -using Content.Shared.Hands; -using Content.Shared.Item; - -namespace Content.Server.Item; - -public sealed class MultiHandedItemSystem : SharedMultiHandedItemSystem -{ - [Dependency] private readonly VirtualItemSystem _virtualItem = default!; - - protected override void OnEquipped(EntityUid uid, MultiHandedItemComponent component, GotEquippedHandEvent args) - { - for (var i = 0; i < component.HandsNeeded - 1; i++) - { - _virtualItem.TrySpawnVirtualItemInHand(uid, args.User); - } - } - - protected override void OnUnequipped(EntityUid uid, MultiHandedItemComponent component, GotUnequippedHandEvent args) - { - _virtualItem.DeleteInHandsMatching(args.User, uid); - } -} diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs index 53c60296d5..b98ba15623 100644 --- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs +++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs @@ -19,6 +19,8 @@ using Robust.Shared.Timing; using Robust.Shared.Audio.Systems; using Content.Shared.Damage.Systems; using Content.Shared.Damage.Components; +using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; namespace Content.Server.Light.EntitySystems diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs index a53df6dbae..0e1d27a3c5 100644 --- a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs @@ -2,6 +2,8 @@ using System.Linq; using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Systems; using Content.Server.PowerCell; +using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Medical.CrewMonitoring; using Content.Shared.Medical.SuitSensor; using Content.Shared.Pinpointer; diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs index d7b8cc67a5..ad50a8f957 100644 --- a/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringServerSystem.cs @@ -1,10 +1,10 @@ -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Server.Medical.SuitSensors; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Medical.SuitSensor; using Robust.Shared.Timing; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Medical.CrewMonitoring; diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index fa4344cc78..2ab09e746f 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -1,7 +1,5 @@ using System.Numerics; using Content.Server.Access.Systems; -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Server.Emp; using Content.Server.Medical.CrewMonitoring; @@ -26,6 +24,7 @@ using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Medical.SuitSensors; diff --git a/Content.Server/PDA/PdaSystem.cs b/Content.Server/PDA/PdaSystem.cs index f63cdff227..6f0d6b7306 100644 --- a/Content.Server/PDA/PdaSystem.cs +++ b/Content.Server/PDA/PdaSystem.cs @@ -2,31 +2,27 @@ using Content.Server.Access.Systems; using Content.Server.AlertLevel; using Content.Server.CartridgeLoader; using Content.Server.Chat.Managers; -using Content.Server.DeviceNetwork.Components; using Content.Server.Instruments; -using Content.Server.Light.EntitySystems; using Content.Server.PDA.Ringer; using Content.Server.RoundEnd; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Systems; using Content.Server.Station.Systems; -using Content.Server.Store.Components; using Content.Server.Store.Systems; using Content.Server.Traitor.Uplink; using Content.Shared.Access.Components; using Content.Shared.CartridgeLoader; using Content.Shared.Chat; using Content.Shared.Light; -using Content.Shared.Light.Components; using Content.Shared.Light.EntitySystems; using Content.Shared.PDA; -using Content.Shared.Store.Components; using Robust.Server.Containers; using Robust.Server.GameObjects; using Robust.Shared.Configuration; using Robust.Shared.Containers; using Robust.Shared.Player; using Robust.Shared.Utility; +using Content.Shared.DeviceNetwork.Components; using Content.Shared.CCVar; using Robust.Shared.Timing; diff --git a/Content.Server/Power/EntitySystems/BatterySystem.cs b/Content.Server/Power/EntitySystems/BatterySystem.cs index 6e636622e6..89e3ed2c1f 100644 --- a/Content.Server/Power/EntitySystems/BatterySystem.cs +++ b/Content.Server/Power/EntitySystems/BatterySystem.cs @@ -13,7 +13,7 @@ namespace Content.Server.Power.EntitySystems [UsedImplicitly] public sealed class BatterySystem : EntitySystem { - [Dependency] protected readonly IGameTiming Timing = default!; + [Dependency] private readonly IGameTiming _timing = default!; public override void Initialize() { @@ -92,7 +92,7 @@ namespace Content.Server.Power.EntitySystems if (comp.AutoRechargePause) { - if (comp.NextAutoRecharge > Timing.CurTime) + if (comp.NextAutoRecharge > _timing.CurTime) continue; } @@ -179,7 +179,7 @@ namespace Content.Server.Power.EntitySystems if (value < 0) value = batteryself.AutoRechargePauseTime; - if (Timing.CurTime + TimeSpan.FromSeconds(value) <= batteryself.NextAutoRecharge) + if (_timing.CurTime + TimeSpan.FromSeconds(value) <= batteryself.NextAutoRecharge) return; SetChargeCooldown(uid, batteryself.AutoRechargePauseTime, batteryself); @@ -194,9 +194,9 @@ namespace Content.Server.Power.EntitySystems return; if (value >= 0) - batteryself.NextAutoRecharge = Timing.CurTime + TimeSpan.FromSeconds(value); + batteryself.NextAutoRecharge = _timing.CurTime + TimeSpan.FromSeconds(value); else - batteryself.NextAutoRecharge = Timing.CurTime; + batteryself.NextAutoRecharge = _timing.CurTime; } /// diff --git a/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs b/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs index 0239273455..f3405486e6 100644 --- a/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs @@ -15,7 +15,6 @@ namespace Content.Server.Power.EntitySystems public sealed class PowerReceiverSystem : SharedPowerReceiverSystem { [Dependency] private readonly IAdminManager _adminManager = default!; - private EntityQuery _recQuery; private EntityQuery _provQuery; diff --git a/Content.Server/Power/Generation/Teg/TegSystem.cs b/Content.Server/Power/Generation/Teg/TegSystem.cs index 437d805dcd..04f876c2c2 100644 --- a/Content.Server/Power/Generation/Teg/TegSystem.cs +++ b/Content.Server/Power/Generation/Teg/TegSystem.cs @@ -9,6 +9,7 @@ using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; using Content.Shared.Atmos; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Examine; using Content.Shared.Power; using Content.Shared.Power.EntitySystems; diff --git a/Content.Server/Radio/EntitySystems/JammerSystem.cs b/Content.Server/Radio/EntitySystems/JammerSystem.cs index 1fe48d22b4..1cea981d3c 100644 --- a/Content.Server/Radio/EntitySystems/JammerSystem.cs +++ b/Content.Server/Radio/EntitySystems/JammerSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.DeviceNetwork.Components; using Content.Server.Power.EntitySystems; using Content.Server.PowerCell; using Content.Shared.DeviceNetwork.Components; diff --git a/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs b/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs index 916694fdd8..c4554d65d6 100644 --- a/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs +++ b/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs @@ -1,5 +1,4 @@ using Content.Server.Administration.Logs; -using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Systems; using Content.Server.Radio.EntitySystems; using Content.Shared.Lock; @@ -10,7 +9,7 @@ using Content.Shared.Robotics.Components; using Content.Shared.Robotics.Systems; using Robust.Server.GameObjects; using Robust.Shared.Timing; -using System.Diagnostics.CodeAnalysis; +using Content.Shared.DeviceNetwork.Events; namespace Content.Server.Research.Systems; diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index a6686c1a2d..20ad4291f5 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -20,6 +20,7 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Prototypes; using Robust.Shared.Timing; +using Content.Shared.DeviceNetwork.Components; using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.RoundEnd diff --git a/Content.Server/Screens/Systems/ScreenSystem.cs b/Content.Server/Screens/Systems/ScreenSystem.cs index 782fe38c88..c159bfe1d5 100644 --- a/Content.Server/Screens/Systems/ScreenSystem.cs +++ b/Content.Server/Screens/Systems/ScreenSystem.cs @@ -2,6 +2,8 @@ using Content.Shared.TextScreen; using Content.Server.Screens.Components; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; using Robust.Shared.Timing; @@ -63,7 +65,7 @@ public sealed class ScreenSystem : EntitySystem /// /// Determines if/how a timer packet affects this screen. /// Currently there are 2 broadcast domains: Arrivals, and every other screen. - /// Domain is determined by the on each timer. + /// Domain is determined by the on each timer. /// Each broadcast domain is divided into subnets. Screen MapUid determines subnet. /// Subnets are the shuttle, source, and dest. Source/dest change each jump. /// This is required to send different timers to the shuttle/terminal/station. diff --git a/Content.Server/SensorMonitoring/BatterySensorSystem.cs b/Content.Server/SensorMonitoring/BatterySensorSystem.cs index 501b094c89..5047cd1d29 100644 --- a/Content.Server/SensorMonitoring/BatterySensorSystem.cs +++ b/Content.Server/SensorMonitoring/BatterySensorSystem.cs @@ -2,6 +2,7 @@ using Content.Server.DeviceNetwork.Systems; using Content.Server.Power.Components; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; namespace Content.Server.SensorMonitoring; diff --git a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs index dec3e6c36e..a562abd926 100644 --- a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs +++ b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs @@ -1,7 +1,7 @@ -using Content.Server.DeviceNetwork.Components; -using Content.Shared.SensorMonitoring; +using Content.Shared.SensorMonitoring; using Robust.Shared.Collections; using ConsoleUIState = Content.Shared.SensorMonitoring.SensorMonitoringConsoleBoundInterfaceState; +using Content.Shared.DeviceNetwork.Components; using IncrementalUIState = Content.Shared.SensorMonitoring.SensorMonitoringIncrementalUpdate; namespace Content.Server.SensorMonitoring; diff --git a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.cs b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.cs index ddd7812394..ebe8f304ba 100644 --- a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.cs +++ b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.cs @@ -1,10 +1,7 @@ using Content.Server.Atmos.Monitor.Components; using Content.Server.Atmos.Monitor.Systems; -using Content.Server.Atmos.Piping.Binary.Components; using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Unary.Components; -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Server.Power.Generation.Teg; using Content.Shared.Atmos.Monitor; @@ -12,6 +9,7 @@ using Content.Shared.Atmos.Piping.Binary.Components; using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.DeviceNetwork.Systems; using Content.Shared.SensorMonitoring; using Robust.Server.GameObjects; diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs index fc8dda9ec0..f273c1fbdb 100644 --- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs +++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Numerics; using Content.Server.Administration; using Content.Server.Chat.Managers; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Server.GameTicking; using Content.Server.GameTicking.Events; @@ -19,6 +18,7 @@ using Content.Shared.Administration; using Content.Shared.CCVar; using Content.Shared.Damage.Components; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Components; using Content.Shared.GameTicking; using Content.Shared.Mobs.Components; using Content.Shared.Movement.Components; @@ -26,20 +26,17 @@ using Content.Shared.Parallax.Biomes; using Content.Shared.Salvage; using Content.Shared.Shuttles.Components; using Content.Shared.Tiles; -using Robust.Server.GameObjects; using Robust.Shared.Collections; using Robust.Shared.Configuration; using Robust.Shared.Console; -using Robust.Shared.EntitySerialization; using Robust.Shared.EntitySerialization.Systems; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.Spawners; using Robust.Shared.Timing; using Robust.Shared.Utility; -using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; namespace Content.Server.Shuttles.Systems; diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs index 9eb8b70584..ab3337af1e 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs @@ -16,6 +16,7 @@ using Content.Shared.Shuttles.Systems; using Content.Shared.UserInterface; using Robust.Shared.Map; using Robust.Shared.Player; +using Content.Shared.DeviceNetwork.Components; using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.Shuttles.Systems; diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index 9434098210..fd83bfab12 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -8,7 +8,6 @@ using Content.Server.Administration.Managers; using Content.Server.Atmos.EntitySystems; using Content.Server.Chat.Systems; using Content.Server.Communications; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Server.GameTicking; using Content.Server.GameTicking.Events; @@ -55,6 +54,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; using Robust.Shared.Utility; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.Shuttles.Systems; diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs index 4d2a8912e8..e950d3f288 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs @@ -1,13 +1,10 @@ using Content.Shared.DeviceNetwork; -using Content.Shared.Emag.Components; using Content.Shared.Movement.Components; using Content.Shared.Popups; using Content.Shared.Robotics; using Content.Shared.Silicons.Borgs.Components; -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; -using Content.Server.DeviceNetwork.Systems; -using Content.Server.Explosion.Components; +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Emag.Systems; using Robust.Shared.Utility; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs index d06cfc7de9..806c26dec3 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs @@ -3,6 +3,7 @@ using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Systems; using Content.Server.Power.Components; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.UserInterface; using Content.Shared.SurveillanceCamera; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs index 75bddf8a98..ae1020ed87 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs @@ -1,15 +1,13 @@ -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; -using Content.Server.Power.Components; using Content.Shared.ActionBlocker; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.SurveillanceCamera; using Content.Shared.Verbs; using Robust.Server.GameObjects; -using Robust.Shared.Player; using Robust.Shared.Prototypes; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.SurveillanceCamera; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs index 735183d99e..336038651e 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs @@ -1,16 +1,15 @@ -using Content.Server.DeviceNetwork; -using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Server.Emp; -using Content.Server.Power.Components; using Content.Shared.ActionBlocker; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.SurveillanceCamera; using Content.Shared.Verbs; using Robust.Server.GameObjects; using Robust.Shared.Player; using Robust.Shared.Prototypes; +using Content.Shared.DeviceNetwork.Components; namespace Content.Server.SurveillanceCamera; diff --git a/Content.Server/Turrets/DeployableTurretSystem.cs b/Content.Server/Turrets/DeployableTurretSystem.cs index 359d91fd1d..72c011bc90 100644 --- a/Content.Server/Turrets/DeployableTurretSystem.cs +++ b/Content.Server/Turrets/DeployableTurretSystem.cs @@ -8,6 +8,8 @@ using Content.Server.Power.Components; using Content.Server.Repairable; using Content.Shared.Destructible; using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; using Content.Shared.Power; using Content.Shared.Turrets; using Content.Shared.Weapons.Ranged.Events; diff --git a/Content.Shared/Charges/Systems/SharedChargesSystem.cs b/Content.Shared/Charges/Systems/SharedChargesSystem.cs index e48d962018..ed1ff94f13 100644 --- a/Content.Shared/Charges/Systems/SharedChargesSystem.cs +++ b/Content.Shared/Charges/Systems/SharedChargesSystem.cs @@ -126,7 +126,7 @@ public abstract class SharedChargesSystem : EntitySystem action.Comp.LastUpdate = _timing.CurTime; } - action.Comp.LastCharges = Math.Clamp(action.Comp.LastCharges + addCharges, 0, action.Comp.MaxCharges); + action.Comp.LastCharges = Math.Clamp(charges, 0, action.Comp.MaxCharges); Dirty(action); } diff --git a/Content.Shared/Climbing/Components/ClimbableComponent.cs b/Content.Shared/Climbing/Components/ClimbableComponent.cs index 1a924e5c30..22a42dea78 100644 --- a/Content.Shared/Climbing/Components/ClimbableComponent.cs +++ b/Content.Shared/Climbing/Components/ClimbableComponent.cs @@ -13,7 +13,13 @@ namespace Content.Shared.Climbing.Components /// /// The range from which this entity can be climbed. /// - [DataField("range")] public float Range = SharedInteractionSystem.InteractionRange / 1.4f; + [DataField] public float Range = SharedInteractionSystem.InteractionRange; + + /// + /// Can drag-drop / verb vaulting be done? Set to false if climbing is being handled manually. + /// + [DataField] + public bool Vaultable = true; /// /// The time it takes to climb onto the entity. diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs index 8e72ddb97d..96427675cb 100644 --- a/Content.Shared/Climbing/Systems/ClimbSystem.cs +++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs @@ -149,7 +149,7 @@ public sealed partial class ClimbSystem : VirtualController private void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args) { - if (args.Handled) + if (args.Handled || !component.Vaultable) return; // If already climbing then don't show outlines. @@ -261,7 +261,7 @@ public sealed partial class ClimbSystem : VirtualController args.Handled = true; } - private void Climb(EntityUid uid, EntityUid user, EntityUid climbable, bool silent = false, ClimbingComponent? climbing = null, + public void Climb(EntityUid uid, EntityUid user, EntityUid climbable, bool silent = false, ClimbingComponent? climbing = null, PhysicsComponent? physics = null, FixturesComponent? fixtures = null, ClimbableComponent? comp = null) { if (!Resolve(uid, ref climbing, ref physics, ref fixtures, false)) @@ -456,6 +456,12 @@ public sealed partial class ClimbSystem : VirtualController /// The reason why it cant be dropped public bool CanVault(ClimbableComponent component, EntityUid user, EntityUid target, out string reason) { + if (!component.Vaultable) + { + reason = string.Empty; + return false; + } + if (!_actionBlockerSystem.CanInteract(user, target)) { reason = Loc.GetString("comp-climbable-cant-interact"); diff --git a/Content.Shared/Configurable/ConfigurationComponent.cs b/Content.Shared/Configurable/ConfigurationComponent.cs index 621871af3c..63c0845083 100644 --- a/Content.Shared/Configurable/ConfigurationComponent.cs +++ b/Content.Shared/Configurable/ConfigurationComponent.cs @@ -2,34 +2,38 @@ using System.Text.RegularExpressions; using Content.Shared.Tools; using Content.Shared.Tools.Systems; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Configurable { - [RegisterComponent, NetworkedComponent] + /// + /// Configuration for mailing units. + /// + /// + /// If you want a more detailed description ask the original coder. + /// + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ConfigurationComponent : Component { - [DataField("config")] + /// + /// Tags for mail unit routing. + /// + [DataField, AutoNetworkedField] public Dictionary Config = new(); - [DataField("qualityNeeded", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string QualityNeeded = SharedToolSystem.PulseQuality; + /// + /// Quality to open up the configuration UI. + /// + [DataField] + public ProtoId QualityNeeded = SharedToolSystem.PulseQuality; - [DataField("validation")] + /// + /// Validate tags in . + /// + [DataField] public Regex Validation = new("^[a-zA-Z0-9 ]*$", RegexOptions.Compiled); - [Serializable, NetSerializable] - public sealed class ConfigurationBoundUserInterfaceState : BoundUserInterfaceState - { - public Dictionary Config { get; } - - public ConfigurationBoundUserInterfaceState(Dictionary config) - { - Config = config; - } - } - /// /// Message data sent from client to server when the device configuration is updated. /// diff --git a/Content.Shared/Configurable/SharedConfigurationSystem.cs b/Content.Shared/Configurable/SharedConfigurationSystem.cs new file mode 100644 index 0000000000..704965188e --- /dev/null +++ b/Content.Shared/Configurable/SharedConfigurationSystem.cs @@ -0,0 +1,77 @@ +using Content.Shared.Interaction; +using Content.Shared.Tools.Systems; +using Robust.Shared.Containers; +using static Content.Shared.Configurable.ConfigurationComponent; + +namespace Content.Shared.Configurable; + +/// +/// +/// +public abstract class SharedConfigurationSystem : EntitySystem +{ + [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; + [Dependency] private readonly SharedToolSystem _toolSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnUpdate); + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnInsert); + } + + private void OnInteractUsing(EntityUid uid, ConfigurationComponent component, InteractUsingEvent args) + { + // TODO use activatable ui system + if (args.Handled) + return; + + if (!_toolSystem.HasQuality(args.Used, component.QualityNeeded)) + return; + + args.Handled = _uiSystem.TryOpenUi(uid, ConfigurationUiKey.Key, args.User); + } + + private void OnUpdate(EntityUid uid, ConfigurationComponent component, ConfigurationUpdatedMessage args) + { + foreach (var key in component.Config.Keys) + { + var value = args.Config.GetValueOrDefault(key); + + if (string.IsNullOrWhiteSpace(value) || component.Validation != null && !component.Validation.IsMatch(value)) + continue; + + component.Config[key] = value; + } + + Dirty(uid, component); + var updatedEvent = new ConfigurationUpdatedEvent(component); + RaiseLocalEvent(uid, updatedEvent); + + // TODO support float (spinbox) and enum (drop-down) configurations + // TODO support verbs. + } + + private void OnInsert(EntityUid uid, ConfigurationComponent component, ContainerIsInsertingAttemptEvent args) + { + if (!_toolSystem.HasQuality(args.EntityUid, component.QualityNeeded)) + return; + + args.Cancel(); + } +} + +/// +/// Sent when configuration values got changes +/// +public sealed class ConfigurationUpdatedEvent : EntityEventArgs +{ + public ConfigurationComponent Configuration; + + public ConfigurationUpdatedEvent(ConfigurationComponent configuration) + { + Configuration = configuration; + } +} diff --git a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs index a291473b30..ec8edea474 100644 --- a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs @@ -277,7 +277,10 @@ public sealed partial class AnchorableSystem : EntitySystem return !attempt.Cancelled; } - private bool TileFree(EntityCoordinates coordinates, PhysicsComponent anchorBody) + /// + /// Returns true if no hard anchored entities exist on the coordinate tile that would collide with the provided physics body. + /// + public bool TileFree(EntityCoordinates coordinates, PhysicsComponent anchorBody) { // Probably ignore CanCollide on the anchoring body? var gridUid = _transformSystem.GetGrid(coordinates); diff --git a/Content.Shared/Containers/SharedThrowInsertContainerSystem.cs b/Content.Shared/Containers/SharedThrowInsertContainerSystem.cs new file mode 100644 index 0000000000..a5c300c284 --- /dev/null +++ b/Content.Shared/Containers/SharedThrowInsertContainerSystem.cs @@ -0,0 +1,8 @@ +namespace Content.Shared.Containers; + +/// +/// Sent before the insertion is made. +/// Allows preventing the insertion if any system on the entity should need to. +/// +[ByRefEvent] +public record struct BeforeThrowInsertEvent(EntityUid ThrownEntity, bool Cancelled = false); diff --git a/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs b/Content.Shared/DeviceNetwork/Components/DeviceNetworkComponent.cs similarity index 93% rename from Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs rename to Content.Shared/DeviceNetwork/Components/DeviceNetworkComponent.cs index 186da57e5d..37a86e7161 100644 --- a/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs +++ b/Content.Shared/DeviceNetwork/Components/DeviceNetworkComponent.cs @@ -1,11 +1,10 @@ -using Content.Server.DeviceNetwork.Systems; -using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Systems; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.DeviceNetwork.Components +namespace Content.Shared.DeviceNetwork.Components { [RegisterComponent] - [Access(typeof(DeviceNetworkSystem), typeof(DeviceNet))] + [Access(typeof(SharedDeviceNetworkSystem), typeof(DeviceNet))] public sealed partial class DeviceNetworkComponent : Component { public enum DeviceNetIdDefaults @@ -113,14 +112,14 @@ namespace Content.Server.DeviceNetwork.Components /// A list of device-lists that this device is on. /// [DataField] - [Access(typeof(DeviceListSystem))] + [Access(typeof(SharedDeviceListSystem))] public HashSet DeviceLists = new(); /// /// A list of configurators that this device is on. /// [DataField] - [Access(typeof(NetworkConfiguratorSystem))] + [Access(typeof(SharedNetworkConfiguratorSystem))] public HashSet Configurators = new(); } } diff --git a/Content.Server/DeviceNetwork/DeviceNet.cs b/Content.Shared/DeviceNetwork/DeviceNet.cs similarity index 97% rename from Content.Server/DeviceNetwork/DeviceNet.cs rename to Content.Shared/DeviceNetwork/DeviceNet.cs index c77d45c061..4234b30385 100644 --- a/Content.Server/DeviceNetwork/DeviceNet.cs +++ b/Content.Shared/DeviceNetwork/DeviceNet.cs @@ -1,8 +1,7 @@ -using Content.Server.DeviceNetwork.Components; using Robust.Shared.Random; -using static Content.Server.DeviceNetwork.Components.DeviceNetworkComponent; +using Content.Shared.DeviceNetwork.Components; -namespace Content.Server.DeviceNetwork; +namespace Content.Shared.DeviceNetwork; /// /// Data class for storing and retrieving information about devices connected to a device network. diff --git a/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs b/Content.Shared/DeviceNetwork/DeviceNetworkConstants.cs similarity index 96% rename from Content.Server/DeviceNetwork/DeviceNetworkConstants.cs rename to Content.Shared/DeviceNetwork/DeviceNetworkConstants.cs index 6cbad603b4..7fec72bb69 100644 --- a/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs +++ b/Content.Shared/DeviceNetwork/DeviceNetworkConstants.cs @@ -1,7 +1,7 @@ -using Content.Server.DeviceNetwork.Components; using Robust.Shared.Utility; +using Content.Shared.DeviceNetwork.Components; -namespace Content.Server.DeviceNetwork +namespace Content.Shared.DeviceNetwork { /// /// A collection of constants to help with using device networks diff --git a/Content.Shared/DeviceNetwork/Events/BeforeBroadcastAttemptEvent.cs b/Content.Shared/DeviceNetwork/Events/BeforeBroadcastAttemptEvent.cs new file mode 100644 index 0000000000..f495847482 --- /dev/null +++ b/Content.Shared/DeviceNetwork/Events/BeforeBroadcastAttemptEvent.cs @@ -0,0 +1,17 @@ +using Content.Shared.DeviceNetwork.Components; + +namespace Content.Shared.DeviceNetwork.Events; + +/// +/// Sent to the sending entity before broadcasting network packets to recipients +/// +public sealed class BeforeBroadcastAttemptEvent : CancellableEntityEventArgs +{ + public readonly IReadOnlySet Recipients; + public HashSet? ModifiedRecipients; + + public BeforeBroadcastAttemptEvent(IReadOnlySet recipients) + { + Recipients = recipients; + } +} diff --git a/Content.Shared/DeviceNetwork/Events/BeforePacketSentEvent.cs b/Content.Shared/DeviceNetwork/Events/BeforePacketSentEvent.cs new file mode 100644 index 0000000000..5d5c038dbf --- /dev/null +++ b/Content.Shared/DeviceNetwork/Events/BeforePacketSentEvent.cs @@ -0,0 +1,35 @@ +using System.Numerics; + +namespace Content.Shared.DeviceNetwork.Events; + +/// +/// Event raised before a device network packet is send. +/// Subscribed to by other systems to prevent the packet from being sent. +/// +public sealed class BeforePacketSentEvent : CancellableEntityEventArgs +{ + /// + /// The EntityUid of the entity the packet was sent from. + /// + public readonly EntityUid Sender; + + public readonly TransformComponent SenderTransform; + + /// + /// The senders current position in world coordinates. + /// + public readonly Vector2 SenderPosition; + + /// + /// The network the packet will be sent to. + /// + public readonly string NetworkId; + + public BeforePacketSentEvent(EntityUid sender, TransformComponent xform, Vector2 senderPosition, string networkId) + { + Sender = sender; + SenderTransform = xform; + SenderPosition = senderPosition; + NetworkId = networkId; + } +} \ No newline at end of file diff --git a/Content.Shared/DeviceNetwork/Events/DeviceNetworkPacketEvent.cs b/Content.Shared/DeviceNetwork/Events/DeviceNetworkPacketEvent.cs new file mode 100644 index 0000000000..4ae6afeef7 --- /dev/null +++ b/Content.Shared/DeviceNetwork/Events/DeviceNetworkPacketEvent.cs @@ -0,0 +1,47 @@ +namespace Content.Shared.DeviceNetwork.Events; + +/// +/// Event raised when a device network packet gets sent. +/// +public sealed class DeviceNetworkPacketEvent : EntityEventArgs +{ + /// + /// The id of the network that this packet is being sent on. + /// + public int NetId; + + /// + /// The frequency the packet is sent on. + /// + public readonly uint Frequency; + + /// + /// Address of the intended recipient. Null if the message was broadcast. + /// + public string? Address; + + /// + /// The device network address of the sending entity. + /// + public readonly string SenderAddress; + + /// + /// The entity that sent the packet. + /// + public EntityUid Sender; + + /// + /// The data that is being sent. + /// + public readonly NetworkPayload Data; + + public DeviceNetworkPacketEvent(int netId, string? address, uint frequency, string senderAddress, EntityUid sender, NetworkPayload data) + { + NetId = netId; + Address = address; + Frequency = frequency; + SenderAddress = senderAddress; + Sender = sender; + Data = data; + } +} \ No newline at end of file diff --git a/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkSystem.cs b/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkSystem.cs new file mode 100644 index 0000000000..5992c40413 --- /dev/null +++ b/Content.Shared/DeviceNetwork/Systems/SharedDeviceNetworkSystem.cs @@ -0,0 +1,25 @@ +using Content.Shared.DeviceNetwork.Components; + +namespace Content.Shared.DeviceNetwork.Systems; + +public abstract class SharedDeviceNetworkSystem : EntitySystem +{ + /// + /// Sends the given payload as a device network packet to the entity with the given address and frequency. + /// Addresses are given to the DeviceNetworkComponent of an entity when connecting. + /// + /// The EntityUid of the sending entity + /// The address of the entity that the packet gets sent to. If null, the message is broadcast to all devices on that frequency (except the sender) + /// The frequency to send on + /// The data to be sent + /// Returns true when the packet was successfully enqueued. + public virtual bool QueuePacket(EntityUid uid, + string? address, + NetworkPayload data, + uint? frequency = null, + int? network = null, + DeviceNetworkComponent? device = null) + { + return false; + } +} diff --git a/Content.Server/Disposal/Mailing/MailingUnitComponent.cs b/Content.Shared/Disposal/Mailing/MailingUnitComponent.cs similarity index 57% rename from Content.Server/Disposal/Mailing/MailingUnitComponent.cs rename to Content.Shared/Disposal/Mailing/MailingUnitComponent.cs index be5eca99c4..255d6cdf01 100644 --- a/Content.Server/Disposal/Mailing/MailingUnitComponent.cs +++ b/Content.Shared/Disposal/Mailing/MailingUnitComponent.cs @@ -1,30 +1,28 @@ -using Content.Shared.Disposal.Components; +using Content.Shared.Disposal.Mailing; +using Robust.Shared.GameStates; -namespace Content.Server.Disposal.Mailing; +namespace Content.Shared.Disposal.Components; -[Access(typeof(MailingUnitSystem))] -[RegisterComponent] +[Access(typeof(SharedMailingUnitSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class MailingUnitComponent : Component { /// /// List of targets the mailing unit can send to. /// Each target is just a disposal routing tag /// - [DataField("targetList")] + [DataField, AutoNetworkedField] public List TargetList = new(); /// /// The target that gets attached to the disposal holders tag list on flush /// - [DataField("target")] + [DataField, AutoNetworkedField] public string? Target; /// /// The tag for this mailing unit /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("tag")] + [DataField, AutoNetworkedField] public string? Tag; - - public SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState? DisposalUnitInterfaceState; } diff --git a/Content.Shared/Disposal/MailingUnitUiMessages.cs b/Content.Shared/Disposal/Mailing/MailingUnitUiMessages.cs similarity index 100% rename from Content.Shared/Disposal/MailingUnitUiMessages.cs rename to Content.Shared/Disposal/Mailing/MailingUnitUiMessages.cs diff --git a/Content.Shared/Disposal/Components/SharedDisposalRouterComponent.cs b/Content.Shared/Disposal/Mailing/SharedDisposalRouterComponent.cs similarity index 100% rename from Content.Shared/Disposal/Components/SharedDisposalRouterComponent.cs rename to Content.Shared/Disposal/Mailing/SharedDisposalRouterComponent.cs diff --git a/Content.Shared/Disposal/Components/SharedDisposalTaggerComponent.cs b/Content.Shared/Disposal/Mailing/SharedDisposalTaggerComponent.cs similarity index 100% rename from Content.Shared/Disposal/Components/SharedDisposalTaggerComponent.cs rename to Content.Shared/Disposal/Mailing/SharedDisposalTaggerComponent.cs diff --git a/Content.Shared/Disposal/Mailing/SharedMailingUnitSystem.cs b/Content.Shared/Disposal/Mailing/SharedMailingUnitSystem.cs new file mode 100644 index 0000000000..cb7a8c46c8 --- /dev/null +++ b/Content.Shared/Disposal/Mailing/SharedMailingUnitSystem.cs @@ -0,0 +1,174 @@ +using Content.Shared.Configurable; +using Content.Shared.DeviceNetwork; +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.DeviceNetwork.Events; +using Content.Shared.DeviceNetwork.Systems; +using Content.Shared.Disposal.Components; +using Content.Shared.Disposal.Unit; +using Content.Shared.Disposal.Unit.Events; +using Content.Shared.Interaction; +using Content.Shared.Power.EntitySystems; +using Robust.Shared.Player; + +namespace Content.Shared.Disposal.Mailing; + +public abstract class SharedMailingUnitSystem : EntitySystem +{ + [Dependency] private readonly SharedDeviceNetworkSystem _deviceNetworkSystem = default!; + [Dependency] private readonly SharedPowerReceiverSystem _power = default!; + [Dependency] protected readonly SharedUserInterfaceSystem UserInterfaceSystem = default!; + + private const string MailTag = "mail"; + + private const string TagConfigurationKey = "tag"; + + private const string NetTag = "tag"; + private const string NetSrc = "src"; + private const string NetTarget = "target"; + private const string NetCmdSent = "mail_sent"; + private const string NetCmdRequest = "get_mailer_tag"; + private const string NetCmdResponse = "mailer_tag"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnPacketReceived); + SubscribeLocalEvent(OnBeforeFlush); + SubscribeLocalEvent(OnConfigurationUpdated); + SubscribeLocalEvent(HandleActivate, before: new[] { typeof(SharedDisposalUnitSystem) }); + SubscribeLocalEvent(OnTargetSelected); + } + + private void OnComponentInit(EntityUid uid, MailingUnitComponent component, ComponentInit args) + { + UpdateTargetList(uid, component); + } + + private void OnPacketReceived(EntityUid uid, MailingUnitComponent component, DeviceNetworkPacketEvent args) + { + if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command) || !_power.IsPowered(uid)) + return; + + switch (command) + { + case NetCmdRequest: + SendTagRequestResponse(uid, args, component.Tag); + break; + case NetCmdResponse when args.Data.TryGetValue(NetTag, out string? tag): + //Add the received tag request response to the list of targets + component.TargetList.Add(tag); + Dirty(uid, component); + break; + } + } + + /// + /// Sends the given tag as a response to a if it's not null + /// + private void SendTagRequestResponse(EntityUid uid, DeviceNetworkPacketEvent args, string? tag) + { + if (tag == null) + return; + + var payload = new NetworkPayload + { + [DeviceNetworkConstants.Command] = NetCmdResponse, + [NetTag] = tag + }; + + _deviceNetworkSystem.QueuePacket(uid, args.Address, payload, args.Frequency); + } + + /// + /// Prevents the unit from flushing if no target is selected + /// + private void OnBeforeFlush(EntityUid uid, MailingUnitComponent component, BeforeDisposalFlushEvent args) + { + if (string.IsNullOrEmpty(component.Target)) + { + args.Cancel(); + return; + } + + Dirty(uid, component); + args.Tags.Add(MailTag); + args.Tags.Add(component.Target); + + BroadcastSentMessage(uid, component); + } + + /// + /// Broadcast that a mail was sent including the src and target tags + /// + private void BroadcastSentMessage(EntityUid uid, MailingUnitComponent component, DeviceNetworkComponent? device = null) + { + if (string.IsNullOrEmpty(component.Tag) || string.IsNullOrEmpty(component.Target) || !Resolve(uid, ref device)) + return; + + var payload = new NetworkPayload + { + [DeviceNetworkConstants.Command] = NetCmdSent, + [NetSrc] = component.Tag, + [NetTarget] = component.Target + }; + + _deviceNetworkSystem.QueuePacket(uid, null, payload, null, null, device); + } + + /// + /// Clears the units target list and broadcasts a . + /// The target list will then get populated with responses from all active mailing units on the same grid + /// + private void UpdateTargetList(EntityUid uid, MailingUnitComponent component, DeviceNetworkComponent? device = null) + { + if (!Resolve(uid, ref device, false)) + return; + + var payload = new NetworkPayload + { + [DeviceNetworkConstants.Command] = NetCmdRequest + }; + + component.TargetList.Clear(); + _deviceNetworkSystem.QueuePacket(uid, null, payload, null, null, device); + } + + /// + /// Gets called when the units tag got updated + /// + private void OnConfigurationUpdated(EntityUid uid, MailingUnitComponent component, ConfigurationUpdatedEvent args) + { + var configuration = args.Configuration.Config; + if (!configuration.ContainsKey(TagConfigurationKey) || configuration[TagConfigurationKey] == string.Empty) + { + component.Tag = null; + return; + } + + component.Tag = configuration[TagConfigurationKey]; + Dirty(uid, component); + } + + private void HandleActivate(EntityUid uid, MailingUnitComponent component, ActivateInWorldEvent args) + { + if (args.Handled || !args.Complex) + return; + + if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor)) + { + return; + } + + args.Handled = true; + UpdateTargetList(uid, component); + UserInterfaceSystem.OpenUi(uid, MailingUnitUiKey.Key, actor.PlayerSession); + } + + private void OnTargetSelected(EntityUid uid, MailingUnitComponent component, TargetSelectedMessage args) + { + component.Target = args.Target; + Dirty(uid, component); + } +} diff --git a/Content.Shared/Disposal/MailingUnitBoundUserInterfaceState.cs b/Content.Shared/Disposal/MailingUnitBoundUserInterfaceState.cs deleted file mode 100644 index 65be092072..0000000000 --- a/Content.Shared/Disposal/MailingUnitBoundUserInterfaceState.cs +++ /dev/null @@ -1,45 +0,0 @@ -using Content.Shared.Disposal.Components; -using Robust.Shared.Serialization; - -namespace Content.Shared.Disposal; - -[Serializable, NetSerializable] -public sealed class MailingUnitBoundUserInterfaceState : BoundUserInterfaceState, IEquatable -{ - public string? Target; - public List TargetList; - public string? Tag; - public SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState DisposalState; - - public MailingUnitBoundUserInterfaceState(SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState disposalState, string? target, List targetList, string? tag) - { - DisposalState = disposalState; - Target = target; - TargetList = targetList; - Tag = tag; - } - - public bool Equals(MailingUnitBoundUserInterfaceState? other) - { - if (other is null) - return false; - if (ReferenceEquals(this, other)) - return true; - return DisposalState.Equals(other.DisposalState) - && Target == other.Target - && TargetList.Equals(other.TargetList) - && Tag == other.Tag; - } - - public override bool Equals(object? other) - { - if (other is MailingUnitBoundUserInterfaceState otherState) - return Equals(otherState); - return false; - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } -} diff --git a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs b/Content.Shared/Disposal/SharedDisposalUnitSystem.cs deleted file mode 100644 index a650ef72f8..0000000000 --- a/Content.Shared/Disposal/SharedDisposalUnitSystem.cs +++ /dev/null @@ -1,162 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Shared.Body.Components; -using Content.Shared.Disposal.Components; -using Content.Shared.DoAfter; -using Content.Shared.DragDrop; -using Content.Shared.Emag.Systems; -using Content.Shared.Item; -using Content.Shared.Throwing; -using Content.Shared.Whitelist; -using Robust.Shared.Audio; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Events; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Serialization; -using Robust.Shared.Timing; - -namespace Content.Shared.Disposal; - -[Serializable, NetSerializable] -public sealed partial class DisposalDoAfterEvent : SimpleDoAfterEvent -{ -} - -public abstract class SharedDisposalUnitSystem : EntitySystem -{ - [Dependency] protected readonly IGameTiming GameTiming = default!; - [Dependency] protected readonly EmagSystem _emag = default!; - [Dependency] protected readonly MetaDataSystem Metadata = default!; - [Dependency] protected readonly SharedJointSystem Joints = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; - - protected static TimeSpan ExitAttemptDelay = TimeSpan.FromSeconds(0.5); - - // Percentage - public const float PressurePerSecond = 0.05f; - - public abstract bool HasDisposals([NotNullWhen(true)] EntityUid? uid); - - public abstract bool ResolveDisposals(EntityUid uid, [NotNullWhen(true)] ref SharedDisposalUnitComponent? component); - - /// - /// Gets the current pressure state of a disposals unit. - /// - /// - /// - /// - /// - public DisposalsPressureState GetState(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent? metadata = null) - { - var nextPressure = Metadata.GetPauseTime(uid, metadata) + component.NextPressurized - GameTiming.CurTime; - var pressurizeTime = 1f / PressurePerSecond; - var pressurizeDuration = pressurizeTime - component.FlushDelay.TotalSeconds; - - if (nextPressure.TotalSeconds > pressurizeDuration) - { - return DisposalsPressureState.Flushed; - } - - if (nextPressure > TimeSpan.Zero) - { - return DisposalsPressureState.Pressurizing; - } - - return DisposalsPressureState.Ready; - } - - public float GetPressure(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent? metadata = null) - { - if (!Resolve(uid, ref metadata)) - return 0f; - - var pauseTime = Metadata.GetPauseTime(uid, metadata); - return MathF.Min(1f, - (float) (GameTiming.CurTime - pauseTime - component.NextPressurized).TotalSeconds / PressurePerSecond); - } - - protected void OnPreventCollide(EntityUid uid, SharedDisposalUnitComponent component, - ref PreventCollideEvent args) - { - var otherBody = args.OtherEntity; - - // Items dropped shouldn't collide but items thrown should - if (HasComp(otherBody) && !HasComp(otherBody)) - { - args.Cancelled = true; - return; - } - - if (component.RecentlyEjected.Contains(otherBody)) - { - args.Cancelled = true; - } - } - - protected void OnCanDragDropOn(EntityUid uid, SharedDisposalUnitComponent component, ref CanDropTargetEvent args) - { - if (args.Handled) - return; - - args.CanDrop = CanInsert(uid, component, args.Dragged); - args.Handled = true; - } - - protected void OnEmagged(EntityUid uid, SharedDisposalUnitComponent component, ref GotEmaggedEvent args) - { - if (!_emag.CompareFlag(args.Type, EmagType.Interaction)) - return; - - if (component.DisablePressure == true) - return; - - component.DisablePressure = true; - args.Handled = true; - } - - public virtual bool CanInsert(EntityUid uid, SharedDisposalUnitComponent component, EntityUid entity) - { - if (!Transform(uid).Anchored) - return false; - - var storable = HasComp(entity); - if (!storable && !HasComp(entity)) - return false; - - if (_whitelistSystem.IsBlacklistPass(component.Blacklist, entity) || - _whitelistSystem.IsWhitelistFail(component.Whitelist, entity)) - return false; - - if (TryComp(entity, out var physics) && (physics.CanCollide) || storable) - return true; - else - return false; - - } - - public abstract void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null); - - [Serializable, NetSerializable] - protected sealed class DisposalUnitComponentState : ComponentState - { - public SoundSpecifier? FlushSound; - public DisposalsPressureState State; - public TimeSpan NextPressurized; - public TimeSpan AutomaticEngageTime; - public TimeSpan? NextFlush; - public bool Powered; - public bool Engaged; - public List RecentlyEjected; - - public DisposalUnitComponentState(SoundSpecifier? flushSound, DisposalsPressureState state, TimeSpan nextPressurized, TimeSpan automaticEngageTime, TimeSpan? nextFlush, bool powered, bool engaged, List recentlyEjected) - { - FlushSound = flushSound; - State = state; - NextPressurized = nextPressurized; - AutomaticEngageTime = automaticEngageTime; - NextFlush = nextFlush; - Powered = powered; - Engaged = engaged; - RecentlyEjected = recentlyEjected; - } - } -} diff --git a/Content.Shared/Disposal/Tube/DisposalEntryComponent.cs b/Content.Shared/Disposal/Tube/DisposalEntryComponent.cs new file mode 100644 index 0000000000..066b16ad1f --- /dev/null +++ b/Content.Shared/Disposal/Tube/DisposalEntryComponent.cs @@ -0,0 +1,12 @@ +using Content.Shared.Disposal.Unit; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Disposal.Tube; + +[RegisterComponent] +[Access(typeof(SharedDisposalTubeSystem), typeof(SharedDisposalUnitSystem))] +public sealed partial class DisposalEntryComponent : Component +{ + [DataField] + public EntProtoId HolderPrototypeId = "DisposalHolder"; +} diff --git a/Content.Shared/Disposal/Components/SharedDisposalTubeComponent.cs b/Content.Shared/Disposal/Tube/SharedDisposalTubeComponent.cs similarity index 100% rename from Content.Shared/Disposal/Components/SharedDisposalTubeComponent.cs rename to Content.Shared/Disposal/Tube/SharedDisposalTubeComponent.cs diff --git a/Content.Shared/Disposal/Unit/BeforeDisposalFlushEvent.cs b/Content.Shared/Disposal/Unit/BeforeDisposalFlushEvent.cs new file mode 100644 index 0000000000..ee141d6c4d --- /dev/null +++ b/Content.Shared/Disposal/Unit/BeforeDisposalFlushEvent.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Disposal.Unit.Events; + +/// +/// Sent before the disposal unit flushes it's contents. +/// Allows adding tags for sorting and preventing the disposal unit from flushing. +/// +public sealed class BeforeDisposalFlushEvent : CancellableEntityEventArgs +{ + public readonly List Tags = new(); +} \ No newline at end of file diff --git a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs b/Content.Shared/Disposal/Unit/DisposalUnitComponent.cs similarity index 68% rename from Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs rename to Content.Shared/Disposal/Unit/DisposalUnitComponent.cs index 36dd14f9b2..34fe223013 100644 --- a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs +++ b/Content.Shared/Disposal/Unit/DisposalUnitComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Atmos; using Robust.Shared.Audio; using Content.Shared.Whitelist; using Robust.Shared.Containers; @@ -7,15 +8,24 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Disposal.Components; -[NetworkedComponent] -public abstract partial class SharedDisposalUnitComponent : Component +/// +/// Takes in entities and flushes them out to attached disposals tubes after a timer. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class DisposalUnitComponent : Component { public const string ContainerId = "disposals"; + /// + /// Air contained in the disposal unit. + /// + [DataField] + public GasMixture Air = new(Atmospherics.CellVolume); + /// /// Sounds played upon the unit flushing. /// - [ViewVariables(VVAccess.ReadWrite), DataField("soundFlush")] + [DataField("soundFlush"), AutoNetworkedField] public SoundSpecifier? FlushSound = new SoundPathSpecifier("/Audio/Machines/disposalflush.ogg"); /// @@ -39,20 +49,13 @@ public abstract partial class SharedDisposalUnitComponent : Component /// /// State for this disposals unit. /// - [DataField] + [DataField, AutoNetworkedField] public DisposalsPressureState State; - // TODO: Just make this use vaulting. - /// - /// We'll track whatever just left disposals so we know what collision we need to ignore until they stop intersecting our BB. - /// - [ViewVariables, DataField] - public List RecentlyEjected = new(); - /// /// Next time the disposal unit will be pressurized. /// - [DataField(customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] public TimeSpan NextPressurized = TimeSpan.Zero; /// @@ -70,26 +73,24 @@ public abstract partial class SharedDisposalUnitComponent : Component /// /// Removes the pressure requirement for flushing. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public bool DisablePressure; /// /// Last time that an entity tried to exit this disposal unit. /// - [ViewVariables] + [DataField, AutoNetworkedField] public TimeSpan LastExitAttempt; [DataField] public bool AutomaticEngage = true; - [ViewVariables(VVAccess.ReadWrite)] - [DataField] + [DataField, AutoNetworkedField] public TimeSpan AutomaticEngageTime = TimeSpan.FromSeconds(30); /// /// Delay from trying to enter disposals ourselves. /// - [ViewVariables(VVAccess.ReadWrite)] [DataField] public float EntryDelay = 0.5f; @@ -104,20 +105,16 @@ public abstract partial class SharedDisposalUnitComponent : Component /// [ViewVariables] public Container Container = default!; - // TODO: Network power shit instead fam. - [ViewVariables, DataField] - public bool Powered; - /// /// Was the disposals unit engaged for a manual flush. /// - [ViewVariables(VVAccess.ReadWrite), DataField] + [DataField, AutoNetworkedField] public bool Engaged; /// /// Next time this unit will flush. Is the lesser of and /// - [ViewVariables, DataField(customTypeSerializer:typeof(TimeOffsetSerializer))] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] public TimeSpan? NextFlush; [Serializable, NetSerializable] @@ -162,37 +159,6 @@ public abstract partial class SharedDisposalUnitComponent : Component Power } - [Serializable, NetSerializable] - public sealed class DisposalUnitBoundUserInterfaceState : BoundUserInterfaceState, IEquatable - { - public readonly string UnitName; - public readonly string UnitState; - public readonly TimeSpan FullPressureTime; - public readonly bool Powered; - public readonly bool Engaged; - - public DisposalUnitBoundUserInterfaceState(string unitName, string unitState, TimeSpan fullPressureTime, bool powered, - bool engaged) - { - UnitName = unitName; - UnitState = unitState; - FullPressureTime = fullPressureTime; - Powered = powered; - Engaged = engaged; - } - - public bool Equals(DisposalUnitBoundUserInterfaceState? other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return UnitName == other.UnitName && - UnitState == other.UnitState && - Powered == other.Powered && - Engaged == other.Engaged && - FullPressureTime.Equals(other.FullPressureTime); - } - } - /// /// Message data sent from client to server when a disposal unit ui button is pressed. /// diff --git a/Content.Shared/Disposal/Unit/SharedDisposalTubeSystem.cs b/Content.Shared/Disposal/Unit/SharedDisposalTubeSystem.cs new file mode 100644 index 0000000000..58d4da7eba --- /dev/null +++ b/Content.Shared/Disposal/Unit/SharedDisposalTubeSystem.cs @@ -0,0 +1,14 @@ +using Content.Shared.Disposal.Components; + +namespace Content.Shared.Disposal.Unit; + +public abstract class SharedDisposalTubeSystem : EntitySystem +{ + public virtual bool TryInsert(EntityUid uid, + DisposalUnitComponent from, + IEnumerable? tags = default, + Tube.DisposalEntryComponent? entry = null) + { + return false; + } +} diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Shared/Disposal/Unit/SharedDisposalUnitSystem.cs similarity index 53% rename from Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs rename to Content.Shared/Disposal/Unit/SharedDisposalUnitSystem.cs index 136ac2c440..1db24c700d 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs +++ b/Content.Shared/Disposal/Unit/SharedDisposalUnitSystem.cs @@ -1,24 +1,15 @@ -using System.Diagnostics.CodeAnalysis; using System.Linq; -using Content.Server.Administration.Logs; -using Content.Server.Atmos.EntitySystems; -using Content.Server.Containers; -using Content.Server.Disposal.Tube; -using Content.Server.Disposal.Tube.Components; -using Content.Server.Disposal.Unit.Components; -using Content.Server.Popups; -using Content.Server.Power.Components; -using Content.Server.Power.EntitySystems; using Content.Shared.ActionBlocker; -using Content.Shared.Atmos; +using Content.Shared.Administration.Logs; +using Content.Shared.Body.Components; +using Content.Shared.Climbing.Systems; +using Content.Shared.Containers; using Content.Shared.Database; -using Content.Shared.Destructible; -using Content.Shared.Disposal; using Content.Shared.Disposal.Components; +using Content.Shared.Disposal.Unit.Events; using Content.Shared.DoAfter; using Content.Shared.DragDrop; using Content.Shared.Emag.Systems; -using Content.Shared.Explosion; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.IdentityManagement; @@ -27,59 +18,59 @@ using Content.Shared.Item; using Content.Shared.Movement.Events; using Content.Shared.Popups; using Content.Shared.Power; +using Content.Shared.Power.EntitySystems; +using Content.Shared.Throwing; using Content.Shared.Verbs; -using Robust.Server.Audio; -using Robust.Server.GameObjects; +using Content.Shared.Whitelist; +using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; -using Robust.Shared.Player; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; using Robust.Shared.Utility; -namespace Content.Server.Disposal.Unit.EntitySystems; +namespace Content.Shared.Disposal.Unit; -public sealed class DisposalUnitSystem : SharedDisposalUnitSystem +[Serializable, NetSerializable] +public sealed partial class DisposalDoAfterEvent : SimpleDoAfterEvent { - [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; - [Dependency] private readonly AppearanceSystem _appearance = default!; - [Dependency] private readonly AtmosphereSystem _atmosSystem = default!; - [Dependency] private readonly AudioSystem _audioSystem = default!; - [Dependency] private readonly DisposalTubeSystem _disposalTubeSystem = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly PowerReceiverSystem _power = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; - [Dependency] private readonly UserInterfaceSystem _ui = default!; - [Dependency] private readonly SharedMapSystem _map = default!; +} + +public abstract class SharedDisposalUnitSystem : EntitySystem +{ + [Dependency] protected readonly ActionBlockerSystem ActionBlockerSystem = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + [Dependency] protected readonly MetaDataSystem Metadata = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] protected readonly SharedAudioSystem Audio = default!; + [Dependency] protected readonly IGameTiming GameTiming = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; + [Dependency] private readonly ClimbSystem _climb = default!; + [Dependency] protected readonly SharedContainerSystem Containers = default!; + [Dependency] protected readonly SharedJointSystem Joints = default!; + [Dependency] private readonly SharedPowerReceiverSystem _power = default!; + [Dependency] private readonly SharedDisposalTubeSystem _disposalTubeSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; + [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; + [Dependency] private readonly SharedMapSystem _map = default!; + + protected static TimeSpan ExitAttemptDelay = TimeSpan.FromSeconds(0.5); + + // Percentage + public const float PressurePerSecond = 0.05f; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGetState); SubscribeLocalEvent(OnPreventCollide); SubscribeLocalEvent(OnCanDragDropOn); - SubscribeLocalEvent(OnEmagged); - - // Shouldn't need re-anchoring. - SubscribeLocalEvent(OnAnchorChanged); - // TODO: Predict me when hands predicted - SubscribeLocalEvent(OnMovement); - SubscribeLocalEvent(OnPowerChange); - SubscribeLocalEvent(OnDisposalInit); - - SubscribeLocalEvent(OnActivate); - SubscribeLocalEvent(OnAfterInteractUsing); - SubscribeLocalEvent(OnDragDropOn); - SubscribeLocalEvent(OnDestruction); - SubscribeLocalEvent(OnExploded); - SubscribeLocalEvent>(AddInsertVerb); SubscribeLocalEvent>(AddDisposalAltVerbs); SubscribeLocalEvent>(AddClimbInsideVerb); @@ -88,27 +79,27 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem SubscribeLocalEvent(OnThrowInsert); - SubscribeLocalEvent(OnUiButtonPressed); + SubscribeLocalEvent(OnUiButtonPressed); + + SubscribeLocalEvent(OnEmagged); + SubscribeLocalEvent(OnAnchorChanged); + SubscribeLocalEvent(OnPowerChange); + SubscribeLocalEvent(OnDisposalInit); + + SubscribeLocalEvent(OnActivate); + SubscribeLocalEvent(OnAfterInteractUsing); + SubscribeLocalEvent(OnDragDropOn); + SubscribeLocalEvent(OnMovement); } - private void OnGetState(EntityUid uid, DisposalUnitComponent component, ref ComponentGetState args) - { - args.State = new DisposalUnitComponentState( - component.FlushSound, - component.State, - component.NextPressurized, - component.AutomaticEngageTime, - component.NextFlush, - component.Powered, - component.Engaged, - GetNetEntityList(component.RecentlyEjected)); - } - - private void AddDisposalAltVerbs(EntityUid uid, SharedDisposalUnitComponent component, GetVerbsEvent args) + private void AddDisposalAltVerbs(Entity ent, ref GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract) return; + var uid = ent.Owner; + var component = ent.Comp; + // Behavior for if the disposals bin has items in it if (component.Container.ContainedEntities.Count > 0) { @@ -133,41 +124,12 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem } } - private void AddClimbInsideVerb(EntityUid uid, SharedDisposalUnitComponent component, GetVerbsEvent args) - { - // This is not an interaction, activation, or alternative verb type because unfortunately most users are - // unwilling to accept that this is where they belong and don't want to accidentally climb inside. - if (!args.CanAccess || - !args.CanInteract || - component.Container.ContainedEntities.Contains(args.User) || - !_actionBlockerSystem.CanMove(args.User)) - { - return; - } - - if (!CanInsert(uid, component, args.User)) - return; - - // Add verb to climb inside of the unit, - Verb verb = new() - { - Act = () => TryInsert(uid, args.User, args.User), - DoContactInteraction = true, - Text = Loc.GetString("disposal-self-insert-verb-get-data-text") - }; - // TODO VERB ICON - // TODO VERB CATEGORY - // create a verb category for "enter"? - // See also, medical scanner. Also maybe add verbs for entering lockers/body bags? - args.Verbs.Add(verb); - } - - private void AddInsertVerb(EntityUid uid, SharedDisposalUnitComponent component, GetVerbsEvent args) + private void AddInsertVerb(EntityUid uid, DisposalUnitComponent component, GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract || args.Hands == null || args.Using == null) return; - if (!_actionBlockerSystem.CanDrop(args.User)) + if (!ActionBlockerSystem.CanDrop(args.User)) return; if (!CanInsert(uid, component, args.Using.Value)) @@ -180,7 +142,7 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem Act = () => { _handsSystem.TryDropIntoContainer(args.User, args.Using.Value, component.Container, checkActionBlocker: false, args.Hands); - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} inserted {ToPrettyString(args.Using.Value)} into {ToPrettyString(uid)}"); + _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} inserted {ToPrettyString(args.Using.Value)} into {ToPrettyString(uid)}"); AfterInsert(uid, component, args.Using.Value, args.User); } }; @@ -188,7 +150,7 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem args.Verbs.Add(insertVerb); } - private void OnDoAfter(EntityUid uid, SharedDisposalUnitComponent component, DoAfterEvent args) + private void OnDoAfter(EntityUid uid, DisposalUnitComponent component, DoAfterEvent args) { if (args.Handled || args.Cancelled || args.Args.Target == null || args.Args.Used == null) return; @@ -204,89 +166,46 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem args.Cancelled = true; } - public override void DoInsertDisposalUnit(EntityUid uid, EntityUid toInsert, EntityUid user, SharedDisposalUnitComponent? disposal = null) - { - if (!ResolveDisposals(uid, ref disposal)) - return; - - if (!_containerSystem.Insert(toInsert, disposal.Container)) - return; - - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user):player} inserted {ToPrettyString(toInsert)} into {ToPrettyString(uid)}"); - AfterInsert(uid, disposal, toInsert, user); - } - public override void Update(float frameTime) { base.Update(frameTime); - var query = AllEntityQuery(); + var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var unit, out var metadata)) { - if (!metadata.EntityPaused) - Update(uid, unit, metadata, frameTime); + Update(uid, unit, metadata); } } - #region UI Handlers - private void OnUiButtonPressed(EntityUid uid, SharedDisposalUnitComponent component, SharedDisposalUnitComponent.UiButtonPressedMessage args) + // TODO: This should just use the same thing as entity storage? + private void OnMovement(EntityUid uid, DisposalUnitComponent component, ref ContainerRelayMovementEntityEvent args) { - if (args.Actor is not { Valid: true } player) - { + var currentTime = GameTiming.CurTime; + + if (!ActionBlockerSystem.CanMove(args.Entity)) return; - } - switch (args.Button) - { - case SharedDisposalUnitComponent.UiButton.Eject: - TryEjectContents(uid, component); - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} hit eject button on {ToPrettyString(uid)}"); - break; - case SharedDisposalUnitComponent.UiButton.Engage: - ToggleEngage(uid, component); - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} hit flush button on {ToPrettyString(uid)}, it's now {(component.Engaged ? "on" : "off")}"); - break; - case SharedDisposalUnitComponent.UiButton.Power: - _power.TogglePower(uid, user: args.Actor); - break; - default: - throw new ArgumentOutOfRangeException($"{ToPrettyString(player):player} attempted to hit a nonexistant button on {ToPrettyString(uid)}"); - } + if (!TryComp(args.Entity, out HandsComponent? hands) || + hands.Count == 0 || + currentTime < component.LastExitAttempt + ExitAttemptDelay) + return; + + Dirty(uid, component); + component.LastExitAttempt = currentTime; + Remove(uid, component, args.Entity); + UpdateUI((uid, component)); } - public void ToggleEngage(EntityUid uid, SharedDisposalUnitComponent component) - { - component.Engaged ^= true; - - if (component.Engaged) - { - ManualEngage(uid, component); - } - else - { - Disengage(uid, component); - } - } - - #endregion - - #region Eventbus Handlers - - private void OnActivate(EntityUid uid, SharedDisposalUnitComponent component, ActivateInWorldEvent args) + private void OnActivate(EntityUid uid, DisposalUnitComponent component, ActivateInWorldEvent args) { if (args.Handled || !args.Complex) return; - if (!TryComp(args.User, out ActorComponent? actor)) - { - return; - } - args.Handled = true; - _ui.OpenUi(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, actor.PlayerSession); + _ui.TryToggleUi(uid, DisposalUnitComponent.DisposalUnitUiKey.Key, args.User); } - private void OnAfterInteractUsing(EntityUid uid, SharedDisposalUnitComponent component, AfterInteractUsingEvent args) + private void OnAfterInteractUsing(EntityUid uid, DisposalUnitComponent component, AfterInteractUsingEvent args) { if (args.Handled || !args.CanReach) return; @@ -301,26 +220,23 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem return; } - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} inserted {ToPrettyString(args.Used)} into {ToPrettyString(uid)}"); + _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(args.User):player} inserted {ToPrettyString(args.Used)} into {ToPrettyString(uid)}"); AfterInsert(uid, component, args.Used, args.User); args.Handled = true; } - private void OnDisposalInit(EntityUid uid, SharedDisposalUnitComponent component, ComponentInit args) + protected virtual void OnDisposalInit(Entity ent, ref ComponentInit args) { - component.Container = _containerSystem.EnsureContainer(uid, SharedDisposalUnitComponent.ContainerId); - - UpdateInterface(uid, component, component.Powered); + ent.Comp.Container = Containers.EnsureContainer(ent, DisposalUnitComponent.ContainerId); } - private void OnPowerChange(EntityUid uid, SharedDisposalUnitComponent component, ref PowerChangedEvent args) + private void OnPowerChange(EntityUid uid, DisposalUnitComponent component, ref PowerChangedEvent args) { - if (!component.Running || args.Powered == component.Powered) + if (!component.Running) return; - component.Powered = args.Powered; + UpdateUI((uid, component)); UpdateVisualState(uid, component); - UpdateInterface(uid, component, args.Powered); if (!args.Powered) { @@ -336,24 +252,7 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem } } - // TODO: This should just use the same thing as entity storage? - private void OnMovement(EntityUid uid, SharedDisposalUnitComponent component, ref ContainerRelayMovementEntityEvent args) - { - var currentTime = GameTiming.CurTime; - - if (!_actionBlockerSystem.CanMove(args.Entity)) - return; - - if (!TryComp(args.Entity, out HandsComponent? hands) || - hands.Count == 0 || - currentTime < component.LastExitAttempt + ExitAttemptDelay) - return; - - component.LastExitAttempt = currentTime; - Remove(uid, component, args.Entity); - } - - private void OnAnchorChanged(EntityUid uid, SharedDisposalUnitComponent component, ref AnchorStateChangedEvent args) + private void OnAnchorChanged(EntityUid uid, DisposalUnitComponent component, ref AnchorStateChangedEvent args) { if (Terminating(uid)) return; @@ -363,108 +262,238 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem TryEjectContents(uid, component); } - private void OnDestruction(EntityUid uid, SharedDisposalUnitComponent component, DestructionEventArgs args) - { - TryEjectContents(uid, component); - } - - private void OnDragDropOn(EntityUid uid, SharedDisposalUnitComponent component, ref DragDropTargetEvent args) + private void OnDragDropOn(EntityUid uid, DisposalUnitComponent component, ref DragDropTargetEvent args) { args.Handled = TryInsert(uid, args.Dragged, args.User); } - #endregion - - private void UpdateState(EntityUid uid, DisposalsPressureState state, SharedDisposalUnitComponent component, MetaDataComponent metadata) + protected virtual void UpdateUI(Entity entity) { - if (component.State == state) - return; - component.State = state; - UpdateVisualState(uid, component); - UpdateInterface(uid, component, component.Powered); - Dirty(uid, component, metadata); - - if (state == DisposalsPressureState.Ready) - { - component.NextPressurized = TimeSpan.Zero; - - // Manually engaged - if (component.Engaged) - { - component.NextFlush = GameTiming.CurTime + component.ManualFlushTime; - } - else if (component.Container.ContainedEntities.Count > 0) - { - component.NextFlush = GameTiming.CurTime + component.AutomaticEngageTime; - } - else - { - component.NextFlush = null; - } - } } /// - /// Work out if we can stop updating this disposals component i.e. full pressure and nothing colliding. + /// Returns the estimated time when the disposal unit will be back to full pressure. /// - private void Update(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent metadata, float frameTime) + public TimeSpan EstimatedFullPressure(EntityUid uid, DisposalUnitComponent component) { - var state = GetState(uid, component, metadata); + if (component.NextPressurized < GameTiming.CurTime) + return TimeSpan.Zero; - // Pressurizing, just check if we need a state update. - if (component.NextPressurized > GameTiming.CurTime) + return component.NextPressurized; + } + + public bool CanFlush(EntityUid unit, DisposalUnitComponent component) + { + return GetState(unit, component) == DisposalsPressureState.Ready + && _power.IsPowered(unit) + && Comp(unit).Anchored; + } + + public void Remove(EntityUid uid, DisposalUnitComponent component, EntityUid toRemove) + { + if (GameTiming.ApplyingState) + return; + + if (!Containers.Remove(toRemove, component.Container)) + return; + + if (component.Container.ContainedEntities.Count == 0) + { + // If not manually engaged then reset the flushing entirely. + if (!component.Engaged) + { + component.NextFlush = null; + Dirty(uid, component); + UpdateUI((uid, component)); + } + } + + _climb.Climb(toRemove, toRemove, uid, silent: true); + + UpdateVisualState(uid, component); + } + + public void UpdateVisualState(EntityUid uid, DisposalUnitComponent component, bool flush = false) + { + if (!TryComp(uid, out AppearanceComponent? appearance)) { - UpdateState(uid, state, component, metadata); return; } - if (component.NextFlush != null) + if (!Transform(uid).Anchored) { - if (component.NextFlush.Value < GameTiming.CurTime) - { - TryFlush(uid, component); - } + _appearance.SetData(uid, DisposalUnitComponent.Visuals.VisualState, DisposalUnitComponent.VisualState.UnAnchored, appearance); + _appearance.SetData(uid, DisposalUnitComponent.Visuals.Handle, DisposalUnitComponent.HandleState.Normal, appearance); + _appearance.SetData(uid, DisposalUnitComponent.Visuals.Light, DisposalUnitComponent.LightStates.Off, appearance); + return; } - UpdateState(uid, state, component, metadata); + var state = GetState(uid, component); - Box2? disposalsBounds = null; - var count = component.RecentlyEjected.Count; - - if (count > 0) + switch (state) { - if (!HasComp(uid)) - { - component.RecentlyEjected.Clear(); - } - else - { - disposalsBounds = _lookup.GetWorldAABB(uid); - } + case DisposalsPressureState.Flushed: + _appearance.SetData(uid, DisposalUnitComponent.Visuals.VisualState, DisposalUnitComponent.VisualState.OverlayFlushing, appearance); + break; + case DisposalsPressureState.Pressurizing: + _appearance.SetData(uid, DisposalUnitComponent.Visuals.VisualState, DisposalUnitComponent.VisualState.OverlayCharging, appearance); + break; + case DisposalsPressureState.Ready: + _appearance.SetData(uid, DisposalUnitComponent.Visuals.VisualState, DisposalUnitComponent.VisualState.Anchored, appearance); + break; } - for (var i = 0; i < component.RecentlyEjected.Count; i++) - { - var ejectedId = component.RecentlyEjected[i]; - if (HasComp(ejectedId)) - { - // TODO: We need to use a specific collision method (which sloth hasn't coded yet) for actual bounds overlaps. - // TODO: Come do this sloth :^) - // Check for itemcomp as we won't just block the disposal unit "sleeping" for something it can't collide with anyway. - if (!HasComp(ejectedId) - && _lookup.GetWorldAABB(ejectedId).Intersects(disposalsBounds!.Value)) - { - continue; - } + _appearance.SetData(uid, DisposalUnitComponent.Visuals.Handle, component.Engaged + ? DisposalUnitComponent.HandleState.Engaged + : DisposalUnitComponent.HandleState.Normal, appearance); - component.RecentlyEjected.RemoveAt(i); - i--; - } + if (!_power.IsPowered(uid)) + { + _appearance.SetData(uid, DisposalUnitComponent.Visuals.Light, DisposalUnitComponent.LightStates.Off, appearance); + return; } - if (count != component.RecentlyEjected.Count) - Dirty(uid, component, metadata); + var lightState = DisposalUnitComponent.LightStates.Off; + + if (component.Container.ContainedEntities.Count > 0) + { + lightState |= DisposalUnitComponent.LightStates.Full; + } + + if (state is DisposalsPressureState.Pressurizing or DisposalsPressureState.Flushed) + { + lightState |= DisposalUnitComponent.LightStates.Charging; + } + else + { + lightState |= DisposalUnitComponent.LightStates.Ready; + } + + _appearance.SetData(uid, DisposalUnitComponent.Visuals.Light, lightState, appearance); + } + + /// + /// Gets the current pressure state of a disposals unit. + /// + /// + /// + /// + /// + public DisposalsPressureState GetState(EntityUid uid, DisposalUnitComponent component, MetaDataComponent? metadata = null) + { + var nextPressure = Metadata.GetPauseTime(uid, metadata) + component.NextPressurized - GameTiming.CurTime; + var pressurizeTime = 1f / PressurePerSecond; + var pressurizeDuration = pressurizeTime - component.FlushDelay.TotalSeconds; + + if (nextPressure.TotalSeconds > pressurizeDuration) + { + return DisposalsPressureState.Flushed; + } + + if (nextPressure > TimeSpan.Zero) + { + return DisposalsPressureState.Pressurizing; + } + + return DisposalsPressureState.Ready; + } + + public float GetPressure(EntityUid uid, DisposalUnitComponent component, MetaDataComponent? metadata = null) + { + if (!Resolve(uid, ref metadata)) + return 0f; + + var pauseTime = Metadata.GetPauseTime(uid, metadata); + return MathF.Min(1f, + (float)(GameTiming.CurTime - pauseTime - component.NextPressurized).TotalSeconds / PressurePerSecond); + } + + protected void OnPreventCollide(EntityUid uid, DisposalUnitComponent component, + ref PreventCollideEvent args) + { + var otherBody = args.OtherEntity; + + // Items dropped shouldn't collide but items thrown should + if (HasComp(otherBody) && !HasComp(otherBody)) + { + args.Cancelled = true; + } + } + + protected void OnCanDragDropOn(EntityUid uid, DisposalUnitComponent component, ref CanDropTargetEvent args) + { + if (args.Handled) + return; + + args.CanDrop = CanInsert(uid, component, args.Dragged); + args.Handled = true; + } + + protected void OnEmagged(EntityUid uid, DisposalUnitComponent component, ref GotEmaggedEvent args) + { + component.DisablePressure = true; + args.Handled = true; + } + + public virtual bool CanInsert(EntityUid uid, DisposalUnitComponent component, EntityUid entity) + { + // TODO: All of the below should be using the EXISTING EVENT + if (!Containers.CanInsert(entity, component.Container)) + return false; + + if (!Transform(uid).Anchored) + return false; + + var storable = HasComp(entity); + if (!storable && !HasComp(entity)) + return false; + + if (_whitelistSystem.IsBlacklistPass(component.Blacklist, entity) || + _whitelistSystem.IsWhitelistFail(component.Whitelist, entity)) + return false; + + if (TryComp(entity, out var physics) && (physics.CanCollide) || storable) + return true; + else + return false; + } + + public void DoInsertDisposalUnit(EntityUid uid, + EntityUid toInsert, + EntityUid user, + DisposalUnitComponent? disposal = null) + { + if (!Resolve(uid, ref disposal)) + return; + + if (!Containers.Insert(toInsert, disposal.Container)) + return; + + _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user):player} inserted {ToPrettyString(toInsert)} into {ToPrettyString(uid)}"); + AfterInsert(uid, disposal, toInsert, user); + } + + public virtual void AfterInsert(EntityUid uid, + DisposalUnitComponent component, + EntityUid inserted, + EntityUid? user = null, + bool doInsert = false) + { + Audio.PlayPredicted(component.InsertSound, uid, user: user); + if (doInsert && !Containers.Insert(inserted, component.Container)) + return; + + if (user != inserted && user != null) + _adminLog.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user.Value):player} inserted {ToPrettyString(inserted)} into {ToPrettyString(uid)}"); + + QueueAutomaticEngage(uid, component); + + _ui.CloseUi(uid, DisposalUnitComponent.DisposalUnitUiKey.Key, inserted); + + // Maybe do pullable instead? Eh still fine. + Joints.RecursiveClearJoints(inserted); + UpdateVisualState(uid, component); } public bool TryInsert(EntityUid unitId, EntityUid toInsertId, EntityUid? userId, DisposalUnitComponent? unit = null) @@ -507,8 +536,61 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem return true; } + private void UpdateState(EntityUid uid, DisposalsPressureState state, DisposalUnitComponent component, MetaDataComponent metadata) + { + if (component.State == state) + return; - public bool TryFlush(EntityUid uid, SharedDisposalUnitComponent component) + component.State = state; + UpdateVisualState(uid, component); + Dirty(uid, component, metadata); + + if (state == DisposalsPressureState.Ready) + { + component.NextPressurized = TimeSpan.Zero; + + // Manually engaged + if (component.Engaged) + { + component.NextFlush = GameTiming.CurTime + component.ManualFlushTime; + } + else if (component.Container.ContainedEntities.Count > 0) + { + component.NextFlush = GameTiming.CurTime + component.AutomaticEngageTime; + } + else + { + component.NextFlush = null; + } + } + } + + /// + /// Work out if we can stop updating this disposals component i.e. full pressure and nothing colliding. + /// + private void Update(EntityUid uid, DisposalUnitComponent component, MetaDataComponent metadata) + { + var state = GetState(uid, component, metadata); + + // Pressurizing, just check if we need a state update. + if (component.NextPressurized > GameTiming.CurTime) + { + UpdateState(uid, state, component, metadata); + return; + } + + if (component.NextFlush != null) + { + if (component.NextFlush.Value < GameTiming.CurTime) + { + TryFlush(uid, component); + } + } + + UpdateState(uid, state, component, metadata); + } + + public bool TryFlush(EntityUid uid, DisposalUnitComponent component) { if (!CanFlush(uid, component)) { @@ -533,11 +615,12 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem var coords = xform.Coordinates; var entry = _map.GetLocal(xform.GridUid.Value, grid, coords) - .FirstOrDefault(HasComp); + .FirstOrDefault(HasComp); if (entry == default || component is not DisposalUnitComponent sDisposals) { component.Engaged = false; + UpdateUI((uid, component)); Dirty(uid, component); return false; } @@ -555,140 +638,23 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem component.NextFlush = null; UpdateVisualState(uid, component, true); - UpdateInterface(uid, component, component.Powered); - Dirty(uid, component); + UpdateUI((uid, component)); return true; } - private void HandleAir(EntityUid uid, DisposalUnitComponent component, TransformComponent xform) + protected virtual void HandleAir(EntityUid uid, DisposalUnitComponent component, TransformComponent xform) { - var air = component.Air; - var indices = _transformSystem.GetGridTilePositionOrDefault((uid, xform)); - if (_atmosSystem.GetTileMixture(xform.GridUid, xform.MapUid, indices, true) is { Temperature: > 0f } environment) - { - var transferMoles = 0.1f * (0.25f * Atmospherics.OneAtmosphere * 1.01f - air.Pressure) * air.Volume / (environment.Temperature * Atmospherics.R); - - component.Air = environment.Remove(transferMoles); - } } - public void UpdateInterface(EntityUid uid, SharedDisposalUnitComponent component, bool powered) - { - var compState = GetState(uid, component); - var stateString = Loc.GetString($"disposal-unit-state-{compState}"); - var state = new SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState(Name(uid), stateString, EstimatedFullPressure(uid, component), powered, component.Engaged); - _ui.SetUiState(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, state); - - var stateUpdatedEvent = new DisposalUnitUIStateUpdatedEvent(state); - RaiseLocalEvent(uid, stateUpdatedEvent); - } - - /// - /// Returns the estimated time when the disposal unit will be back to full pressure. - /// - private TimeSpan EstimatedFullPressure(EntityUid uid, SharedDisposalUnitComponent component) - { - if (component.NextPressurized < GameTiming.CurTime) - return TimeSpan.Zero; - - return component.NextPressurized; - } - - public void UpdateVisualState(EntityUid uid, SharedDisposalUnitComponent component, bool flush = false) - { - if (!TryComp(uid, out AppearanceComponent? appearance)) - { - return; - } - - if (!Transform(uid).Anchored) - { - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.UnAnchored, appearance); - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Handle, SharedDisposalUnitComponent.HandleState.Normal, appearance); - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Light, SharedDisposalUnitComponent.LightStates.Off, appearance); - return; - } - - var state = GetState(uid, component); - - switch (state) - { - case DisposalsPressureState.Flushed: - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.OverlayFlushing, appearance); - break; - case DisposalsPressureState.Pressurizing: - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.OverlayCharging, appearance); - break; - case DisposalsPressureState.Ready: - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.VisualState, SharedDisposalUnitComponent.VisualState.Anchored, appearance); - break; - } - - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Handle, component.Engaged - ? SharedDisposalUnitComponent.HandleState.Engaged - : SharedDisposalUnitComponent.HandleState.Normal, appearance); - - if (!component.Powered) - { - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Light, SharedDisposalUnitComponent.LightStates.Off, appearance); - return; - } - - var lightState = SharedDisposalUnitComponent.LightStates.Off; - - if (component.Container.ContainedEntities.Count > 0) - { - lightState |= SharedDisposalUnitComponent.LightStates.Full; - } - - if (state is DisposalsPressureState.Pressurizing or DisposalsPressureState.Flushed) - { - lightState |= SharedDisposalUnitComponent.LightStates.Charging; - } - else - { - lightState |= SharedDisposalUnitComponent.LightStates.Ready; - } - - _appearance.SetData(uid, SharedDisposalUnitComponent.Visuals.Light, lightState, appearance); - } - - public void Remove(EntityUid uid, SharedDisposalUnitComponent component, EntityUid toRemove) - { - _containerSystem.Remove(toRemove, component.Container); - - if (component.Container.ContainedEntities.Count == 0) - { - // If not manually engaged then reset the flushing entirely. - if (!component.Engaged) - { - component.NextFlush = null; - } - } - - if (!component.RecentlyEjected.Contains(toRemove)) - component.RecentlyEjected.Add(toRemove); - - UpdateVisualState(uid, component); - Dirty(uid, component); - } - - public bool CanFlush(EntityUid unit, SharedDisposalUnitComponent component) - { - return GetState(unit, component) == DisposalsPressureState.Ready - && component.Powered - && Comp(unit).Anchored; - } - - public void ManualEngage(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent? metadata = null) + public void ManualEngage(EntityUid uid, DisposalUnitComponent component, MetaDataComponent? metadata = null) { component.Engaged = true; UpdateVisualState(uid, component); - UpdateInterface(uid, component, component.Powered); Dirty(uid, component); + UpdateUI((uid, component)); if (!CanFlush(uid, component)) return; @@ -701,7 +667,7 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem component.NextFlush = TimeSpan.FromSeconds(Math.Min((component.NextFlush ?? TimeSpan.MaxValue).TotalSeconds, nextEngage.TotalSeconds)); } - public void Disengage(EntityUid uid, SharedDisposalUnitComponent component) + public void Disengage(EntityUid uid, DisposalUnitComponent component) { component.Engaged = false; @@ -711,14 +677,14 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem } UpdateVisualState(uid, component); - UpdateInterface(uid, component, component.Powered); Dirty(uid, component); + UpdateUI((uid, component)); } /// /// Remove all entities currently in the disposal unit. /// - public void TryEjectContents(EntityUid uid, SharedDisposalUnitComponent component) + public void TryEjectContents(EntityUid uid, DisposalUnitComponent component) { foreach (var entity in component.Container.ContainedEntities.ToArray()) { @@ -729,38 +695,16 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem { component.NextFlush = null; Dirty(uid, component); + UpdateUI((uid, component)); } } - public override bool HasDisposals(EntityUid? uid) - { - return HasComp(uid); - } - - public override bool ResolveDisposals(EntityUid uid, [NotNullWhen(true)] ref SharedDisposalUnitComponent? component) - { - if (component != null) - return true; - - TryComp(uid, out var storage); - component = storage; - return component != null; - } - - public override bool CanInsert(EntityUid uid, SharedDisposalUnitComponent component, EntityUid entity) - { - if (!base.CanInsert(uid, component, entity)) - return false; - - return _containerSystem.CanInsert(entity, component.Container); - } - /// /// If something is inserted (or the likes) then we'll queue up an automatic flush in the future. /// - public void QueueAutomaticEngage(EntityUid uid, SharedDisposalUnitComponent component, MetaDataComponent? metadata = null) + public void QueueAutomaticEngage(EntityUid uid, DisposalUnitComponent component, MetaDataComponent? metadata = null) { - if (component.Deleted || !component.AutomaticEngage || !component.Powered && component.Container.ContainedEntities.Count == 0) + if (component.Deleted || !component.AutomaticEngage || !_power.IsPowered(uid) && component.Container.ContainedEntities.Count == 0) { return; } @@ -771,53 +715,74 @@ public sealed class DisposalUnitSystem : SharedDisposalUnitSystem component.NextFlush = flushTime; Dirty(uid, component); + UpdateUI((uid, component)); } - public void AfterInsert(EntityUid uid, SharedDisposalUnitComponent component, EntityUid inserted, EntityUid? user = null, bool doInsert = false) + private void OnUiButtonPressed(EntityUid uid, DisposalUnitComponent component, DisposalUnitComponent.UiButtonPressedMessage args) { - _audioSystem.PlayPvs(component.InsertSound, uid); + if (args.Actor is not { Valid: true } player) + { + return; + } - if (doInsert && !_containerSystem.Insert(inserted, component.Container)) + switch (args.Button) + { + case DisposalUnitComponent.UiButton.Eject: + TryEjectContents(uid, component); + _adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} hit eject button on {ToPrettyString(uid)}"); + break; + case DisposalUnitComponent.UiButton.Engage: + ToggleEngage(uid, component); + _adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} hit flush button on {ToPrettyString(uid)}, it's now {(component.Engaged ? "on" : "off")}"); + break; + case DisposalUnitComponent.UiButton.Power: + _power.TogglePower(uid, user: args.Actor); + break; + default: + throw new ArgumentOutOfRangeException($"{ToPrettyString(player):player} attempted to hit a nonexistant button on {ToPrettyString(uid)}"); + } + } + + public void ToggleEngage(EntityUid uid, DisposalUnitComponent component) + { + component.Engaged ^= true; + + if (component.Engaged) + { + ManualEngage(uid, component); + } + else + { + Disengage(uid, component); + } + } + + private void AddClimbInsideVerb(EntityUid uid, DisposalUnitComponent component, GetVerbsEvent args) + { + // This is not an interaction, activation, or alternative verb type because unfortunately most users are + // unwilling to accept that this is where they belong and don't want to accidentally climb inside. + if (!args.CanAccess || + !args.CanInteract || + component.Container.ContainedEntities.Contains(args.User) || + !ActionBlockerSystem.CanMove(args.User)) + { + return; + } + + if (!CanInsert(uid, component, args.User)) return; - if (user != inserted && user != null) - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user.Value):player} inserted {ToPrettyString(inserted)} into {ToPrettyString(uid)}"); - - QueueAutomaticEngage(uid, component); - - _ui.CloseUi(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, inserted); - - // Maybe do pullable instead? Eh still fine. - Joints.RecursiveClearJoints(inserted); - UpdateVisualState(uid, component); - } - - private void OnExploded(Entity ent, ref BeforeExplodeEvent args) - { - args.Contents.AddRange(ent.Comp.Container.ContainedEntities); - } - -} - -/// -/// Sent before the disposal unit flushes it's contents. -/// Allows adding tags for sorting and preventing the disposal unit from flushing. -/// -public sealed class DisposalUnitUIStateUpdatedEvent : EntityEventArgs -{ - public SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState State; - - public DisposalUnitUIStateUpdatedEvent(SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState state) - { - State = state; + // Add verb to climb inside of the unit, + Verb verb = new() + { + Act = () => TryInsert(uid, args.User, args.User), + DoContactInteraction = true, + Text = Loc.GetString("disposal-self-insert-verb-get-data-text") + }; + // TODO VERB ICON + // TODO VERB CATEGORY + // create a verb category for "enter"? + // See also, medical scanner. Also maybe add verbs for entering lockers/body bags? + args.Verbs.Add(verb); } } - -/// -/// Sent before the disposal unit flushes it's contents. -/// Allows adding tags for sorting and preventing the disposal unit from flushing. -/// -public sealed class BeforeDisposalFlushEvent : CancellableEntityEventArgs -{ - public readonly List Tags = new(); -} diff --git a/Content.Shared/Foldable/DeployFoldableSystem.cs b/Content.Shared/Foldable/DeployFoldableSystem.cs index 16315cde69..a83518dfa3 100644 --- a/Content.Shared/Foldable/DeployFoldableSystem.cs +++ b/Content.Shared/Foldable/DeployFoldableSystem.cs @@ -1,7 +1,10 @@ +using Content.Shared.Construction.EntitySystems; using Content.Shared.DragDrop; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; +using Content.Shared.Popups; +using Robust.Shared.Physics.Components; namespace Content.Shared.Foldable; @@ -9,6 +12,8 @@ public sealed class DeployFoldableSystem : EntitySystem { [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly FoldableSystem _foldable = default!; + [Dependency] private readonly AnchorableSystem _anchorable = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; public override void Initialize() { @@ -57,6 +62,13 @@ public sealed class DeployFoldableSystem : EntitySystem if (!TryComp(ent, out var foldable)) return; + if (!TryComp(ent.Owner, out PhysicsComponent? anchorBody) + || !_anchorable.TileFree(args.ClickLocation, anchorBody)) + { + _popup.PopupPredicted(Loc.GetString("foldable-deploy-fail", ("object", ent)), ent, args.User); + return; + } + if (!TryComp(args.User, out HandsComponent? hands) || !_hands.TryDrop(args.User, args.Used, targetDropLocation: args.ClickLocation, handsComp: hands)) return; diff --git a/Content.Shared/Foldable/FoldableSystem.cs b/Content.Shared/Foldable/FoldableSystem.cs index 3ba4201e79..73916f1c15 100644 --- a/Content.Shared/Foldable/FoldableSystem.cs +++ b/Content.Shared/Foldable/FoldableSystem.cs @@ -1,9 +1,11 @@ -using Content.Shared.Body.Components; using Content.Shared.Buckle; using Content.Shared.Buckle.Components; +using Content.Shared.Construction.EntitySystems; +using Content.Shared.Popups; using Content.Shared.Storage.Components; using Content.Shared.Verbs; using Robust.Shared.Containers; +using Robust.Shared.Physics.Components; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -15,6 +17,8 @@ public sealed class FoldableSystem : EntitySystem [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedBuckleSystem _buckle = default!; [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly AnchorableSystem _anchorable = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; public override void Initialize() { @@ -83,9 +87,17 @@ public sealed class FoldableSystem : EntitySystem args.Cancel(); } - public bool TryToggleFold(EntityUid uid, FoldableComponent comp) + public bool TryToggleFold(EntityUid uid, FoldableComponent comp, EntityUid? folder = null) { - return TrySetFolded(uid, comp, !comp.IsFolded); + var result = TrySetFolded(uid, comp, !comp.IsFolded); + if (!result && folder != null) + { + if (comp.IsFolded) + _popup.PopupPredicted(Loc.GetString("foldable-unfold-fail", ("object", uid)), uid, folder.Value); + else + _popup.PopupPredicted(Loc.GetString("foldable-fold-fail", ("object", uid)), uid, folder.Value); + } + return result; } public bool CanToggleFold(EntityUid uid, FoldableComponent? fold = null) @@ -97,6 +109,10 @@ public sealed class FoldableSystem : EntitySystem if (_container.IsEntityInContainer(uid) && !fold.CanFoldInsideContainer) return false; + if (!TryComp(uid, out PhysicsComponent? body) || + !_anchorable.TileFree(Transform(uid).Coordinates, body)) + return false; + var ev = new FoldAttemptEvent(fold); RaiseLocalEvent(uid, ref ev); return !ev.Cancelled; @@ -121,12 +137,12 @@ public sealed class FoldableSystem : EntitySystem private void AddFoldVerb(EntityUid uid, FoldableComponent component, GetVerbsEvent args) { - if (!args.CanAccess || !args.CanInteract || args.Hands == null || !CanToggleFold(uid, component)) + if (!args.CanAccess || !args.CanInteract || args.Hands == null) return; AlternativeVerb verb = new() { - Act = () => TryToggleFold(uid, component), + Act = () => TryToggleFold(uid, component, args.User), Text = component.IsFolded ? Loc.GetString(component.UnfoldVerbText) : Loc.GetString(component.FoldVerbText), Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/fold.svg.192dpi.png")), diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index f492bce09e..15ae370a8d 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -51,7 +51,6 @@ namespace Content.Shared.Interaction public abstract partial class SharedInteractionSystem : EntitySystem { [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; @@ -223,24 +222,24 @@ namespace Content.Shared.Interaction { if (!item.DeleteOnDrop) RemCompDeferred(uid); - else if (_net.IsServer) - QueueDel(uid); + else + PredictedQueueDel(uid); } private void OnUnequipHand(EntityUid uid, UnremoveableComponent item, GotUnequippedHandEvent args) { if (!item.DeleteOnDrop) RemCompDeferred(uid); - else if (_net.IsServer) - QueueDel(uid); + else + PredictedQueueDel(uid); } private void OnDropped(EntityUid uid, UnremoveableComponent item, DroppedEvent args) { if (!item.DeleteOnDrop) RemCompDeferred(uid); - else if (_net.IsServer) - QueueDel(uid); + else + PredictedQueueDel(uid); } private bool HandleTryPullObject(ICommonSession? session, EntityCoordinates coords, EntityUid uid) @@ -855,7 +854,7 @@ namespace Content.Shared.Interaction { // If the target is an item, we ignore any colliding entities. Currently done so that if items get stuck // inside of walls, users can still pick them up. - ignored.UnionWith(_broadphase.GetEntitiesIntersectingBody(target, (int) collisionMask, false, physics)); + ignored.UnionWith(_broadphase.GetEntitiesIntersectingBody(target, (int) collisionMask, false, physics)); // Note: This also bypasses items underneath doors, which may be problematic if it'd cause undesirable behavior. } else if (_wallMountQuery.TryComp(target, out var wallMount)) { diff --git a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs index 9eac60adc4..256a5ec2a9 100644 --- a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs +++ b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs @@ -157,11 +157,6 @@ public abstract class SharedVirtualItemSystem : EntitySystem /// public void DeleteInHandsMatching(EntityUid user, EntityUid matching) { - // Client can't currently predict deleting networked entities so we use this workaround, another - // problem can popup when the hands leave PVS for example and this avoids that too - if (_netManager.IsClient) - return; - foreach (var hand in _handsSystem.EnumerateHands(user)) { if (TryComp(hand.HeldEntity, out VirtualItemComponent? virt) && virt.BlockingEntity == matching) @@ -206,11 +201,6 @@ public abstract class SharedVirtualItemSystem : EntitySystem /// Set this param if you have the name of the slot, it avoids unnecessary queries public void DeleteInSlotMatching(EntityUid user, EntityUid matching, string? slotName = null) { - // Client can't currently predict deleting networked entities so we use this workaround, another - // problem can popup when the hands leave PVS for example and this avoids that too - if (_netManager.IsClient) - return; - if (slotName != null) { if (!_inventorySystem.TryGetSlotEntity(user, slotName, out var slotEnt)) @@ -244,14 +234,8 @@ public abstract class SharedVirtualItemSystem : EntitySystem /// The virtual item, if spawned public bool TrySpawnVirtualItem(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem) { - if (_netManager.IsClient) - { - virtualItem = null; - return false; - } - var pos = Transform(user).Coordinates; - virtualItem = Spawn(VirtualItem, pos); + virtualItem = PredictedSpawnAttachedTo(VirtualItem, pos); var virtualItemComp = Comp(virtualItem.Value); virtualItemComp.BlockingEntity = blockingEnt; Dirty(virtualItem.Value, virtualItemComp); @@ -272,8 +256,6 @@ public abstract class SharedVirtualItemSystem : EntitySystem if (TerminatingOrDeleted(item)) return; - _transformSystem.DetachEntity(item, Transform(item)); - if (_netManager.IsServer) - QueueDel(item); + PredictedQueueDel(item.Owner); } } diff --git a/Content.Shared/Item/MultiHandedItemComponent.cs b/Content.Shared/Item/MultiHandedItemComponent.cs index 9a90d063ba..3a0ac23bcd 100644 --- a/Content.Shared/Item/MultiHandedItemComponent.cs +++ b/Content.Shared/Item/MultiHandedItemComponent.cs @@ -9,6 +9,6 @@ namespace Content.Shared.Item; [RegisterComponent, NetworkedComponent] public sealed partial class MultiHandedItemComponent : Component { - [DataField("handsNeeded"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public int HandsNeeded = 2; } diff --git a/Content.Shared/Item/MultiHandedItemSystem.cs b/Content.Shared/Item/MultiHandedItemSystem.cs new file mode 100644 index 0000000000..da9d895dd2 --- /dev/null +++ b/Content.Shared/Item/MultiHandedItemSystem.cs @@ -0,0 +1,56 @@ +using Content.Shared.Hands; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Inventory.VirtualItem; +using Content.Shared.Popups; +using Robust.Shared.Timing; + +namespace Content.Shared.Item; + +public sealed class MultiHandedItemSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedVirtualItemSystem _virtualItem = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnAttemptPickup); + SubscribeLocalEvent(OnVirtualItemDeleted); + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); + } + + private void OnEquipped(Entity ent, ref GotEquippedHandEvent args) + { + for (var i = 0; i < ent.Comp.HandsNeeded - 1; i++) + { + _virtualItem.TrySpawnVirtualItemInHand(ent.Owner, args.User); + } + } + + private void OnUnequipped(Entity ent, ref GotUnequippedHandEvent args) + { + _virtualItem.DeleteInHandsMatching(args.User, ent.Owner); + } + + private void OnAttemptPickup(Entity ent, ref GettingPickedUpAttemptEvent args) + { + if (TryComp(args.User, out var hands) && hands.CountFreeHands() >= ent.Comp.HandsNeeded) + return; + + args.Cancel(); + _popup.PopupPredictedCursor(Loc.GetString("multi-handed-item-pick-up-fail", + ("number", ent.Comp.HandsNeeded - 1), ("item", ent.Owner)), args.User); + } + + private void OnVirtualItemDeleted(Entity ent, ref VirtualItemDeletedEvent args) + { + if (args.BlockingEntity != ent.Owner || _timing.ApplyingState) + return; + + _hands.TryDrop(args.User, ent.Owner); + } +} diff --git a/Content.Shared/Item/SharedMultiHandedItemSystem.cs b/Content.Shared/Item/SharedMultiHandedItemSystem.cs deleted file mode 100644 index 0259b361b5..0000000000 --- a/Content.Shared/Item/SharedMultiHandedItemSystem.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Content.Shared.Hands; -using Content.Shared.Hands.Components; -using Content.Shared.Hands.EntitySystems; -using Content.Shared.Popups; -using Robust.Shared.Timing; - -namespace Content.Shared.Item; - -public abstract class SharedMultiHandedItemSystem : EntitySystem -{ - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly SharedHandsSystem _hands = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - - /// - public override void Initialize() - { - SubscribeLocalEvent(OnAttemptPickup); - SubscribeLocalEvent(OnVirtualItemDeleted); - SubscribeLocalEvent(OnEquipped); - SubscribeLocalEvent(OnUnequipped); - } - - protected abstract void OnEquipped(EntityUid uid, MultiHandedItemComponent component, GotEquippedHandEvent args); - protected abstract void OnUnequipped(EntityUid uid, MultiHandedItemComponent component, GotUnequippedHandEvent args); - - private void OnAttemptPickup(EntityUid uid, MultiHandedItemComponent component, GettingPickedUpAttemptEvent args) - { - if (TryComp(args.User, out var hands) && hands.CountFreeHands() >= component.HandsNeeded) - return; - - args.Cancel(); - if (_timing.IsFirstTimePredicted) - { - _popup.PopupCursor(Loc.GetString("multi-handed-item-pick-up-fail", - ("number", component.HandsNeeded - 1), ("item", uid)), args.User); - } - } - - private void OnVirtualItemDeleted(EntityUid uid, MultiHandedItemComponent component, VirtualItemDeletedEvent args) - { - if (args.BlockingEntity != uid) - return; - - _hands.TryDrop(args.User, uid); - } -} diff --git a/Content.Shared/Power/Components/SharedApcPowerReceiverComponent.cs b/Content.Shared/Power/Components/SharedApcPowerReceiverComponent.cs index 69c3bd790e..80bacd24bd 100644 --- a/Content.Shared/Power/Components/SharedApcPowerReceiverComponent.cs +++ b/Content.Shared/Power/Components/SharedApcPowerReceiverComponent.cs @@ -8,9 +8,15 @@ public abstract partial class SharedApcPowerReceiverComponent : Component [ViewVariables] public bool Powered; - [ViewVariables] - public virtual bool NeedsPower { get; set; } + /// + /// When false, causes this to appear powered even if not receiving power from an Apc. + /// + [ViewVariables(VVAccess.ReadWrite)] + public virtual bool NeedsPower { get; set;} - [ViewVariables] + /// + /// When true, causes this to never appear powered. + /// + [ViewVariables(VVAccess.ReadWrite)] public virtual bool PowerDisabled { get; set; } } diff --git a/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs b/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs index 2d152d8b45..d86273974b 100644 --- a/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs +++ b/Content.Shared/Power/EntitySystems/SharedPowerReceiverSystem.cs @@ -62,8 +62,13 @@ public abstract class SharedPowerReceiverSystem : EntitySystem return !receiver.PowerDisabled; // i.e. PowerEnabled } - /// - /// Checks if entity is APC-powered device, and if it have power. + protected virtual void RaisePower(Entity entity) + { + // NOOP on server because client has 0 idea of load so we can't raise it properly in shared. + } + + /// + /// Checks if entity is APC-powered device, and if it have power. /// public bool IsPowered(Entity entity) { diff --git a/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs b/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs index 9ddcb423b4..e63c6ac7b7 100644 --- a/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs +++ b/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs @@ -58,13 +58,7 @@ public sealed partial class EncryptionKeySystem : EntitySystem _hands.PickupOrDrop(args.User, ent, dropNear: true); } - if (!_timing.IsFirstTimePredicted) - return; - - // TODO add predicted pop-up overrides. - if (_net.IsServer) - _popup.PopupEntity(Loc.GetString("encryption-keys-all-extracted"), uid, args.User); - + _popup.PopupPredicted(Loc.GetString("encryption-keys-all-extracted"), uid, args.User); _audio.PlayPredicted(component.KeyExtractionSound, uid, args.User); } diff --git a/Content.Shared/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs b/Content.Shared/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs index 93c7c22471..8caf1c39a6 100644 --- a/Content.Shared/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs +++ b/Content.Shared/Research/TechnologyDisk/Systems/TechnologyDiskSystem.cs @@ -74,8 +74,7 @@ public sealed class TechnologyDiskSystem : EntitySystem } } _popup.PopupClient(Loc.GetString("tech-disk-inserted"), target, args.User); - if (_net.IsServer) - QueueDel(ent); + PredictedQueueDel(ent.Owner); args.Handled = true; } diff --git a/Content.Shared/Storage/EntitySystems/DumpableSystem.cs b/Content.Shared/Storage/EntitySystems/DumpableSystem.cs index 93c4b69e4d..d0ad27eee5 100644 --- a/Content.Shared/Storage/EntitySystems/DumpableSystem.cs +++ b/Content.Shared/Storage/EntitySystems/DumpableSystem.cs @@ -1,5 +1,7 @@ using System.Linq; using Content.Shared.Disposal; +using Content.Shared.Disposal.Components; +using Content.Shared.Disposal.Unit; using Content.Shared.DoAfter; using Content.Shared.Interaction; using Content.Shared.Item; @@ -40,7 +42,7 @@ public sealed class DumpableSystem : EntitySystem if (!args.CanReach || args.Handled) return; - if (!_disposalUnitSystem.HasDisposals(args.Target) && !HasComp(args.Target)) + if (!HasComp(args.Target) && !HasComp(args.Target)) return; if (!TryComp(uid, out var storage)) @@ -81,7 +83,7 @@ public sealed class DumpableSystem : EntitySystem if (!TryComp(uid, out var storage) || !storage.Container.ContainedEntities.Any()) return; - if (_disposalUnitSystem.HasDisposals(args.Target)) + if (HasComp(args.Target)) { UtilityVerb verb = new() { @@ -146,7 +148,7 @@ public sealed class DumpableSystem : EntitySystem var dumped = false; - if (_disposalUnitSystem.HasDisposals(args.Args.Target)) + if (HasComp(args.Args.Target)) { dumped = true; diff --git a/Content.Shared/Wieldable/SharedWieldableSystem.cs b/Content.Shared/Wieldable/SharedWieldableSystem.cs index ee7b0de263..3cb86b275b 100644 --- a/Content.Shared/Wieldable/SharedWieldableSystem.cs +++ b/Content.Shared/Wieldable/SharedWieldableSystem.cs @@ -22,6 +22,7 @@ using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Weapons.Ranged.Systems; using Content.Shared.Wieldable.Components; using Robust.Shared.Audio.Systems; +using Robust.Shared.Collections; using Robust.Shared.Network; using Robust.Shared.Timing; @@ -280,26 +281,21 @@ public abstract class SharedWieldableSystem : EntitySystem _audio.PlayPredicted(component.WieldSound, used, user); //This section handles spawning the virtual item(s) to occupy the required additional hand(s). - //Since the client can't currently predict entity spawning, only do this if this is running serverside. - //Remove this check if TrySpawnVirtualItem in SharedVirtualItemSystem is allowed to complete clientside. - if (_netManager.IsServer) + var virtuals = new ValueList(); + for (var i = 0; i < component.FreeHandsRequired; i++) { - var virtuals = new List(); - for (var i = 0; i < component.FreeHandsRequired; i++) + if (_virtualItem.TrySpawnVirtualItemInHand(used, user, out var virtualItem, true)) { - if (_virtualItem.TrySpawnVirtualItemInHand(used, user, out var virtualItem, true)) - { - virtuals.Add(virtualItem.Value); - continue; - } - - foreach (var existingVirtual in virtuals) - { - QueueDel(existingVirtual); - } - - return false; + virtuals.Add(virtualItem.Value); + continue; } + + foreach (var existingVirtual in virtuals) + { + QueueDel(existingVirtual); + } + + return false; } var selfMessage = Loc.GetString("wieldable-component-successful-wield", ("item", used)); diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index dff89adf6a..1488fb5207 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,34 +1,4 @@ Entries: -- author: lzk228 - changes: - - message: Now you are allowed to paint multiple airlocks with the spray painter. - Along with that you can cancel the doafter by clicking on the door you are painting. - type: Tweak - id: 7752 - time: '2024-12-24T02:25:04.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34001 -- author: ArtisticRoomba - changes: - - message: Reinforced tables now require welding to construct and deconstruct. - type: Tweak - id: 7753 - time: '2024-12-26T22:47:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33992 -- author: crazybrain - changes: - - message: Bluespace lockers and quantum spin inverters can no longer go on the - arrivals shuttle. - type: Tweak - id: 7754 - time: '2024-12-27T12:34:31.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34072 -- author: Plykiya - changes: - - message: You now see a popup when being cuffed or uncuffed again. - type: Fix - id: 7755 - time: '2024-12-27T13:34:32.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33639 - author: Alpaccalypse changes: - message: Power monitoring computer boards can no longer be researched or printed, @@ -3916,3 +3886,31 @@ id: 8252 time: '2025-04-19T01:48:41.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/33835 +- author: SharkSnake98 + changes: + - message: Added 12 new, varied drinks for the bartender to mix during shifts. + type: Add + id: 8253 + time: '2025-04-19T05:12:11.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36287 +- author: Ko4erga + changes: + - message: Added new color turtlenecks in WinterDrobe. + type: Add + id: 8254 + time: '2025-04-19T05:14:50.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32920 +- author: metalgearsloth + changes: + - message: Virtual items (e.g. wielding) are now predicted. + type: Add + id: 8255 + time: '2025-04-19T06:51:12.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36617 +- author: metalgearsloth + changes: + - message: Fix charges sometimes breaking for auto-recharge devices such as RCDs. + type: Fix + id: 8256 + time: '2025-04-19T08:49:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36714 diff --git a/Resources/Locale/en-US/_strings/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/_strings/flavors/flavor-profiles.ftl index e3783df236..dccdba5a63 100644 --- a/Resources/Locale/en-US/_strings/flavors/flavor-profiles.ftl +++ b/Resources/Locale/en-US/_strings/flavors/flavor-profiles.ftl @@ -236,8 +236,11 @@ flavor-complex-long-island = suspiciously like iced tea flavor-complex-three-mile-island = like tea brewed in nuclear runoff flavor-complex-whiskey-cola = like carbonated molasses flavor-complex-root-beer-float = like ice cream in root beer +flavor-complex-crush-depth = like the Hadal Zone flavor-complex-black-russian = like alcoholic coffee flavor-complex-white-russian = like alcoholic sweetened coffee +flavor-complex-electric-shark = like Shark Week in the tropics +flavor-complex-tortuga = like sweet tea flavor-complex-moonshine = like pure alcohol flavor-complex-singulo = like a bottomless hole flavor-complex-syndie-bomb = like bitter whiskey @@ -253,6 +256,12 @@ flavor-complex-atomic-cola = like hoarding bottle caps flavor-complex-cuba-libre = like spiked cola flavor-complex-gin-tonic = refreshingly bitter flavor-complex-screwdriver = like spiked orange juice +flavor-complex-jack-rose = like a testimony +flavor-complex-jungle-bird = like you’re in a tropical aviary +flavor-complex-kalimotxo = like fancy spiked cola +flavor-complex-vampiro = fruity, savoury, and spicy +flavor-complex-bronx = like mildly sweet, alcoholic fruit +flavor-complex-monkey-business = like going ape flavor-complex-vodka-red-bool = like a heart attack flavor-complex-irish-bool = like caffeine and Ireland flavor-complex-xeno-basher = like killing bugs @@ -260,6 +269,7 @@ flavor-complex-budget-insuls-drink = like door hacking flavor-complex-watermelon-wakeup = like a sweet wakeup call flavor-complex-rubberneck = like synthetics flavor-complex-irish-slammer = like a spiked cola float +flavor-complex-alien-brain-hemorrhage = like an extraterrestrial injury flavor-complex-themartinez = like violets and lemon vodka flavor-complex-cogchamp = like brass flavor-complex-white-gilgamesh = like lightly carbonated cream @@ -292,6 +302,7 @@ flavor-complex-driest-martini = like a drunk mimic flavor-complex-erika-surprise = like the bartender made a mistake flavor-complex-gin-fizz = refreshing and lemony flavor-complex-gildlager = like the Tzar's gold +flavor-complex-dark-and-stormy = like ginger ale spiked with rum flavor-complex-grog = like a sea shanty flavor-complex-hippies-delight = like your blood pressure is dropping flavor-complex-hooch = like it would be delicious if you were a diesel engine @@ -302,6 +313,7 @@ flavor-complex-martini = like a spy movie flavor-complex-mojito = like going into the shade after being in the hot sun flavor-complex-neurotoxin = like an underground testing facility flavor-complex-patron = like being serenaded by mariachi +flavor-complex-radler = like spiked lemonade flavor-complex-red-mead = like a viking battle flavor-complex-sbiten = like fire flavor-complex-snowwhite = like sour and bitter hops diff --git a/Resources/Locale/en-US/_strings/foldable/components/foldable-component.ftl b/Resources/Locale/en-US/_strings/foldable/components/foldable-component.ftl index 525820920b..1221efbdf0 100644 --- a/Resources/Locale/en-US/_strings/foldable/components/foldable-component.ftl +++ b/Resources/Locale/en-US/_strings/foldable/components/foldable-component.ftl @@ -1,5 +1,8 @@ # Foldable +foldable-fold-fail = You can't fold the {$object} here. +foldable-unfold-fail = You can't unfold the {$object} here. + foldable-deploy-fail = You can't deploy the {$object} here. fold-verb = Fold unfold-verb = Unfold diff --git a/Resources/Locale/en-US/_strings/reagents/meta/consumable/drink/alcohol.ftl b/Resources/Locale/en-US/_strings/reagents/meta/consumable/drink/alcohol.ftl index 5a22328900..df9e6ce78f 100644 --- a/Resources/Locale/en-US/_strings/reagents/meta/consumable/drink/alcohol.ftl +++ b/Resources/Locale/en-US/_strings/reagents/meta/consumable/drink/alcohol.ftl @@ -61,6 +61,9 @@ reagent-desc-champagne = A premium sparkling wine reagent-name-acid-spit = acidspit reagent-desc-acid-spit = A drink for the daring, can be deadly if incorrectly prepared! +reagent-name-alien-brain-hemorrhage = alien brain hemorrhage +reagent-desc-alien-brain-hemorrhage = You might want to get that checked out at Med. + reagent-name-allies-cocktail = allies cocktail reagent-desc-allies-cocktail = A drink made from your allies, not as sweet as when made from your enemies. @@ -109,15 +112,24 @@ reagent-desc-booger = Ewww... reagent-name-brave-bull = Brave Bull reagent-desc-brave-bull = It's just as effective as Dutch-Courage! +reagent-name-bronx = Bronx +reagent-desc-bronx = The orange-flavoured cousin of the Manhattan and Martini. + reagent-name-coconut-rum = coconut rum reagent-desc-coconut-rum = Rum with coconut for that tropical feel. reagent-name-cosmopolitan = cosmopolitan reagent-desc-cosmopolitan = Even in the worst situations, nothing beats a fresh cosmopolitan. +reagent-name-crush-depth = crush depth +reagent-desc-crush-depth = A stygian drink, harkening back to the abyssopelagic. Dark and Cold, it serves as a reminder that the most ancient emotion is fear, and the strongest type of fear is that of the unknown. + reagent-name-cuba-libre = Cuba libre reagent-desc-cuba-libre = Rum, mixed with cola. Viva la revolucion. +reagent-name-dark-and-stormy = dark & stormy +reagent-desc-dark-and-stormy = You can almost hear the thunder. + reagent-name-demons-blood = Demon's Blood reagent-desc-demons-blood = AHHHH!!!! @@ -130,6 +142,9 @@ reagent-desc-doctors-delight = A gulp a day keeps the MediBot away. That's proba reagent-name-driest-martini = driest martini reagent-desc-driest-martini = Only for the experienced. You think you see sand floating in the glass. +reagent-name-electric-shark = electric shark +reagent-desc-electric-shark = Fun Shark fact: Selachians make up 20% of Space Station 16’s Engineering staff! + reagent-name-erika-surprise = Erika surprise reagent-desc-erika-surprise = The surprise is, it's green! @@ -166,9 +181,21 @@ reagent-desc-irish-cream = Whiskey-imbued cream. What else could you expect from reagent-name-irish-coffee = Irish coffee reagent-desc-irish-coffee = Coffee served with irish cream. Regular cream just isn't the same! +reagent-name-jack-rose = Jack rose +reagent-desc-jack-rose = Excessively Red. + +reagent-name-jungle-bird = jungle bird +reagent-desc-jungle-bird = Despite the name, it’s not exceptionally popular among Voxes. + +reagent-name-kalimotxo = kalimotxo +reagent-desc-kalimotxo = A high-class Cuba Libre, for the discerning alcoholic. + reagent-name-kira-special = Kira special reagent-desc-kira-special = Long live the guy who everyone had mistaken for a girl. Baka! +reagent-name-tortuga = Tortuga +reagent-desc-tortuga = Perfect for pirates who’ve been selected as the designated driver. Yarr! + reagent-name-long-island-iced-tea = Long Island iced tea reagent-desc-long-island-iced-tea = The liquor cabinet, brought together in a delicious mix. Intended for middle-aged alcoholic women only. @@ -196,6 +223,9 @@ reagent-desc-mead = A Viking's drink, though a cheap one. reagent-name-mojito = Mojito reagent-desc-mojito = If it's good enough for Spesscuba, it's good enough for you. +reagent-name-monkey-business = monkey business +reagent-desc-monkey-business = You’ve got to wonder how the monkeys feel about this drink. + reagent-name-moonshine = moonshine reagent-desc-moonshine = Artisanal homemade liquor. What could go wrong? @@ -211,6 +241,9 @@ reagent-desc-patron = Tequila with silver in it, a favorite of alcoholic women i reagent-name-pina-colada = Piña Colada reagent-desc-pina-colada = For getting lost in the rain. +reagent-name-radler = radler +reagent-desc-radler = A simple but staple classic, straight out of Space-Germany. + reagent-name-red-mead = red mead reagent-desc-red-mead = The true Viking's drink! Even though it has a strange red color. @@ -250,6 +283,9 @@ reagent-desc-three-mile-island = "Made for a woman, strong enough for a man." reagent-name-toxins-special = toxins special reagent-desc-toxins-special = This thing is ON FIRE! CALL THE DAMN SHUTTLE! +reagent-name-vampiro = vampiro +reagent-desc-vampiro = Popular in Mexico and Transylvania. + reagent-name-vodka-martini = vodka martini reagent-desc-vodka-martini = Vodka instead of Gin. Not quite how 007 enjoyed it, but still delicious. diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/winterdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/winterdrobe.yml index a513e8d626..fe4c820bdb 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/winterdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/winterdrobe.yml @@ -7,10 +7,6 @@ ClothingNeckScarfStripedBlack: 3 ClothingNeckScarfStripedBrown: 3 ClothingNeckScarfStripedLightBlue: 3 -#sunrise-start - ClothingNeckScarfStripedCyan: 3 - ClothingNeckScarfStripedYellow: 3 -#sunrise-end ClothingNeckScarfStripedOrange: 3 ClothingNeckScarfStripedPurple: 3 ClothingOuterCoatTrench: 6 @@ -22,9 +18,45 @@ ClothingOuterCoatBomber: 3 ClothingHeadHatSantahat: 2 ClothingHeadHatXmasCrown: 2 - ClothingOuterChristmasSweeter: 3 #sunrise-edit - ClothingHandsGlovesChristmas: 3 #sunrise-edit - ClothingHandsGlovesChristmasLong: 3 #sunrise-edit + ClothingUniformTurtleneckColorWhite: 2 + ClothingUniformTurtleneckColorGrey: 2 + ClothingUniformTurtleneckColorBlack: 2 + ClothingUniformTurtleneckColorBlue: 2 + ClothingUniformTurtleneckColorDarkBlue: 2 + ClothingUniformTurtleneckColorTeal: 2 + ClothingUniformTurtleneckColorGreen: 2 + ClothingUniformTurtleneckColorDarkGreen: 2 + ClothingUniformTurtleneckColorOrange: 2 + ClothingUniformTurtleneckColorPink: 2 + ClothingUniformTurtleneckColorRed: 2 + ClothingUniformTurtleneckColorYellow: 2 + ClothingUniformTurtleneckColorPurple: 2 + ClothingUniformTurtleneckColorLightBrown: 2 + ClothingUniformTurtleneckColorBrown: 2 + ClothingUniformTurtleneckColorMaroon: 2 + ClothingUniformTurtleneckSkirtColorWhite: 2 + ClothingUniformTurtleneckSkirtColorGrey: 2 + ClothingUniformTurtleneckSkirtColorBlack: 2 + ClothingUniformTurtleneckSkirtColorBlue: 2 + ClothingUniformTurtleneckSkirtColorDarkBlue: 2 + ClothingUniformTurtleneckSkirtColorTeal: 2 + ClothingUniformTurtleneckSkirtColorGreen: 2 + ClothingUniformTurtleneckSkirtColorDarkGreen: 2 + ClothingUniformTurtleneckSkirtColorOrange: 2 + ClothingUniformTurtleneckSkirtColorPink: 2 + ClothingUniformTurtleneckSkirtColorRed: 2 + ClothingUniformTurtleneckSkirtColorYellow: 2 + ClothingUniformTurtleneckSkirtColorPurple: 2 + ClothingUniformTurtleneckSkirtColorLightBrown: 2 + ClothingUniformTurtleneckSkirtColorBrown: 2 + ClothingUniformTurtleneckSkirtColorMaroon: 2 + #sunrise-start + ClothingNeckScarfStripedCyan: 3 + ClothingNeckScarfStripedYellow: 3 + ClothingOuterChristmasSweeter: 3 + ClothingHandsGlovesChristmas: 3 + ClothingHandsGlovesChristmasLong: 3 + #sunrise-end emaggedInventory: ClothingNeckScarfStripedSyndieGreen: 3 diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/color_turtlenecks.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/color_turtlenecks.yml new file mode 100644 index 0000000000..81d9801482 --- /dev/null +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/color_turtlenecks.yml @@ -0,0 +1,491 @@ +# White Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorWhite + name: white turtleneck + description: A generic white turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + - state: trousers-inhand-left + right: + - state: inhand-right + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + - state: trousers-equipped-INNERCLOTHING + +# Grey Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorGrey + name: grey turtleneck + description: A tasteful grey turtleneck that reminds you of the good old days. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#b3b3b3" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#b3b3b3" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#b3b3b3" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#b3b3b3" + - state: trousers-equipped-INNERCLOTHING + +# Black Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorBlack + name: black turtleneck + description: A generic black turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#3f3f3f" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#3f3f3f" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#3f3f3f" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#3f3f3f" + - state: trousers-equipped-INNERCLOTHING + +# Blue Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorBlue + name: blue turtleneck + description: A generic blue turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#52aecc" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#52aecc" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#52aecc" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#52aecc" + - state: trousers-equipped-INNERCLOTHING + +# Dark Blue Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorDarkBlue + name: dark blue turtleneck + description: A generic dark blue turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#3285ba" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#3285ba" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#3285ba" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#3285ba" + - state: trousers-equipped-INNERCLOTHING + +# Teal Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorTeal + name: teal turtleneck + description: A generic teal turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#77f3b7" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#77f3b7" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#77f3b7" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#77f3b7" + - state: trousers-equipped-INNERCLOTHING + +# Green Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorGreen + name: green turtleneck + description: A generic green turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#9ed63a" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#9ed63a" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#9ed63a" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#9ed63a" + - state: trousers-equipped-INNERCLOTHING + + # Dark Green Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorDarkGreen + name: dark green turtleneck + description: A generic dark green turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#79CC26" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#79CC26" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#79CC26" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#79CC26" + - state: trousers-equipped-INNERCLOTHING + +# Orange Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorOrange + name: orange turtleneck + description: A generic orange turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#ff8c19" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#ff8c19" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#ff8c19" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#ff8c19" + - state: trousers-equipped-INNERCLOTHING + +# Pink Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorPink + name: pink turtleneck + description: A generic pink turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#ffa69b" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#ffa69b" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#ffa69b" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#ffa69b" + - state: trousers-equipped-INNERCLOTHING + +# Red Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorRed + name: red turtleneck + description: A generic red turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#eb0c07" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#eb0c07" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#eb0c07" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#eb0c07" + - state: trousers-equipped-INNERCLOTHING + +# Yellow Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorYellow + name: yellow turtleneck + description: A generic yellow turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#ffe14d" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#ffe14d" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#ffe14d" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#ffe14d" + - state: trousers-equipped-INNERCLOTHING + +# Purple Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorPurple + name: purple turtleneck + description: A generic light purple turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#9f70cc" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#9f70cc" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#9f70cc" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#9f70cc" + - state: trousers-equipped-INNERCLOTHING + +# Light Brown Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorLightBrown + name: light brown turtleneck + description: A generic light brown turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#c59431" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#c59431" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#c59431" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#c59431" + - state: trousers-equipped-INNERCLOTHING + +# Brown Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorBrown + name: brown turtleneck + description: A generic brown turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#a17229" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#a17229" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#a17229" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#a17229" + - state: trousers-equipped-INNERCLOTHING + +# Maroon Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckColorMaroon + name: maroon turtleneck + description: A generic maroon turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + layers: + - state: icon + color: "#cc295f" + - state: trousers-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#cc295f" + - state: trousers-inhand-left + right: + - state: inhand-right + color: "#cc295f" + - state: trousers-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#cc295f" + - state: trousers-equipped-INNERCLOTHING diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/color_turtlenecks_skirt.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/color_turtlenecks_skirt.yml new file mode 100644 index 0000000000..1a61e0803f --- /dev/null +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/color_turtlenecks_skirt.yml @@ -0,0 +1,491 @@ +# White Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorWhite + name: white turtleneck with skirt + description: A generic white turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + - state: skirt-inhand-left + right: + - state: inhand-right + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + - state: skirt-equipped-INNERCLOTHING + +# Grey Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorGrey + name: grey turtleneck with skirt + description: A tasteful grey turtleneck that reminds you of the good old days. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#b3b3b3" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#b3b3b3" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#b3b3b3" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#b3b3b3" + - state: skirt-equipped-INNERCLOTHING + +# Black Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorBlack + name: black turtleneck with skirt + description: A generic black turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#3f3f3f" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#3f3f3f" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#3f3f3f" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#3f3f3f" + - state: skirt-equipped-INNERCLOTHING + +# Blue Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorBlue + name: blue turtleneck with skirt + description: A generic blue turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#52aecc" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#52aecc" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#52aecc" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#52aecc" + - state: skirt-equipped-INNERCLOTHING + +# Dark Blue Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorDarkBlue + name: dark blue turtleneck with skirt + description: A generic dark blue turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#3285ba" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#3285ba" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#3285ba" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#3285ba" + - state: skirt-equipped-INNERCLOTHING + +# Teal Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorTeal + name: teal turtleneck with skirt + description: A generic teal turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#77f3b7" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#77f3b7" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#77f3b7" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#77f3b7" + - state: skirt-equipped-INNERCLOTHING + +# Green Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorGreen + name: green turtleneck with skirt + description: A generic green turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#9ed63a" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#9ed63a" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#9ed63a" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#9ed63a" + - state: skirt-equipped-INNERCLOTHING + + # Dark Green Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorDarkGreen + name: dark green turtleneck with skirt + description: A generic dark green turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#79CC26" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#79CC26" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#79CC26" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#79CC26" + - state: skirt-equipped-INNERCLOTHING + +# Orange Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorOrange + name: orange turtleneck with skirt + description: A generic orange turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#ff8c19" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#ff8c19" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#ff8c19" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#ff8c19" + - state: skirt-equipped-INNERCLOTHING + +# Pink Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorPink + name: pink turtleneck with skirt + description: A generic pink turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#ffa69b" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#ffa69b" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#ffa69b" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#ffa69b" + - state: skirt-equipped-INNERCLOTHING + +# Red Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorRed + name: red turtleneck with skirt + description: A generic red turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#eb0c07" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#eb0c07" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#eb0c07" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#eb0c07" + - state: skirt-equipped-INNERCLOTHING + +# Yellow Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorYellow + name: yellow turtleneck with skirt + description: A generic yellow turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#ffe14d" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#ffe14d" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#ffe14d" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#ffe14d" + - state: skirt-equipped-INNERCLOTHING + +# Purple Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorPurple + name: purple turtleneck with skirt + description: A generic light purple turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#9f70cc" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#9f70cc" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#9f70cc" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#9f70cc" + - state: skirt-equipped-INNERCLOTHING + +# Light Brown Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorLightBrown + name: light brown turtleneck with skirt + description: A generic light brown turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#c59431" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#c59431" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#c59431" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#c59431" + - state: skirt-equipped-INNERCLOTHING + +# Brown Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorBrown + name: brown turtleneck with skirt + description: A generic brown turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#a17229" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#a17229" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#a17229" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#a17229" + - state: skirt-equipped-INNERCLOTHING + +# Maroon Turtleneck +- type: entity + parent: ClothingUniformBase + id: ClothingUniformTurtleneckSkirtColorMaroon + name: maroon turtleneck with skirt + description: A generic maroon turtleneck with no rank markings. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + layers: + - state: icon + color: "#cc295f" + - state: skirt-icon + - type: Item + inhandVisuals: + left: + - state: inhand-left + color: "#cc295f" + - state: skirt-inhand-left + right: + - state: inhand-right + color: "#cc295f" + - state: skirt-inhand-right + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/color_turtle.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING + color: "#cc295f" + - state: skirt-equipped-INNERCLOTHING diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml index c3a9a3a143..8504925528 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml @@ -16,6 +16,7 @@ prototypes: - DrinkAbsintheGlass - DrinkAleGlass + - DrinkAlienBrainHemorrhage - DrinkAloe - DrinkAndalusia - DrinkAntifreeze @@ -32,17 +33,21 @@ - DrinkBloodyMaryGlass - DrinkBooger - DrinkBraveBullGlass + - DrinkBronxGlass - BudgetInsulsDrinkGlass - DrinkCarrotJuice - DrinkCoconutRum - DrinkChocolateGlass - DrinkCognacGlass - DrinkCosmopolitan + - DrinkCrushDepthGlass - DrinkCubaLibreGlass + - DrinkDarkandStormyGlass - DrinkDeadRumGlass - DrinkDevilsKiss - DrinkDriestMartiniGlass - DrinkDrGibbGlass + - DrinkElectricSharkGlass - DrinkErikaSurprise - DrinkFourteenLokoGlass - DrinkGargleBlasterGlass @@ -62,6 +67,9 @@ - DrinkIrishSlammer - DrinkIrishCoffeeGlass - DrinkLemonadeGlass + - DrinkJackRoseGlass + - DrinkJungleBirdGlass + - DrinkKalimotxoGlass - DrinkKiraSpecial - DrinkLongIslandIcedTeaGlass - DrinkManhattanGlass @@ -71,11 +79,13 @@ - DrinkMeadGlass - DrinkMilkshake - DrinkMojito + - DrinkMonkeyBusinessGlass - DrinkNTCahors - DrinkPainkillerGlass - DrinkPatronGlass - DrinkPinaColadaGlass - DrinkPoscaGlass + - DrinkRadlerGlass - DrinkRedMeadGlass - DrinkRewriter - DrinkRoyRogersGlass @@ -92,7 +102,9 @@ - DrinkSyndicatebomb - DrinkTequilaSunriseGlass - DrinkThreeMileIslandGlass + - DrinkTortugaGlass - DrinkToxinsSpecialGlass + - DrinkVampiroGlass - DrinkVodkaMartiniGlass - DrinkVodkaRedBool - DrinkVodkaTonicGlass diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml index 2a908f6b04..dce200d219 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml @@ -195,6 +195,22 @@ sprite: Objects/Consumable/Drinks/aleglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkAlienBrainHemorrhage + suffix: alien brain hemorrhage + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: AlienBrainHemorrhage + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/alienbrainhemorrhage.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkAlliesCocktail @@ -515,6 +531,22 @@ sprite: Objects/Consumable/Drinks/bravebullglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkBronxGlass + suffix: bronx + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Bronx + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/bronx.rsi + state: icon + - type: entity parent: DrinkGlass id: BudgetInsulsDrinkGlass @@ -669,6 +701,22 @@ - ReagentId: Cream Quantity: 30 +- type: entity + parent: DrinkGlass + id: DrinkCrushDepthGlass + suffix: crush depth + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: CrushDepth + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/crushdepth.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkCubaLibreGlass @@ -685,6 +733,22 @@ sprite: Objects/Consumable/Drinks/cubalibreglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkDarkandStormyGlass + suffix: dark and stormy + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: DarkandStormy + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/dark&stormy.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkDeadRumGlass @@ -781,6 +845,22 @@ sprite: Objects/Consumable/Drinks/dr_gibb_glass.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkElectricSharkGlass + suffix: electric shark + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: ElectricShark + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/electricshark.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkErikaSurprise @@ -1185,6 +1265,54 @@ sprite: Objects/Consumable/Drinks/coffeeliqueurglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkJackRoseGlass + suffix: jack rose + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: JackRose + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/jackrose.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkJungleBirdGlass + suffix: jungle bird + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: JungleBird + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/junglebird.rsi + state: icon + +- type: entity + parent: DrinkGlass + id: DrinkKalimotxoGlass + suffix: kalimotxo + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Kalimotxo + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/kalimotxo.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkKiraSpecial @@ -1201,6 +1329,7 @@ sprite: Objects/Consumable/Drinks/kiraspecial.rsi state: icon + - type: entity parent: DrinkGlass id: DrinkLemonadeGlass @@ -1399,6 +1528,22 @@ sprite: Objects/Consumable/Drinks/mojito.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkMonkeyBusinessGlass + suffix: monkey business + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: MonkeyBusiness + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/monkeybusiness.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkNeurotoxinGlass @@ -1575,6 +1720,22 @@ sprite: Objects/Consumable/Drinks/glass_light_yellow.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkRadlerGlass + suffix: radler + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Radler + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/radler.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkRedMeadGlass @@ -2053,6 +2214,22 @@ - ReagentId: JuiceTomato Quantity: 30 +- type: entity + parent: DrinkGlass + id: DrinkTortugaGlass + suffix: tortuga + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Tortuga + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/tortuga.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkToxinsSpecialGlass @@ -2069,6 +2246,22 @@ sprite: Objects/Consumable/Drinks/toxinsspecialglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkVampiroGlass + suffix: vampiro + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Vampiro + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/vampiro.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkVermouthGlass @@ -2317,7 +2510,7 @@ drink: maxVol: 30 reagents: - - ReagentId: Daiquiri + - ReagentId: Daiquiri Quantity: 30 - type: Icon sprite: Objects/Consumable/Drinks/daiquiri.rsi diff --git a/Resources/Prototypes/Entities/Objects/Devices/radio.yml b/Resources/Prototypes/Entities/Objects/Devices/radio.yml index 84e15878af..adf094d12e 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/radio.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/radio.yml @@ -33,6 +33,7 @@ components: - type: RadioMicrophone broadcastChannel: Security + listenRange: 1 - type: RadioSpeaker channels: - Security diff --git a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml index cb3ae3d065..2605af8019 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml @@ -32,8 +32,6 @@ components: - HumanoidAppearance - type: DisposalUnit - autoEngageEnabled: false - noUI: true blacklist: components: - HumanoidAppearance diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml index 9d04b32563..7388a814f7 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml @@ -8,6 +8,8 @@ snap: - Disposal components: + - type: Climbable + vaultable: false - type: Sprite sprite: Structures/Piping/disposal.rsi layers: @@ -29,6 +31,17 @@ map: [ "enum.DisposalUnitVisualLayers.OverlayEngaged" ] - type: Physics bodyType: Static + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.45,-0.45,0.45,0.45" + density: 55 + mask: + - TableMask + layer: + - TableLayer - type: Destructible thresholds: - trigger: @@ -116,7 +129,6 @@ graph: DisposalMachine node: mailing_unit - type: DisposalUnit - autoEngageEnabled: false whitelist: components: - Item @@ -136,6 +148,6 @@ - type: UserInterface interfaces: enum.MailingUnitUiKey.Key: - type: DisposalUnitBoundUserInterface + type: MailingUnitBoundUserInterface enum.ConfigurationUiKey.Key: type: ConfigurationBoundUserInterface diff --git a/Resources/Prototypes/Flavors/flavors.yml b/Resources/Prototypes/Flavors/flavors.yml index ffd6fe40b8..0aa9341647 100644 --- a/Resources/Prototypes/Flavors/flavors.yml +++ b/Resources/Prototypes/Flavors/flavors.yml @@ -599,6 +599,11 @@ flavorType: Complex description: flavor-complex-irish-slammer +- type: flavor + id: alienbrainhemorrhage + flavorType: Complex + description: flavor-complex-alien-brain-hemorrhage + - type: flavor id: vodkaredbool flavorType: Complex @@ -624,6 +629,11 @@ flavorType: Complex description: flavor-complex-watermelon-wakeup +- type: flavor + id: electricshark + flavorType: Complex + description: flavor-complex-electric-shark + - type: flavor id: rubberneck flavorType: Complex @@ -749,6 +759,11 @@ flavorType: Complex description: flavor-complex-coconut-rum +- type: flavor + id: darkandstormy + flavorType: Complex + description: flavor-complex-dark-and-stormy + - type: flavor id: coffeeliquor flavorType: Complex @@ -799,6 +814,11 @@ flavorType: Complex description: flavor-complex-arnold-palmer +- type: flavor + id: tortuga + flavorType: Complex + description: flavor-complex-tortuga + - type: flavor id: bluehawaiian flavorType: Complex @@ -859,6 +879,11 @@ flavorType: Complex description: flavor-complex-iced-beer +- type: flavor + id: radler + flavorType: Complex + description: flavor-complex-radler + - type: flavor id: gargleblaster flavorType: Complex @@ -894,6 +919,11 @@ flavorType: Complex description: flavor-complex-atomic-cola +- type: flavor + id: crushdepth + flavorType: Complex + description: flavor-complex-crush-depth + - type: flavor id: cubalibre flavorType: Complex @@ -904,6 +934,31 @@ flavorType: Complex description: flavor-complex-gin-tonic +- type: flavor + id: jackrose + flavorType: Complex + description: flavor-complex-jack-rose + +- type: flavor + id: junglebird + flavorType: Complex + description: flavor-complex-jungle-bird + +- type: flavor + id: kalimotxo + flavorType: Complex + description: flavor-complex-kalimotxo + +- type: flavor + id: vampiro + flavorType: Complex + description: flavor-complex-vampiro + +- type: flavor + id: bronx + flavorType: Complex + description: flavor-complex-bronx + - type: flavor id: screwdriver flavorType: Complex @@ -1049,6 +1104,11 @@ flavorType: Complex description: flavor-complex-mojito +- type: flavor + id: monkeybusiness + flavorType: Complex + description: flavor-complex-monkey-business + - type: flavor id: neurotoxin flavorType: Complex diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml index eb0ff97333..fe68441573 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml @@ -479,6 +479,21 @@ metamorphicFillBaseName: fill- metamorphicChangeColor: false +- type: reagent + id: AlienBrainHemorrhage + name: reagent-name-alien-brain-hemorrhage + parent: BaseAlcohol + desc: reagent-desc-alien-brain-hemorrhage + physicalDesc: reagent-physical-desc-creamy + flavor: alienbrainhemorrhage + color: "#FFFDD0" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/alienbrainhemorrhage.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: AlliesCocktail name: reagent-name-allies-cocktail @@ -768,6 +783,21 @@ reagent: Ethanol amount: 0.2 +- type: reagent + id: Bronx + name: reagent-name-bronx + parent: BaseAlcohol + desc: reagent-desc-bronx + physicalDesc: reagent-physical-desc-strong-smelling + flavor: bronx + color: "#d68829" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/bronx.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: CoconutRum name: reagent-name-coconut-rum @@ -814,6 +844,21 @@ reagent: Ethanol amount: 0.15 +- type: reagent + id: CrushDepth + name: reagent-name-crush-depth + parent: BaseAlcohol + desc: reagent-desc-crush-depth + physicalDesc: reagent-physical-desc-cloudy + flavor: crushdepth + color: "#0a0a33" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/crushdepth.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: CubaLibre name: reagent-name-cuba-libre @@ -838,6 +883,21 @@ amount: 0.07 fizziness: 0.2 +- type: reagent + id: DarkandStormy + name: reagent-name-dark-and-stormy + parent: BaseAlcohol + desc: reagent-desc-dark-and-stormy + physicalDesc: reagent-physical-desc-bubbly + flavor: darkandstormy + color: "#cf7f17" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/dark&stormy.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: DemonsBlood name: reagent-name-demons-blood @@ -924,6 +984,21 @@ reagent: Ethanol amount: 0.15 +- type: reagent + id: ElectricShark + name: reagent-name-electric-shark + parent: BaseAlcohol + desc: reagent-desc-electric-shark + physicalDesc: reagent-physical-desc-tropical + flavor: electricshark + color: "#3097cf" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/electricshark.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: ErikaSurprise name: reagent-name-erika-surprise @@ -1158,6 +1233,51 @@ reagent: Ethanol amount: 0.15 +- type: reagent + id: JackRose + name: reagent-name-jack-rose + parent: BaseAlcohol + desc: reagent-desc-jack-rose + physicalDesc: reagent-physical-desc-tart + flavor: jackrose + color: "#f53b3b" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/jackrose.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + +- type: reagent + id: JungleBird + name: reagent-name-jungle-bird + parent: BaseAlcohol + desc: reagent-desc-jungle-bird + physicalDesc: reagent-physical-desc-tropical + flavor: junglebird + color: "#f27c3d" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/junglebird.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + +- type: reagent + id: Kalimotxo + name: reagent-name-kalimotxo + parent: BaseAlcohol + desc: reagent-desc-kalimotxo + physicalDesc: reagent-physical-desc-bubbly + flavor: kalimotxo + color: "#360606" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/kalimotxo.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: LongIslandIcedTea name: reagent-name-long-island-iced-tea @@ -1297,6 +1417,21 @@ metamorphicChangeColor: false fizziness: 0.3 +- type: reagent + id: MonkeyBusiness + name: reagent-name-monkey-business + parent: BaseAlcohol + desc: reagent-desc-monkey-business + physicalDesc: reagent-physical-desc-tart + flavor: monkeybusiness + color: "#d6b929" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/monkeybusiness.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: Moonshine name: reagent-name-moonshine @@ -1441,6 +1576,21 @@ reagent: Ethanol amount: 0.2 +- type: reagent + id: Radler + name: reagent-name-radler + parent: BaseAlcohol + desc: reagent-desc-radler + physicalDesc: reagent-physical-desc-citric + flavor: radler + color: "#edff2b" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/radler.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: Sbiten name: reagent-name-sbiten @@ -1671,6 +1821,21 @@ metamorphicFillBaseName: fill- metamorphicChangeColor: false +- type: reagent + id: Vampiro + name: reagent-name-vampiro + parent: BaseAlcohol + desc: reagent-desc-vampiro + physicalDesc: reagent-physical-desc-spicy + flavor: vampiro + color: "#b51b1b" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/vampiro.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + - type: reagent id: VodkaMartini name: reagent-name-vodka-martini diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml b/Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml index 21e53910c5..78177927cf 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml @@ -670,3 +670,18 @@ - !type:OrganType type: Dwarf shouldHave: false + +- type: reagent + id: Tortuga + name: reagent-name-tortuga + parent: BaseDrink + desc: reagent-desc-tortuga + physicalDesc: reagent-physical-desc-sweet + flavor: tortuga + color: "#1c8c40" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/tortuga.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false diff --git a/Resources/Prototypes/Recipes/Reactions/drinks.yml b/Resources/Prototypes/Recipes/Reactions/drinks.yml index b307166aa8..8cc2da8623 100644 --- a/Resources/Prototypes/Recipes/Reactions/drinks.yml +++ b/Resources/Prototypes/Recipes/Reactions/drinks.yml @@ -8,6 +8,18 @@ products: AcidSpit: 3 +- type: reaction + id: AlienBrainHemorrhage + reactants: + IrishCream: + amount: 1 + BlueCuracao: + amount: 1 + Grenadine: + amount: 1 + products: + AlienBrainHemorrhage: 3 + - type: reaction id: AlliesCocktail requiredMixerCategories: @@ -238,6 +250,20 @@ products: BraveBull: 3 +- type: reaction + id: Bronx + requiredMixerCategories: + - Shake + reactants: + Gin: + amount: 1 + Vermouth: + amount: 1 + JuiceOrange: + amount: 1 + products: + Bronx: 3 + - type: reaction id: CafeLatte reactants: @@ -282,6 +308,16 @@ products: CreamOfCoconut: 3 +- type: reaction + id: CrushDepth + reactants: + RootBeerFloat: + amount: 1 + Rum: + amount: 1 + products: + CrushDepth: 2 + - type: reaction id: CubaLibre reactants: @@ -292,6 +328,16 @@ products: CubaLibre: 3 +- type: reaction + id: DarkandStormy + reactants: + SolDry: + amount: 1 + Rum: + amount: 1 + products: + DarkandStormy: 2 + - type: reaction id: DemonsBlood requiredMixerCategories: @@ -352,6 +398,20 @@ products: DriestMartini: 2 +- type: reaction + id: ElectricShark + requiredMixerCategories: + - Shake + reactants: + DarkandStormy: + amount: 4 + BlueCuracao: + amount: 1 + JuicePineapple: + amount: 1 + products: + ElectricShark: 6 + - type: reaction id: ErikaSurprise requiredMixerCategories: @@ -598,6 +658,48 @@ products: IrishCream: 3 +- type: reaction + id: JackRose + requiredMixerCategories: + - Shake + reactants: + JuiceApple: + amount: 1 + Cognac: + amount: 1 + Grenadine: + amount: 1 + JuiceLemon: + amount: 1 + products: + JackRose: 4 + +- type: reaction + id: JungleBird + requiredMixerCategories: + - Shake + reactants: + Rum: + amount: 3 + JuicePineapple: + amount: 1 + Grenadine: + amount: 1 + JuiceLime: + amount: 1 + products: + JungleBird: 6 + +- type: reaction + id: Kalimotxo + reactants: + Cola: + amount: 1 + Wine: + amount: 1 + products: + Kalimotxo: 2 + - type: reaction id: KiraSpecial requiredMixerCategories: @@ -737,6 +839,22 @@ products: Mojito: 4 +- type: reaction + id: MonkeyBusiness + requiredMixerCategories: + - Shake + reactants: + Gin: + amount: 1 + JuiceOrange: + amount: 1 + Grenadine: + amount: 1 + Absinthe: + amount: 1 + products: + MonkeyBusiness: 4 + - type: reaction id: Moonshine reactants: @@ -838,6 +956,16 @@ products: Posca: 3 +- type: reaction + id: Radler + reactants: + Lemonade: + amount: 1 + Beer: + amount: 1 + products: + Radler: 2 + - type: reaction id: RedMead reactants: @@ -1041,6 +1169,18 @@ products: ThreeMileIsland: 10 +- type: reaction + id: Tortuga + requiredMixerCategories: + - Stir + reactants: + IcedTea: + amount: 1 + Sugar: + amount: 1 + products: + Tortuga: 2 + - type: reaction id: ToxinsSpecial requiredMixerCategories: @@ -1055,6 +1195,22 @@ products: ToxinsSpecial: 5 +- type: reaction + id: Vampiro + requiredMixerCategories: + - Shake + reactants: + TequilaSunrise: + amount: 3 + BloodyMary: + amount: 1 + Hotsauce: + amount: 1 + LemonLime: + amount: 1 + products: + Vampiro: 6 + - type: reaction id: VodkaMartini requiredMixerCategories: @@ -1221,7 +1377,7 @@ amount: 1 products: Cola: 4 - + - type: reaction id: Caipirinha requiredMixerCategories: diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/equipped-INNERCLOTHING.png new file mode 100644 index 0000000000..30ec8b9d59 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/icon.png new file mode 100644 index 0000000000..1194286cc5 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/inhand-left.png new file mode 100644 index 0000000000..7d8c952aa0 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/inhand-right.png new file mode 100644 index 0000000000..c0da296e64 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/meta.json new file mode 100644 index 0000000000..d4dc27c853 --- /dev/null +++ b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/meta.json @@ -0,0 +1,41 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Derived from qmturtleneck sprite from beestation at commit https://github.com/BeeStation/BeeStation-Hornet/commit/a11e7468ca552cfc97c9164c69ccdafff09e794c and modified by Emisse, also modified by Ko4erga", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-INNERCLOTHING", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "skirt-icon" + }, + { + "name": "skirt-equipped-INNERCLOTHING", + "directions": 4 + }, + { + "name": "skirt-inhand-left", + "directions": 4 + }, + { + "name": "skirt-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-equipped-INNERCLOTHING.png new file mode 100644 index 0000000000..4ed406823a Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-icon.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-icon.png new file mode 100644 index 0000000000..9516069cb3 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-inhand-left.png new file mode 100644 index 0000000000..74b28bdc7b Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-inhand-left.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-inhand-right.png new file mode 100644 index 0000000000..f355445440 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/color_turtle.rsi/skirt-inhand-right.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/equipped-INNERCLOTHING.png new file mode 100644 index 0000000000..30ec8b9d59 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/icon.png new file mode 100644 index 0000000000..1194286cc5 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/inhand-left.png new file mode 100644 index 0000000000..7d8c952aa0 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/inhand-right.png new file mode 100644 index 0000000000..c0da296e64 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/meta.json new file mode 100644 index 0000000000..530c661f35 --- /dev/null +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/meta.json @@ -0,0 +1,41 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Derived from qmturtleneck sprite from beestation at commit https://github.com/BeeStation/BeeStation-Hornet/commit/a11e7468ca552cfc97c9164c69ccdafff09e794c and modified by Emisse, also modified by Ko4erga", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-INNERCLOTHING", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "trousers-icon" + }, + { + "name": "trousers-equipped-INNERCLOTHING", + "directions": 4 + }, + { + "name": "trousers-inhand-left", + "directions": 4 + }, + { + "name": "trousers-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-equipped-INNERCLOTHING.png new file mode 100644 index 0000000000..bccf027039 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-icon.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-icon.png new file mode 100644 index 0000000000..c3d1c9d611 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-inhand-left.png new file mode 100644 index 0000000000..4b9e806da8 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-inhand-left.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-inhand-right.png new file mode 100644 index 0000000000..2b5979d70d Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/color_turtle.rsi/trousers-inhand-right.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-1.png new file mode 100644 index 0000000000..735ad356e8 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-2.png new file mode 100644 index 0000000000..c17e37680e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-3.png new file mode 100644 index 0000000000..1852a05e35 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-4.png new file mode 100644 index 0000000000..f29fe70e8b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-5.png new file mode 100644 index 0000000000..ec670c6cfa Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/icon.png new file mode 100644 index 0000000000..111507b00b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/icon_empty.png new file mode 100644 index 0000000000..2e029295f8 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/meta.json new file mode 100644 index 0000000000..fb5566d3dc --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/alienbrainhemorrhage.rsi/meta.json @@ -0,0 +1,34 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-1.png new file mode 100644 index 0000000000..7c10712880 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-2.png new file mode 100644 index 0000000000..adaedaca73 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-3.png new file mode 100644 index 0000000000..6e3e63da2e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-4.png new file mode 100644 index 0000000000..88d25fbe7b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/icon.png new file mode 100644 index 0000000000..d56aa94afc Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/icon_empty.png new file mode 100644 index 0000000000..bfb6c282c0 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/meta.json new file mode 100644 index 0000000000..52c392be67 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/bronx.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-1.png new file mode 100644 index 0000000000..41520971b1 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-2.png new file mode 100644 index 0000000000..aef4008182 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-3.png new file mode 100644 index 0000000000..ef796be597 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-4.png new file mode 100644 index 0000000000..9963457a6e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-5.png new file mode 100644 index 0000000000..5a83559b9f Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/icon.png new file mode 100644 index 0000000000..64cdd3eb8c Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/icon_empty.png new file mode 100644 index 0000000000..14bad18f6c Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/meta.json new file mode 100644 index 0000000000..fb5566d3dc --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/crushdepth.rsi/meta.json @@ -0,0 +1,34 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-1.png new file mode 100644 index 0000000000..ca76f8d344 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-2.png new file mode 100644 index 0000000000..aefd7e17cf Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-3.png new file mode 100644 index 0000000000..d9008407c6 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-4.png new file mode 100644 index 0000000000..1216e99cb6 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-5.png new file mode 100644 index 0000000000..3f12cd164b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/icon.png new file mode 100644 index 0000000000..90cd2bf570 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/icon_empty.png new file mode 100644 index 0000000000..8ad26bfc2e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/meta.json new file mode 100644 index 0000000000..fb5566d3dc --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/dark&stormy.rsi/meta.json @@ -0,0 +1,34 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-1.png new file mode 100644 index 0000000000..7fd25a8b79 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-2.png new file mode 100644 index 0000000000..35985ab459 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-3.png new file mode 100644 index 0000000000..c2ed2bbdd3 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-4.png new file mode 100644 index 0000000000..ef1da7eb09 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-5.png new file mode 100644 index 0000000000..6d7ec355bc Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/icon.png new file mode 100644 index 0000000000..bddb1cd6a9 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/icon_empty.png new file mode 100644 index 0000000000..5ae82dc839 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/meta.json new file mode 100644 index 0000000000..fb5566d3dc --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/electricshark.rsi/meta.json @@ -0,0 +1,34 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-1.png new file mode 100644 index 0000000000..e91fcca8dc Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-2.png new file mode 100644 index 0000000000..6b07b1de3a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-3.png new file mode 100644 index 0000000000..58ac6675e5 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-4.png new file mode 100644 index 0000000000..7d452d9314 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/icon.png new file mode 100644 index 0000000000..b89e6ffd22 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/icon_empty.png new file mode 100644 index 0000000000..5607707f40 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/meta.json new file mode 100644 index 0000000000..52c392be67 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/jackrose.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-1.png new file mode 100644 index 0000000000..85821df5d9 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-2.png new file mode 100644 index 0000000000..44e1ca3e35 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-3.png new file mode 100644 index 0000000000..802d422c3f Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-4.png new file mode 100644 index 0000000000..5c57ae9737 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/icon.png new file mode 100644 index 0000000000..b63c467af2 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/icon_empty.png new file mode 100644 index 0000000000..c21ad2a11e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/meta.json new file mode 100644 index 0000000000..52c392be67 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/junglebird.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-1.png new file mode 100644 index 0000000000..a48cfa933c Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-2.png new file mode 100644 index 0000000000..a41f789084 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-3.png new file mode 100644 index 0000000000..dba0ef1770 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-4.png new file mode 100644 index 0000000000..47ddc76e44 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-5.png new file mode 100644 index 0000000000..9ba296aae2 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/icon.png new file mode 100644 index 0000000000..237652ba74 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/icon_empty.png new file mode 100644 index 0000000000..e2caac82a4 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/meta.json new file mode 100644 index 0000000000..fb5566d3dc --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/kalimotxo.rsi/meta.json @@ -0,0 +1,34 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-1.png new file mode 100644 index 0000000000..9fdd9db4c4 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-2.png new file mode 100644 index 0000000000..e1fd43182e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-3.png new file mode 100644 index 0000000000..8b802c67fb Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-4.png new file mode 100644 index 0000000000..2ea71b9702 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/icon.png new file mode 100644 index 0000000000..842091e98d Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/icon_empty.png new file mode 100644 index 0000000000..ea020e72a8 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/meta.json new file mode 100644 index 0000000000..52c392be67 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/monkeybusiness.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-1.png new file mode 100644 index 0000000000..030a2ea926 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-2.png new file mode 100644 index 0000000000..b5e942dc85 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-3.png new file mode 100644 index 0000000000..c94a2809b0 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-4.png new file mode 100644 index 0000000000..9e44a20822 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-5.png new file mode 100644 index 0000000000..72396bb28a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/icon.png new file mode 100644 index 0000000000..dead0ec31d Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/icon_empty.png new file mode 100644 index 0000000000..efa22b2808 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/meta.json new file mode 100644 index 0000000000..fb5566d3dc --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/radler.rsi/meta.json @@ -0,0 +1,34 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-1.png new file mode 100644 index 0000000000..2eb13c4fcb Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-2.png new file mode 100644 index 0000000000..2b64762c11 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-3.png new file mode 100644 index 0000000000..d6334a476c Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-4.png new file mode 100644 index 0000000000..dda1d511aa Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/icon.png new file mode 100644 index 0000000000..0902145f2b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/icon_empty.png new file mode 100644 index 0000000000..433a627e84 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/meta.json new file mode 100644 index 0000000000..52c392be67 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/tortuga.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-1.png new file mode 100644 index 0000000000..596d98eef1 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-2.png new file mode 100644 index 0000000000..9b3f32db5e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-3.png new file mode 100644 index 0000000000..50afc91678 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-4.png new file mode 100644 index 0000000000..a47a7fd0a9 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/icon.png new file mode 100644 index 0000000000..f99adfbb1a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/icon_empty.png new file mode 100644 index 0000000000..5c537f1f7d Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/meta.json new file mode 100644 index 0000000000..52c392be67 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/vampiro.rsi/meta.json @@ -0,0 +1,31 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SharkSnake98 on Github", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/RobustToolbox b/RobustToolbox index b146b1b82c..191d7ab81c 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit b146b1b82cda98f9445e7a9e2146e569e6cf4197 +Subproject commit 191d7ab81c3693503bc9f483c5829228d9cb57cf