diff --git a/Content.Benchmarks/ComponentManagerGetAllComponents.cs b/Content.Benchmarks/ComponentManagerGetAllComponents.cs index 46e6150f1e..ec8ae2f3d9 100644 --- a/Content.Benchmarks/ComponentManagerGetAllComponents.cs +++ b/Content.Benchmarks/ComponentManagerGetAllComponents.cs @@ -79,7 +79,7 @@ namespace Content.Benchmarks { var count = 0; - foreach (var _ in _componentManager.EntityQuery()) + foreach (var _ in _componentManager.EntityQuery(true)) { count += 1; } diff --git a/Content.Client/Animations/ReusableAnimations.cs b/Content.Client/Animations/ReusableAnimations.cs new file mode 100644 index 0000000000..5b93efe5ae --- /dev/null +++ b/Content.Client/Animations/ReusableAnimations.cs @@ -0,0 +1,56 @@ +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Client.GameObjects.Components.Animations; +using Robust.Shared.Animations; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.Log; +using Robust.Shared.Map; +using Robust.Shared.Maths; +using System; + +namespace Content.Client.Animations +{ + public static class ReusableAnimations + { + + public static void AnimateEntityPickup(IEntity entity, EntityCoordinates initialPosition, Vector2 finalPosition) + { + var animatableClone = entity.EntityManager.SpawnEntity("clientsideclone", initialPosition); + animatableClone.Name = entity.Name; + + if(!entity.TryGetComponent(out SpriteComponent sprite0)) + { + Logger.Error($"Entity ({0}) couldn't be animated for pickup since it doesn't have a {1}!", entity.Name, nameof(SpriteComponent)); + return; + } + var sprite = animatableClone.GetComponent(); + sprite.CopyFrom(sprite0); + + var animations = animatableClone.GetComponent(); + animations.AnimationCompleted += (s) => { + animatableClone.Delete(); + }; + + animations.Play(new Animation + { + Length = TimeSpan.FromMilliseconds(125), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(ITransformComponent), + Property = nameof(ITransformComponent.WorldPosition), + InterpolationMode = AnimationInterpolationMode.Linear, + KeyFrames = + { + new AnimationTrackComponentProperty.KeyFrame(initialPosition.Position, 0), + new AnimationTrackComponentProperty.KeyFrame(finalPosition, 0.125f) + } + } + } + }, "fancy_pickup_anim"); + } + + } +} diff --git a/Content.Client/Chat/ChatManager.cs b/Content.Client/Chat/ChatManager.cs index 96910110f8..490bdd7a0c 100644 --- a/Content.Client/Chat/ChatManager.cs +++ b/Content.Client/Chat/ChatManager.cs @@ -78,7 +78,7 @@ namespace Content.Client.Chat private ChatChannel _filteredChannels; [Dependency] private readonly IClientNetManager _netManager = default!; - [Dependency] private readonly IClientConsole _console = default!; + [Dependency] private readonly IClientConsoleHost _consoleHost = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IEyeManager _eyeManager = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; @@ -255,7 +255,7 @@ namespace Content.Client.Chat { // run locally var conInput = text.Substring(1); - _console.ProcessCommand(conInput); + _consoleHost.ExecuteCommand(conInput); break; } case OOCAlias: @@ -263,7 +263,7 @@ namespace Content.Client.Chat var conInput = text.Substring(1); if (string.IsNullOrWhiteSpace(conInput)) return; - _console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\""); + _consoleHost.ExecuteCommand($"ooc \"{CommandParsing.Escape(conInput)}\""); break; } case AdminChatAlias: @@ -273,11 +273,11 @@ namespace Content.Client.Chat return; if (_groupController.CanCommand("asay")) { - _console.ProcessCommand($"asay \"{CommandParsing.Escape(conInput)}\""); + _consoleHost.ExecuteCommand($"asay \"{CommandParsing.Escape(conInput)}\""); } else { - _console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\""); + _consoleHost.ExecuteCommand($"ooc \"{CommandParsing.Escape(conInput)}\""); } break; @@ -287,7 +287,7 @@ namespace Content.Client.Chat var conInput = text.Substring(1); if (string.IsNullOrWhiteSpace(conInput)) return; - _console.ProcessCommand($"me \"{CommandParsing.Escape(conInput)}\""); + _consoleHost.ExecuteCommand($"me \"{CommandParsing.Escape(conInput)}\""); break; } default: @@ -295,7 +295,7 @@ namespace Content.Client.Chat var conInput = _currentChatBox?.DefaultChatFormat != null ? string.Format(_currentChatBox.DefaultChatFormat, CommandParsing.Escape(text)) : text; - _console.ProcessCommand(conInput); + _consoleHost.ExecuteCommand(conInput); break; } } diff --git a/Content.Client/ClientNotifyManager.cs b/Content.Client/ClientNotifyManager.cs index 847417aac5..818c0829b1 100644 --- a/Content.Client/ClientNotifyManager.cs +++ b/Content.Client/ClientNotifyManager.cs @@ -4,12 +4,12 @@ using System.Collections.Generic; using Content.Client.Interfaces; using Content.Client.UserInterface.Stylesheets; using Content.Shared; -using Robust.Client.Interfaces.Console; using Robust.Client.Interfaces.Graphics.ClientEye; using Robust.Client.Interfaces.Input; using Robust.Client.Interfaces.UserInterface; using Robust.Client.Player; using Robust.Client.UserInterface.Controls; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; @@ -168,12 +168,11 @@ namespace Content.Client public string Description => ""; public string Help => ""; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var arg = args[0]; var mgr = IoCManager.Resolve(); mgr.PopupMessage(arg); - return false; } } } diff --git a/Content.Client/Commands/AtmosDebugCommands.cs b/Content.Client/Commands/AtmosDebugCommands.cs index 823d1183e7..10f6856f01 100644 --- a/Content.Client/Commands/AtmosDebugCommands.cs +++ b/Content.Client/Commands/AtmosDebugCommands.cs @@ -1,9 +1,9 @@ using JetBrains.Annotations; -using Robust.Client.Interfaces.Console; using Content.Client.GameObjects.EntitySystems; using Robust.Shared.GameObjects.Systems; using Content.Shared.Atmos; using System; +using Robust.Shared.Console; namespace Content.Client.Commands { @@ -13,32 +13,31 @@ namespace Content.Client.Commands public string Command => "atvrange"; public string Description => "Sets the atmos debug range (as two floats, start [red] and end [blue])"; public string Help => "atvrange "; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 2) { - console.AddLine(Help); - return false; + shell.WriteLine(Help); + return; } if (!float.TryParse(args[0], out var xStart)) { - console.AddLine("Bad float START"); - return false; + shell.WriteLine("Bad float START"); + return; } if (!float.TryParse(args[1], out var xEnd)) { - console.AddLine("Bad float END"); - return false; + shell.WriteLine("Bad float END"); + return; } if (xStart == xEnd) { - console.AddLine("Scale cannot be zero, as this would cause a division by zero in AtmosDebugOverlay."); - return false; + shell.WriteLine("Scale cannot be zero, as this would cause a division by zero in AtmosDebugOverlay."); + return; } var sys = EntitySystem.Get(); sys.CfgBase = xStart; sys.CfgScale = xEnd - xStart; - return false; } } @@ -48,17 +47,17 @@ namespace Content.Client.Commands public string Command => "atvmode"; public string Description => "Sets the atmos debug mode. This will automatically reset the scale."; public string Help => "atvmode []"; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 1) { - console.AddLine(Help); - return false; + shell.WriteLine(Help); + return; } if (!Enum.TryParse(args[0], out var xMode)) { - console.AddLine("Invalid mode"); - return false; + shell.WriteLine("Invalid mode"); + return; } int xSpecificGas = 0; float xBase = 0; @@ -67,21 +66,21 @@ namespace Content.Client.Commands { if (args.Length != 2) { - console.AddLine("A target gas must be provided for this mode."); - return false; + shell.WriteLine("A target gas must be provided for this mode."); + return; } if (!AtmosCommandUtils.TryParseGasID(args[1], out xSpecificGas)) { - console.AddLine("Gas ID not parsable or out of range."); - return false; + shell.WriteLine("Gas ID not parsable or out of range."); + return; } } else { if (args.Length != 1) { - console.AddLine("No further information is required for this mode."); - return false; + shell.WriteLine("No further information is required for this mode."); + return; } if (xMode == AtmosDebugOverlayMode.Temperature) { @@ -95,7 +94,6 @@ namespace Content.Client.Commands sys.CfgSpecificGas = xSpecificGas; sys.CfgBase = xBase; sys.CfgScale = xScale; - return false; } } @@ -105,21 +103,20 @@ namespace Content.Client.Commands public string Command => "atvcbm"; public string Description => "Changes from red/green/blue to greyscale"; public string Help => "atvcbm "; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 1) { - console.AddLine(Help); - return false; + shell.WriteLine(Help); + return; } if (!bool.TryParse(args[0], out var xFlag)) { - console.AddLine("Invalid flag"); - return false; + shell.WriteLine("Invalid flag"); + return; } var sys = EntitySystem.Get(); sys.CfgCBM = xFlag; - return false; } } } diff --git a/Content.Client/Commands/CreditsCommand.cs b/Content.Client/Commands/CreditsCommand.cs index 47643b11ac..f3fa57e85e 100644 --- a/Content.Client/Commands/CreditsCommand.cs +++ b/Content.Client/Commands/CreditsCommand.cs @@ -1,6 +1,6 @@ using Content.Client.UserInterface; using JetBrains.Annotations; -using Robust.Client.Interfaces.Console; +using Robust.Shared.Console; namespace Content.Client.Commands { @@ -11,10 +11,9 @@ namespace Content.Client.Commands public string Description => "Opens the credits window"; public string Help => "credits"; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { new CreditsWindow().Open(); - return false; } } } diff --git a/Content.Client/Commands/DebugAiCommand.cs b/Content.Client/Commands/DebugAiCommand.cs index 065da01bab..ddaadc153d 100644 --- a/Content.Client/Commands/DebugAiCommand.cs +++ b/Content.Client/Commands/DebugAiCommand.cs @@ -1,6 +1,6 @@ using Content.Client.GameObjects.EntitySystems.AI; using JetBrains.Annotations; -using Robust.Client.Interfaces.Console; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; namespace Content.Client.Commands @@ -16,12 +16,13 @@ namespace Content.Client.Commands public string Description => "Handles all tooltip debugging above AI mobs"; public string Help => "debugai [hide/paths/thonk]"; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { #if DEBUG if (args.Length < 1) { - return true; + shell.RemoteExecuteCommand(argStr); + return; } var anyAction = false; @@ -50,9 +51,10 @@ namespace Content.Client.Commands } } - return !anyAction; + if(!anyAction) + shell.RemoteExecuteCommand(argStr); #else - return true; + shell.RemoteExecuteCommand(argStr); #endif } } diff --git a/Content.Client/Commands/DebugCommands.cs b/Content.Client/Commands/DebugCommands.cs index aa9eef2a94..15879deece 100644 --- a/Content.Client/Commands/DebugCommands.cs +++ b/Content.Client/Commands/DebugCommands.cs @@ -1,9 +1,10 @@ +using System; using Content.Client.GameObjects.Components; using Content.Client.GameObjects.EntitySystems; using Content.Client.Interfaces; using Content.Shared.GameObjects; -using Robust.Client.Interfaces.Console; using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -17,12 +18,10 @@ namespace Content.Client.Commands public string Description => "Toggles visibility of markers such as spawn points."; public string Help => ""; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { EntitySystem.Get() .MarkersVisible ^= true; - - return false; } } @@ -33,12 +32,10 @@ namespace Content.Client.Commands public string Description => "Makes entities below the floor always visible."; public string Help => $"Usage: {Command}"; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { EntitySystem.Get() .EnableAll ^= true; - - return false; } } @@ -49,13 +46,13 @@ namespace Content.Client.Commands public string Description => "Makes entities below the floor always visible until the client is restarted."; public string Help => $"Usage: {Command}"; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { EntitySystem.Get() .EnableAll = true; var components = IoCManager.Resolve().ComponentManager - .EntityQuery(); + .EntityQuery(true); foreach (var component in components) { @@ -64,8 +61,6 @@ namespace Content.Client.Commands sprite.DrawDepth = (int) DrawDepth.Overlays; } } - - return false; } } @@ -75,14 +70,12 @@ namespace Content.Client.Commands public string Description => "Send a notify client side."; public string Help => "notify "; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var message = args[0]; var notifyManager = IoCManager.Resolve(); notifyManager.PopupMessage(message); - - return false; } } @@ -92,18 +85,18 @@ namespace Content.Client.Commands public string Description => "Creates and teleports you to a new uninitialized map for mapping."; public string Help => $"Usage: {Command} / {Command} "; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length == 0) { - console.AddLine(Help); - return false; + shell.WriteLine(Help); + return; } - console.Commands["togglelight"].Execute(console); - console.Commands["showsubfloorforever"].Execute(console); + shell.ConsoleHost.RegisteredCommands["togglelight"].Execute(shell, string.Empty, Array.Empty()); + shell.ConsoleHost.RegisteredCommands["showsubfloorforever"].Execute(shell, string.Empty, Array.Empty()); - return true; + shell.RemoteExecuteCommand(argStr); } } } diff --git a/Content.Client/Commands/DebugPathfindingCommand.cs b/Content.Client/Commands/DebugPathfindingCommand.cs index 9c79bec8e7..0d6135abbb 100644 --- a/Content.Client/Commands/DebugPathfindingCommand.cs +++ b/Content.Client/Commands/DebugPathfindingCommand.cs @@ -1,6 +1,6 @@ using Content.Client.GameObjects.EntitySystems.AI; using JetBrains.Annotations; -using Robust.Client.Interfaces.Console; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; namespace Content.Client.Commands @@ -13,12 +13,13 @@ namespace Content.Client.Commands public string Description => "Toggles visibility of pathfinding debuggers."; public string Help => "pathfinder [hide/nodes/routes/graph/regioncache/regions]"; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { #if DEBUG if (args.Length < 1) { - return true; + shell.RemoteExecuteCommand(argStr); + return; } var anyAction = false; @@ -63,9 +64,10 @@ namespace Content.Client.Commands } } - return !anyAction; + if(!anyAction) + shell.RemoteExecuteCommand(argStr); #else - return true; + shell.RemoteExecuteCommand(argStr); #endif } } diff --git a/Content.Client/Commands/HideMechanismsCommand.cs b/Content.Client/Commands/HideMechanismsCommand.cs index 7570055038..bbe5d9f769 100644 --- a/Content.Client/Commands/HideMechanismsCommand.cs +++ b/Content.Client/Commands/HideMechanismsCommand.cs @@ -1,7 +1,7 @@ using Content.Shared.GameObjects.Components.Body.Mechanism; using Robust.Client.Console; using Robust.Client.GameObjects; -using Robust.Client.Interfaces.Console; +using Robust.Shared.Console; using Robust.Shared.Containers; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -14,10 +14,10 @@ namespace Content.Client.Commands public string Description => $"Reverts the effects of {ShowMechanismsCommand.CommandName}"; public string Help => $"{Command}"; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var componentManager = IoCManager.Resolve(); - var mechanisms = componentManager.EntityQuery(); + var mechanisms = componentManager.EntityQuery(true); foreach (var mechanism in mechanisms) { @@ -41,9 +41,7 @@ namespace Content.Client.Commands } } - IoCManager.Resolve().ProcessCommand("hidecontainedcontext"); - - return false; + IoCManager.Resolve().ExecuteCommand("hidecontainedcontext"); } } } diff --git a/Content.Client/Commands/ShowMechanismsCommand.cs b/Content.Client/Commands/ShowMechanismsCommand.cs index 86e18c33a9..85ab4583a4 100644 --- a/Content.Client/Commands/ShowMechanismsCommand.cs +++ b/Content.Client/Commands/ShowMechanismsCommand.cs @@ -1,7 +1,7 @@ using Content.Shared.GameObjects.Components.Body.Mechanism; using Robust.Client.Console; using Robust.Client.GameObjects; -using Robust.Client.Interfaces.Console; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -16,10 +16,10 @@ namespace Content.Client.Commands public string Description => "Makes mechanisms visible, even when they shouldn't be."; public string Help => $"{Command}"; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var componentManager = IoCManager.Resolve(); - var mechanisms = componentManager.EntityQuery(); + var mechanisms = componentManager.EntityQuery(true); foreach (var mechanism in mechanisms) { @@ -29,9 +29,7 @@ namespace Content.Client.Commands } } - IoCManager.Resolve().ProcessCommand("showcontainedcontext"); - - return false; + IoCManager.Resolve().ExecuteCommand("showcontainedcontext"); } } } diff --git a/Content.Client/Commands/ToggleOutlineCommand.cs b/Content.Client/Commands/ToggleOutlineCommand.cs index ca96762eac..af7aa9e80e 100644 --- a/Content.Client/Commands/ToggleOutlineCommand.cs +++ b/Content.Client/Commands/ToggleOutlineCommand.cs @@ -1,5 +1,5 @@ using Content.Shared; -using Robust.Client.Interfaces.Console; +using Robust.Shared.Console; using Robust.Shared.Interfaces.Configuration; using Robust.Shared.IoC; @@ -13,16 +13,14 @@ namespace Content.Client.Commands public string Help => ""; - public bool Execute(IDebugConsole console, params string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var configurationManager = IoCManager.Resolve(); var cvar = CCVars.OutlineEnabled; var old = configurationManager.GetCVar(cvar); configurationManager.SetCVar(cvar, !old); - console.AddLine($"Draw outlines set to: {configurationManager.GetCVar(cvar)}"); - - return false; + shell.WriteLine($"Draw outlines set to: {configurationManager.GetCVar(cvar)}"); } } } diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 23c3612739..a9b1309d5c 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -13,6 +13,7 @@ using Content.Client.StationEvents; using Content.Client.UserInterface; using Content.Client.UserInterface.AdminMenu; using Content.Client.UserInterface.Stylesheets; +using Content.Client.Graphics.Overlays; using Content.Shared.Actions; using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components.Cargo; @@ -149,7 +150,12 @@ namespace Content.Client IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); - IoCManager.Resolve().AddOverlay(new ParallaxOverlay()); + var overlayMgr = IoCManager.Resolve(); + overlayMgr.AddOverlay(new ParallaxOverlay()); + overlayMgr.AddOverlay(new GradientCircleMaskOverlay()); + overlayMgr.AddOverlay(new CircleMaskOverlay()); + overlayMgr.AddOverlay(new FlashOverlay()); + overlayMgr.AddOverlay(new RadiationPulseOverlay()); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); diff --git a/Content.Client/EscapeMenuOwner.cs b/Content.Client/EscapeMenuOwner.cs index b57a67653d..1f8de2f5b6 100644 --- a/Content.Client/EscapeMenuOwner.cs +++ b/Content.Client/EscapeMenuOwner.cs @@ -1,4 +1,4 @@ -using Content.Client.State; +using Content.Client.State; using Content.Client.UserInterface; using Robust.Client.Console; using Robust.Client.Interfaces.Input; @@ -12,7 +12,7 @@ namespace Content.Client { internal sealed class EscapeMenuOwner : IEscapeMenuOwner { - [Dependency] private readonly IClientConsole _clientConsole = default!; + [Dependency] private readonly IClientConsoleHost _consoleHost = default!; [Dependency] private readonly IInputManager _inputManager = default!; [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IGameHud _gameHud = default!; @@ -31,7 +31,7 @@ namespace Content.Client if (obj.NewState is GameScreenBase) { // Switched TO GameScreen. - _escapeMenu = new EscapeMenu(_clientConsole); + _escapeMenu = new EscapeMenu(_consoleHost); _escapeMenu.OnClose += () => _gameHud.EscapeButtonDown = false; diff --git a/Content.Client/GameObjects/Components/Chemistry/FoamVisualizer.cs b/Content.Client/GameObjects/Components/Chemistry/FoamVisualizer.cs new file mode 100644 index 0000000000..79fb64a230 --- /dev/null +++ b/Content.Client/GameObjects/Components/Chemistry/FoamVisualizer.cs @@ -0,0 +1,74 @@ +#nullable enable +using System; +using Content.Shared.GameObjects.Components.Chemistry; +using JetBrains.Annotations; +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Client.GameObjects.Components.Animations; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.Maths; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Client.GameObjects.Components.Chemistry +{ + [UsedImplicitly] + public class FoamVisualizer : AppearanceVisualizer + { + private const string AnimationKey = "foamdissolve_animation"; + private Animation _foamDissolve = new(); + public override void LoadData(YamlMappingNode node) + { + base.LoadData(node); + + var delay = 0.6f; + var state = "foam-dissolve"; + + if (node.TryGetNode("animationTime", out var delayNode)) + { + delay = delayNode.AsFloat(); + } + + if (node.TryGetNode("animationState", out var stateNode)) + { + state = stateNode.AsString(); + } + + _foamDissolve = new Animation {Length = TimeSpan.FromSeconds(delay)}; + var flick = new AnimationTrackSpriteFlick(); + _foamDissolve.AnimationTracks.Add(flick); + flick.LayerKey = FoamVisualLayers.Base; + flick.KeyFrames.Add(new AnimationTrackSpriteFlick.KeyFrame(state, 0f)); + } + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (component.TryGetData(FoamVisuals.State, out var state)) + { + if (state) + { + if (component.Owner.TryGetComponent(out AnimationPlayerComponent? animPlayer)) + { + if (!animPlayer.HasRunningAnimation(AnimationKey)) + animPlayer.Play(_foamDissolve, AnimationKey); + } + } + } + + if (component.TryGetData(FoamVisuals.Color, out var color)) + { + if (component.Owner.TryGetComponent(out ISpriteComponent? sprite)) + { + sprite.Color = color; + } + } + } + } + + public enum FoamVisualLayers : byte + { + Base + } +} diff --git a/Content.Client/GameObjects/Components/Chemistry/HyposprayComponent.cs b/Content.Client/GameObjects/Components/Chemistry/HyposprayComponent.cs new file mode 100644 index 0000000000..979d371e62 --- /dev/null +++ b/Content.Client/GameObjects/Components/Chemistry/HyposprayComponent.cs @@ -0,0 +1,68 @@ +using Content.Client.UserInterface.Stylesheets; +using Content.Client.Utility; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Chemistry; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Timing; +using Robust.Shared.ViewVariables; + +#nullable enable + +namespace Content.Client.GameObjects.Components.Chemistry +{ + [RegisterComponent] + public sealed class HyposprayComponent : SharedHyposprayComponent, IItemStatus + { + [ViewVariables] private ReagentUnit CurrentVolume { get; set; } + [ViewVariables] private ReagentUnit TotalVolume { get; set; } + [ViewVariables(VVAccess.ReadWrite)] private bool _uiUpdateNeeded; + + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) + { + if (curState is not HyposprayComponentState cState) + return; + + CurrentVolume = cState.CurVolume; + TotalVolume = cState.MaxVolume; + _uiUpdateNeeded = true; + } + + Control IItemStatus.MakeControl() + { + return new StatusControl(this); + } + + private sealed class StatusControl : Control + { + private readonly HyposprayComponent _parent; + private readonly RichTextLabel _label; + + public StatusControl(HyposprayComponent parent) + { + _parent = parent; + _label = new RichTextLabel {StyleClasses = {StyleNano.StyleClassItemStatus}}; + AddChild(_label); + + parent._uiUpdateNeeded = true; + } + + protected override void Update(FrameEventArgs args) + { + base.Update(args); + if (!_parent._uiUpdateNeeded) + { + return; + } + + _parent._uiUpdateNeeded = false; + + _label.SetMarkup(Loc.GetString( + "Volume: [color=white]{0}/{1}[/color]", + _parent.CurrentVolume, _parent.TotalVolume)); + } + } + } +} diff --git a/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserBoundUserInterface.cs b/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserBoundUserInterface.cs index 6ab682f76b..e6675df4c4 100644 --- a/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserBoundUserInterface.cs +++ b/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserBoundUserInterface.cs @@ -48,7 +48,10 @@ namespace Content.Client.GameObjects.Components.Chemistry.ReagentDispenser _window.DispenseButton1.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount1); _window.DispenseButton5.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount5); _window.DispenseButton10.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount10); + _window.DispenseButton15.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount15); + _window.DispenseButton20.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount20); _window.DispenseButton25.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount25); + _window.DispenseButton30.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount30); _window.DispenseButton50.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount50); _window.DispenseButton100.OnPressed += _ => ButtonPressed(UiButton.SetDispenseAmount100); } diff --git a/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserWindow.cs b/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserWindow.cs index d32d10f776..699df5e956 100644 --- a/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserWindow.cs +++ b/Content.Client/GameObjects/Components/Chemistry/ReagentDispenser/ReagentDispenserWindow.cs @@ -34,9 +34,18 @@ namespace Content.Client.GameObjects.Components.Chemistry.ReagentDispenser /// Sets the dispense amount to 10 when pressed. public Button DispenseButton10 { get; } + /// Sets the dispense amount to 15 when pressed. + public Button DispenseButton15 { get; } + + /// Sets the dispense amount to 20 when pressed. + public Button DispenseButton20 { get; } + /// Sets the dispense amount to 25 when pressed. public Button DispenseButton25 { get; } + /// Sets the dispense amount to 30 when pressed. + public Button DispenseButton30 { get; } + /// Sets the dispense amount to 50 when pressed. public Button DispenseButton50 { get; } @@ -79,7 +88,10 @@ namespace Content.Client.GameObjects.Components.Chemistry.ReagentDispenser (DispenseButton1 = new Button {Text = "1", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenRight }}), (DispenseButton5 = new Button {Text = "5", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenBoth }}), (DispenseButton10 = new Button {Text = "10", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenBoth }}), + (DispenseButton15 = new Button {Text = "15", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenBoth }}), + (DispenseButton20 = new Button {Text = "20", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenBoth }}), (DispenseButton25 = new Button {Text = "25", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenBoth }}), + (DispenseButton30 = new Button {Text = "30", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenBoth }}), (DispenseButton50 = new Button {Text = "50", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenBoth }}), (DispenseButton100 = new Button {Text = "100", Group = dispenseAmountGroup, StyleClasses = { StyleBase.ButtonOpenLeft }}), } @@ -215,9 +227,18 @@ namespace Content.Client.GameObjects.Components.Chemistry.ReagentDispenser case 10: DispenseButton10.Pressed = true; break; + case 15: + DispenseButton15.Pressed = true; + break; + case 20: + DispenseButton20.Pressed = true; + break; case 25: DispenseButton25.Pressed = true; break; + case 30: + DispenseButton30.Pressed = true; + break; case 50: DispenseButton50.Pressed = true; break; diff --git a/Content.Client/GameObjects/Components/Chemistry/SmokeVisualizer.cs b/Content.Client/GameObjects/Components/Chemistry/SmokeVisualizer.cs new file mode 100644 index 0000000000..91f68b6f71 --- /dev/null +++ b/Content.Client/GameObjects/Components/Chemistry/SmokeVisualizer.cs @@ -0,0 +1,26 @@ +#nullable enable +using Content.Shared.GameObjects.Components.Chemistry; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.Maths; + +namespace Content.Client.GameObjects.Components.Chemistry +{ + [UsedImplicitly] + public class SmokeVisualizer : AppearanceVisualizer + { + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (component.TryGetData(SmokeVisuals.Color, out var color)) + { + if (component.Owner.TryGetComponent(out ISpriteComponent? sprite)) + { + sprite.Color = color; + } + } + } + } +} diff --git a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs index 85d6119014..e24e60cf4e 100644 --- a/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Client/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.Linq; using Content.Client.GameObjects.EntitySystems; -using Content.Shared; using Content.Shared.GameObjects.Components.Instruments; using Content.Shared.Physics; using Robust.Client.Audio.Midi; @@ -11,13 +10,11 @@ using Robust.Shared.Audio.Midi; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Timers; using Robust.Shared.GameObjects.Systems; -using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Players; using Robust.Shared.Serialization; -using Robust.Shared.Timers; using Robust.Shared.ViewVariables; namespace Content.Client.GameObjects.Components.Instruments @@ -162,6 +159,41 @@ namespace Content.Client.GameObjects.Components.Instruments [ViewVariables] public bool IsRendererAlive => _renderer != null; + [ViewVariables] + public int PlayerTotalTick => _renderer?.PlayerTotalTick ?? 0; + + [ViewVariables] + public int PlayerTick + { + get => _renderer?.PlayerTick ?? 0; + set + { + if (!IsRendererAlive || _renderer!.Status != MidiRendererStatus.File) return; + + _midiEventBuffer.Clear(); + + _renderer.PlayerTick = value; + var tick = _renderer.SequencerTick; + + // We add a "all notes off" message. + for (byte i = 0; i < 16; i++) + { + _midiEventBuffer.Add(new MidiEvent() + { + Tick = tick, Type = 176, + Control = 123, Velocity = 0, Channel = i, + }); + } + + // Now we add a Reset All Controllers message. + _midiEventBuffer.Add(new MidiEvent() + { + Tick = tick, Type = 176, + Control = 121, Value = 0, + }); + } + } + public override void Initialize() { base.Initialize(); @@ -390,20 +422,6 @@ namespace Content.Client.GameObjects.Components.Instruments /// The received midi event private void RendererOnMidiEvent(MidiEvent midiEvent) { - // avoid of out-of-band, unimportant or unsupported events - switch (midiEvent.Type) - { - case 0x80: // NOTE_OFF - case 0x90: // NOTE_ON - case 0xa0: // KEY_PRESSURE - case 0xb0: // CONTROL_CHANGE - case 0xd0: // CHANNEL_PRESSURE - case 0xe0: // PITCH_BEND - break; - default: - return; - } - _midiEventBuffer.Add(midiEvent); } diff --git a/Content.Client/GameObjects/Components/Items/HandsComponent.cs b/Content.Client/GameObjects/Components/Items/HandsComponent.cs index 21f112d031..a59f0333f9 100644 --- a/Content.Client/GameObjects/Components/Items/HandsComponent.cs +++ b/Content.Client/GameObjects/Components/Items/HandsComponent.cs @@ -1,14 +1,23 @@ -#nullable enable +#nullable enable +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Content.Client.Animations; using Content.Client.UserInterface; using Content.Shared.GameObjects.Components.Items; +using Robust.Client.Animations; using Robust.Client.GameObjects; +using Robust.Client.GameObjects.Components.Animations; using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.Animations; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Players; using Robust.Shared.ViewVariables; namespace Content.Client.GameObjects.Components.Items @@ -244,6 +253,23 @@ namespace Content.Client.GameObjects.Components.Items } } + public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null) + { + base.HandleNetworkMessage(message, netChannel, session); + + switch (message) + { + case AnimatePickupEntityMessage msg: + { + if (Owner.EntityManager.TryGetEntity(msg.EntityId, out var entity)) + { + ReusableAnimations.AnimateEntityPickup(entity, msg.EntityPosition, Owner.Transform.WorldPosition); + } + break; + } + } + } + public void SendChangeHand(string index) { SendNetworkMessage(new ClientChangedHandMsg(index)); diff --git a/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs b/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs deleted file mode 100644 index 2a6c1e7358..0000000000 --- a/Content.Client/GameObjects/Components/Mobs/ClientOverlayEffectsComponent.cs +++ /dev/null @@ -1,169 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Content.Shared.GameObjects.Components.Mobs; -using Content.Shared.Interfaces; -using Robust.Client.GameObjects; -using Robust.Client.Graphics.Overlays; -using Robust.Client.Interfaces.Graphics.Overlays; -using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.Network; -using Robust.Shared.Interfaces.Reflection; -using Robust.Shared.IoC; -using Robust.Shared.Log; -using Robust.Shared.Players; -using Robust.Shared.ViewVariables; - -namespace Content.Client.GameObjects.Components.Mobs -{ - /// - /// A character UI component which shows the current damage state of the mob (living/dead) - /// - [RegisterComponent] - [ComponentReference(typeof(SharedOverlayEffectsComponent))] - public sealed class ClientOverlayEffectsComponent : SharedOverlayEffectsComponent//, ICharacterUI - { - [Dependency] private readonly IOverlayManager _overlayManager = default!; - [Dependency] private readonly IReflectionManager _reflectionManager = default!; - [Dependency] private readonly IClientNetManager _netManager = default!; - - /// - /// A list of overlay containers representing the current overlays applied - /// - private List _currentEffects = new(); - - [ViewVariables(VVAccess.ReadOnly)] - public List ActiveOverlays - { - get => _currentEffects; - set => SetEffects(value); - } - - public override void Initialize() - { - base.Initialize(); - - UpdateOverlays(); - } - - public override void HandleMessage(ComponentMessage message, IComponent component) - { - switch (message) - { - case PlayerAttachedMsg _: - UpdateOverlays(); - break; - case PlayerDetachedMsg _: - ActiveOverlays.ForEach(o => _overlayManager.RemoveOverlay(o.ID)); - break; - } - } - - public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession session = null) - { - base.HandleNetworkMessage(message, netChannel, session); - if (message is OverlayEffectComponentMessage overlayMessage) - { - SetEffects(overlayMessage.Overlays); - } - } - - private void UpdateOverlays() - { - _currentEffects = _overlayManager.AllOverlays - .Where(overlay => Enum.IsDefined(typeof(SharedOverlayID), overlay.ID)) - .Select(overlay => new OverlayContainer(overlay.ID)) - .ToList(); - - foreach (var overlayContainer in ActiveOverlays) - { - if (!_overlayManager.HasOverlay(overlayContainer.ID)) - { - if (TryCreateOverlay(overlayContainer, out var overlay)) - { - _overlayManager.AddOverlay(overlay); - } - } - } - - SendNetworkMessage(new ResendOverlaysMessage(), _netManager.ServerChannel); - } - - private void SetEffects(List newOverlays) - { - foreach (var container in ActiveOverlays.ToArray()) - { - if (!newOverlays.Contains(container)) - { - RemoveOverlay(container); - } - } - - foreach (var container in newOverlays) - { - if (!ActiveOverlays.Contains(container)) - { - AddOverlay(container); - } - else - { - UpdateOverlayConfiguration(container, _overlayManager.GetOverlay(container.ID)); - } - } - - _currentEffects = newOverlays; - } - - private void RemoveOverlay(OverlayContainer container) - { - ActiveOverlays.Remove(container); - _overlayManager.RemoveOverlay(container.ID); - } - - private void AddOverlay(OverlayContainer container) - { - if (_overlayManager.HasOverlay(container.ID)) - { - return; - } - - ActiveOverlays.Add(container); - if (TryCreateOverlay(container, out var overlay)) - { - _overlayManager.AddOverlay(overlay); - } - else - { - Logger.ErrorS("overlay", $"Could not add overlay {container.ID}"); - } - } - - private void UpdateOverlayConfiguration(OverlayContainer container, Overlay overlay) - { - if (overlay is IConfigurableOverlay configurable) - { - foreach (var param in container.Parameters) - { - configurable.Configure(param); - } - } - } - - private bool TryCreateOverlay(OverlayContainer container, out Overlay overlay) - { - var overlayTypes = _reflectionManager.GetAllChildren(); - var overlayType = overlayTypes.FirstOrDefault(t => t.Name == container.ID); - - if (overlayType != null) - { - overlay = IoCManager.Resolve().CreateInstance(overlayType); - UpdateOverlayConfiguration(container, overlay); - return true; - } - - overlay = default; - return false; - } - } -} diff --git a/Content.Client/GameObjects/Components/Observer/GhostComponent.cs b/Content.Client/GameObjects/Components/Observer/GhostComponent.cs index 8af023096f..b42f8439e0 100644 --- a/Content.Client/GameObjects/Components/Observer/GhostComponent.cs +++ b/Content.Client/GameObjects/Components/Observer/GhostComponent.cs @@ -46,7 +46,7 @@ namespace Content.Client.GameObjects.Components.Observer private void SetGhostVisibility(bool visibility) { - foreach (var ghost in _componentManager.GetAllComponents(typeof(GhostComponent))) + foreach (var ghost in _componentManager.GetAllComponents(typeof(GhostComponent), true)) { if (ghost.Owner.TryGetComponent(out SpriteComponent? component)) { diff --git a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs index 02d30dce09..c97b1e2f91 100644 --- a/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs +++ b/Content.Client/GameObjects/Components/Storage/ClientStorageComponent.cs @@ -1,17 +1,23 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; +using Content.Client.Animations; using Content.Client.GameObjects.Components.Items; using Content.Shared.GameObjects.Components.Storage; using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Client.GameObjects.Components.Animations; using Robust.Client.Graphics.Drawing; using Robust.Client.Interfaces.GameObjects.Components; using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.Animations; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.GameObjects.Components; using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Maths; @@ -77,6 +83,9 @@ namespace Content.Client.GameObjects.Components.Storage case CloseStorageUIMessage _: CloseUI(); break; + case AnimateInsertingEntitiesMessage msg: + HandleAnimatingInsertingEntities(msg); + break; } } @@ -92,6 +101,24 @@ namespace Content.Client.GameObjects.Components.Storage Window.BuildEntityList(); } + /// + /// Animate the newly stored entities in flying towards this storage's position + /// + /// + private void HandleAnimatingInsertingEntities(AnimateInsertingEntitiesMessage msg) + { + for (var i = 0; msg.StoredEntities.Count > i; i++) + { + var entityId = msg.StoredEntities[i]; + var initialPosition = msg.EntityPositions[i]; + + if (Owner.EntityManager.TryGetEntity(entityId, out var entity)) + { + ReusableAnimations.AnimateEntityPickup(entity, initialPosition, Owner.Transform.WorldPosition); + } + } + } + /// /// Opens the storage UI if closed. Closes it if opened. /// @@ -284,7 +311,7 @@ namespace Content.Client.GameObjects.Components.Storage /// /// Button created for each entity that represents that item in the storage UI, with a texture, and name and size label /// - private class EntityButton : PanelContainer + private class EntityButton : Control { public EntityUid EntityUid { get; set; } public Button ActualButton { get; } diff --git a/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs b/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs index f990eb2b27..f4cc9eddf8 100644 --- a/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs +++ b/Content.Client/GameObjects/Components/Weapons/FlashableComponent.cs @@ -1,5 +1,6 @@ using System; using System.Threading; +using Content.Client.Graphics.Overlays; using Content.Shared.GameObjects.Components.Weapons; using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Overlays; @@ -19,10 +20,8 @@ namespace Content.Client.GameObjects.Components.Weapons [RegisterComponent] public sealed class FlashableComponent : SharedFlashableComponent { - private CancellationTokenSource _cancelToken; private TimeSpan _startTime; private double _duration; - private FlashOverlay _overlay; public override void HandleComponentState(ComponentState curState, ComponentState nextState) { @@ -57,94 +56,15 @@ namespace Content.Client.GameObjects.Components.Weapons if (currentTime > newEndTime) { - DisableOverlay(); return; } _startTime = newState.Time; _duration = newState.Duration; - EnableOverlay(newEndTime - currentTime); - } - - private void EnableOverlay(double duration) - { - // If the timer gets reset - if (_overlay != null) - { - _overlay.Duration = _duration; - _overlay.StartTime = _startTime; - _cancelToken.Cancel(); - } - else - { - var overlayManager = IoCManager.Resolve(); - _overlay = new FlashOverlay(_duration); - overlayManager.AddOverlay(_overlay); - } - - _cancelToken = new CancellationTokenSource(); - Owner.SpawnTimer((int) duration * 1000, DisableOverlay, _cancelToken.Token); - } - - private void DisableOverlay() - { - if (_overlay == null) - { - return; - } - var overlayManager = IoCManager.Resolve(); - overlayManager.RemoveOverlay(_overlay.ID); - _overlay = null; - _cancelToken.Cancel(); - _cancelToken = null; - } - } - - public sealed class FlashOverlay : Overlay - { - public override OverlaySpace Space => OverlaySpace.ScreenSpace; - private readonly IGameTiming _timer; - private readonly IClyde _displayManager; - public TimeSpan StartTime { get; set; } - public double Duration { get; set; } - public FlashOverlay(double duration) : base(nameof(FlashOverlay)) - { - _timer = IoCManager.Resolve(); - _displayManager = IoCManager.Resolve(); - StartTime = _timer.CurTime; - Duration = duration; - } - - protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace) - { - var elapsedTime = (_timer.CurTime - StartTime).TotalSeconds; - if (elapsedTime > Duration) - { - return; - } - var screenHandle = (DrawingHandleScreen) handle; - - screenHandle.DrawRect( - new UIBox2(0.0f, 0.0f, _displayManager.ScreenSize.X, _displayManager.ScreenSize.Y), - Color.White.WithAlpha(GetAlpha(elapsedTime / Duration)) - ); - } - - private float GetAlpha(double ratio) - { - // Ideally you just want a smooth slope to finish it so it's not jarring at the end - // By all means put in a better curve - const float slope = -9.0f; - const float exponent = 0.1f; - const float yOffset = 9.0f; - const float xOffset = 0.0f; - - // Overkill but easy to adjust if you want to mess around with the design - var result = (float) MathHelper.Clamp(slope * (float) Math.Pow(ratio - xOffset, exponent) + yOffset, 0.0, 1.0); - DebugTools.Assert(!float.IsNaN(result)); - return result; + var overlay = overlayManager.GetOverlay(nameof(FlashOverlay)); + overlay.ReceiveFlash(_duration); } } } diff --git a/Content.Client/GameObjects/EntitySystems/CameraRecoilSystem.cs b/Content.Client/GameObjects/EntitySystems/CameraRecoilSystem.cs index f37f9c8539..6f6f598b4c 100644 --- a/Content.Client/GameObjects/EntitySystems/CameraRecoilSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/CameraRecoilSystem.cs @@ -11,7 +11,7 @@ namespace Content.Client.GameObjects.EntitySystems { base.FrameUpdate(frameTime); - foreach (var recoil in EntityManager.ComponentManager.EntityQuery()) + foreach (var recoil in EntityManager.ComponentManager.EntityQuery(true)) { recoil.FrameUpdate(frameTime); } diff --git a/Content.Client/GameObjects/EntitySystems/DoAfter/DoAfterSystem.cs b/Content.Client/GameObjects/EntitySystems/DoAfter/DoAfterSystem.cs index 7f911cfcb4..c93905ded1 100644 --- a/Content.Client/GameObjects/EntitySystems/DoAfter/DoAfterSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/DoAfter/DoAfterSystem.cs @@ -61,7 +61,7 @@ namespace Content.Client.GameObjects.EntitySystems.DoAfter if (_attachedEntity == null || _attachedEntity.Deleted) return; - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { if (!_knownComponents.Contains(comp)) { diff --git a/Content.Client/GameObjects/EntitySystems/DragDropSystem.cs b/Content.Client/GameObjects/EntitySystems/DragDropSystem.cs index ab4e1d601c..f4ef1b72a3 100644 --- a/Content.Client/GameObjects/EntitySystems/DragDropSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/DragDropSystem.cs @@ -302,6 +302,8 @@ namespace Content.Client.GameObjects.EntitySystems foreach (var entity in entities) { + if (entity == _dragDropHelper.Dragged) continue; + // check if it's able to be dropped on by current dragged entity var dropArgs = new DragDropEventArgs(_dragger, args.Coordinates, _dragDropHelper.Dragged, entity); var valid = true; @@ -381,10 +383,9 @@ namespace Content.Client.GameObjects.EntitySystems var pvsEntities = EntityManager.GetEntitiesIntersecting(_eyeManager.CurrentMap, bounds, true); foreach (var pvsEntity in pvsEntities) { - if (!pvsEntity.TryGetComponent(out ISpriteComponent? inRangeSprite)) continue; - - // can't highlight if there's no sprite or it's not visible - if (inRangeSprite.Visible == false) continue; + if (!pvsEntity.TryGetComponent(out ISpriteComponent? inRangeSprite) || + !inRangeSprite.Visible || + pvsEntity == _dragDropHelper.Dragged) continue; var valid = (bool?) null; // check if it's able to be dropped on by current dragged entity diff --git a/Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs b/Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs index 59c22113c1..4d4e7c907a 100644 --- a/Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/InstrumentSystem.cs @@ -44,7 +44,7 @@ namespace Content.Client.GameObjects.EntitySystems return; } - foreach (var instrumentComponent in EntityManager.ComponentManager.EntityQuery()) + foreach (var instrumentComponent in EntityManager.ComponentManager.EntityQuery(true)) { instrumentComponent.Update(frameTime); } diff --git a/Content.Client/GameObjects/EntitySystems/MarkerSystem.cs b/Content.Client/GameObjects/EntitySystems/MarkerSystem.cs index bec86abbb4..f6acf68b4f 100644 --- a/Content.Client/GameObjects/EntitySystems/MarkerSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/MarkerSystem.cs @@ -19,7 +19,7 @@ namespace Content.Client.GameObjects.EntitySystems private void UpdateMarkers() { - foreach (var markerComponent in EntityManager.ComponentManager.EntityQuery()) + foreach (var markerComponent in EntityManager.ComponentManager.EntityQuery(true)) { markerComponent.UpdateVisibility(); } diff --git a/Content.Client/GameObjects/EntitySystems/MeleeLungeSystem.cs b/Content.Client/GameObjects/EntitySystems/MeleeLungeSystem.cs index 3f180d4399..f61ae4506f 100644 --- a/Content.Client/GameObjects/EntitySystems/MeleeLungeSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/MeleeLungeSystem.cs @@ -11,7 +11,7 @@ namespace Content.Client.GameObjects.EntitySystems { base.FrameUpdate(frameTime); - foreach (var meleeLungeComponent in EntityManager.ComponentManager.EntityQuery()) + foreach (var meleeLungeComponent in EntityManager.ComponentManager.EntityQuery(true)) { meleeLungeComponent.Update(frameTime); } diff --git a/Content.Client/GameObjects/EntitySystems/MeleeWeaponSystem.cs b/Content.Client/GameObjects/EntitySystems/MeleeWeaponSystem.cs index e35c150cd2..f3d7883d8d 100644 --- a/Content.Client/GameObjects/EntitySystems/MeleeWeaponSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/MeleeWeaponSystem.cs @@ -1,4 +1,4 @@ -using System; +using System; using Content.Client.GameObjects.Components.Mobs; using Content.Client.GameObjects.Components.Weapons.Melee; using Content.Shared.GameObjects.Components.Weapons.Melee; @@ -14,7 +14,6 @@ using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.Maths; using Robust.Shared.Prototypes; -using Robust.Shared.Timers; using static Content.Shared.GameObjects.EntitySystemMessages.MeleeWeaponSystemMessages; namespace Content.Client.GameObjects.EntitySystems @@ -35,7 +34,7 @@ namespace Content.Client.GameObjects.EntitySystems { base.FrameUpdate(frameTime); - foreach (var arcAnimationComponent in EntityManager.ComponentManager.EntityQuery()) + foreach (var arcAnimationComponent in EntityManager.ComponentManager.EntityQuery(true)) { arcAnimationComponent.Update(frameTime); } @@ -49,7 +48,12 @@ namespace Content.Client.GameObjects.EntitySystems return; } - var attacker = EntityManager.GetEntity(msg.Attacker); + if (!EntityManager.TryGetEntity(msg.Attacker, out var attacker)) + { + //FIXME: This should never happen. + Logger.Error($"Tried to play a weapon arc {msg.ArcPrototype}, but the attacker does not exist. attacker={msg.Attacker}, source={msg.Source}"); + return; + } if (!attacker.Deleted) { diff --git a/Content.Client/GameObjects/EntitySystems/SubFloorHideSystem.cs b/Content.Client/GameObjects/EntitySystems/SubFloorHideSystem.cs index d4f4352bd9..249df06da8 100644 --- a/Content.Client/GameObjects/EntitySystems/SubFloorHideSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/SubFloorHideSystem.cs @@ -35,7 +35,7 @@ namespace Content.Client.GameObjects.EntitySystems private void UpdateAll() { - foreach (var comp in EntityManager.ComponentManager.EntityQuery()) + foreach (var comp in EntityManager.ComponentManager.EntityQuery(true)) { if (!_mapManager.TryGetGrid(comp.Owner.Transform.GridID, out var grid)) return; diff --git a/Content.Client/GameObjects/EntitySystems/SuspicionEndTimerSystem.cs b/Content.Client/GameObjects/EntitySystems/SuspicionEndTimerSystem.cs new file mode 100644 index 0000000000..0186bf4a01 --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/SuspicionEndTimerSystem.cs @@ -0,0 +1,23 @@ +using System; +using Content.Shared.GameObjects.EntitySystemMessages; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Client.GameObjects.EntitySystems +{ + public sealed class SuspicionEndTimerSystem : EntitySystem + { + public TimeSpan? EndTime { get; private set; } + + public override void Initialize() + { + base.Initialize(); + + SubscribeNetworkEvent(RxTimerMessage); + } + + private void RxTimerMessage(SuspicionMessages.SetSuspicionEndTimerMessage ev) + { + EndTime = ev.EndTime; + } + } +} diff --git a/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs b/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs index 9e300ce897..50d7bddf28 100644 --- a/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs +++ b/Content.Client/Graphics/Overlays/CircleMaskOverlay.cs @@ -3,6 +3,7 @@ using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Overlays; using Robust.Client.Graphics.Shaders; using Robust.Client.Interfaces.Graphics.ClientEye; +using Robust.Client.Player; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -13,11 +14,12 @@ namespace Content.Client.Graphics.Overlays { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEyeManager _eyeManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; public override OverlaySpace Space => OverlaySpace.WorldSpace; private readonly ShaderInstance _shader; - public CircleMaskOverlay() : base(nameof(SharedOverlayID.CircleMaskOverlay)) + public CircleMaskOverlay() : base(nameof(CircleMaskOverlay)) { IoCManager.InjectDependencies(this); _shader = _prototypeManager.Index("CircleMask").Instance(); @@ -25,6 +27,8 @@ namespace Content.Client.Graphics.Overlays protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace) { + if (!GradientCircleMaskOverlay.LocalPlayerHasState(_playerManager, false, true)) + return; handle.UseShader(_shader); var worldHandle = (DrawingHandleWorld)handle; var viewport = _eyeManager.GetWorldViewport(); diff --git a/Content.Client/Graphics/Overlays/FlashOverlay.cs b/Content.Client/Graphics/Overlays/FlashOverlay.cs index 547e4dcb17..6acab964bf 100644 --- a/Content.Client/Graphics/Overlays/FlashOverlay.cs +++ b/Content.Client/Graphics/Overlays/FlashOverlay.cs @@ -1,5 +1,6 @@ using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.Interfaces; +using Content.Shared.Network.NetMessages; using Robust.Client.Graphics; using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Overlays; @@ -14,7 +15,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace Content.Client.Graphics.Overlays { - public class FlashOverlay : Overlay, IConfigurableOverlay + public class FlashOverlay : Overlay { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IClyde _displayManager = default!; @@ -22,27 +23,33 @@ namespace Content.Client.Graphics.Overlays public override OverlaySpace Space => OverlaySpace.ScreenSpace; private readonly ShaderInstance _shader; - private readonly double _startTime; - private int _lastsFor = 5000; + private double _startTime = -1; + private double _lastsFor = 1; private Texture _screenshotTexture; - public FlashOverlay() : base(nameof(SharedOverlayID.FlashOverlay)) + public FlashOverlay() : base(nameof(FlashOverlay)) { IoCManager.InjectDependencies(this); _shader = _prototypeManager.Index("FlashedEffect").Instance().Duplicate(); + } - _startTime = _gameTiming.CurTime.TotalMilliseconds; + public void ReceiveFlash(double duration) + { _displayManager.Screenshot(ScreenshotType.BeforeUI, image => { var rgba32Image = image.CloneAs(Configuration.Default); _screenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image); }); + _startTime = _gameTiming.CurTime.TotalSeconds; + _lastsFor = duration; } protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace) { + var percentComplete = (float) ((_gameTiming.CurTime.TotalSeconds - _startTime) / _lastsFor); + if (percentComplete >= 1.0f) + return; handle.UseShader(_shader); - var percentComplete = (float) ((_gameTiming.CurTime.TotalMilliseconds - _startTime) / _lastsFor); _shader?.SetParameter("percentComplete", percentComplete); var screenSpaceHandle = handle as DrawingHandleScreen; @@ -60,13 +67,5 @@ namespace Content.Client.Graphics.Overlays _screenshotTexture = null; } - - public void Configure(OverlayParameter parameters) - { - if (parameters is TimedOverlayParameter timedParams) - { - _lastsFor = timedParams.Length; - } - } } } diff --git a/Content.Client/Graphics/Overlays/GradientCircleMask.cs b/Content.Client/Graphics/Overlays/GradientCircleMask.cs index 5dec976b53..b60fd7d16b 100644 --- a/Content.Client/Graphics/Overlays/GradientCircleMask.cs +++ b/Content.Client/Graphics/Overlays/GradientCircleMask.cs @@ -1,8 +1,10 @@ using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.Components.Mobs.State; using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Overlays; using Robust.Client.Graphics.Shaders; using Robust.Client.Interfaces.Graphics.ClientEye; +using Robust.Client.Player; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -13,18 +15,43 @@ namespace Content.Client.Graphics.Overlays { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEyeManager _eyeManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; public override OverlaySpace Space => OverlaySpace.WorldSpace; private readonly ShaderInstance _shader; - public GradientCircleMaskOverlay() : base(nameof(SharedOverlayID.GradientCircleMaskOverlay)) + public GradientCircleMaskOverlay() : base(nameof(GradientCircleMaskOverlay)) { IoCManager.InjectDependencies(this); _shader = _prototypeManager.Index("GradientCircleMask").Instance(); } + public static bool LocalPlayerHasState(IPlayerManager pm, bool critical, bool dead) { + var playerEntity = pm.LocalPlayer?.ControlledEntity; + + if (playerEntity == null) + { + return false; + } + + if (playerEntity.TryGetComponent(out var mobState)) + { + if (critical) + if (mobState.IsCritical()) + return true; + if (dead) + if (mobState.IsDead()) + return true; + } + + return false; + } + protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace) { + if (!LocalPlayerHasState(_playerManager, true, false)) + return; + handle.UseShader(_shader); var worldHandle = (DrawingHandleWorld)handle; var viewport = _eyeManager.GetWorldViewport(); diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs index 6823e56a43..c176efa82d 100644 --- a/Content.Client/IgnoredComponents.cs +++ b/Content.Client/IgnoredComponents.cs @@ -235,11 +235,14 @@ namespace Content.Client "SliceableFood", "DamageOtherOnHit", "DamageOnLand", + "SmokeSolutionAreaEffect", + "FoamSolutionAreaEffect", "GasFilter", "Recyclable", "SecretStash", "Toilet", - "ClusterFlash" + "ClusterFlash", + "GasGenerator" }; } } diff --git a/Content.Client/Instruments/InstrumentMenu.xaml b/Content.Client/Instruments/InstrumentMenu.xaml new file mode 100644 index 0000000000..23e4b75a9b --- /dev/null +++ b/Content.Client/Instruments/InstrumentMenu.xaml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/Instruments/InstrumentMenu.cs b/Content.Client/Instruments/InstrumentMenu.xaml.cs similarity index 55% rename from Content.Client/Instruments/InstrumentMenu.cs rename to Content.Client/Instruments/InstrumentMenu.xaml.cs index 5f30d71494..9ead93cc77 100644 --- a/Content.Client/Instruments/InstrumentMenu.cs +++ b/Content.Client/Instruments/InstrumentMenu.xaml.cs @@ -5,35 +5,39 @@ using Content.Client.GameObjects.Components.Instruments; using Content.Client.UserInterface.Stylesheets; using Content.Client.Utility; using Robust.Client.Audio.Midi; +using Robust.Client.AutoGenerated; using Robust.Client.Graphics.Drawing; using Robust.Client.Interfaces.UserInterface; using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; using Robust.Shared.Containers; +using Robust.Shared.Input; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Log; using Robust.Shared.Maths; using Robust.Shared.Timers; +using Robust.Shared.Timing; +using Range = Robust.Client.UserInterface.Controls.Range; namespace Content.Client.Instruments { - public class InstrumentMenu : SS14Window + [GenerateTypedNameReferences] + public partial class InstrumentMenu : SS14Window { [Dependency] private readonly IMidiManager _midiManager = default!; [Dependency] private readonly IFileDialogManager _fileDialogManager = default!; private readonly InstrumentBoundUserInterface _owner; - private readonly Button _midiLoopButton; - private readonly Button _midiStopButton; - private readonly Button _midiInputButton; protected override Vector2? CustomSize => (400, 150); public InstrumentMenu(InstrumentBoundUserInterface owner) { + RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _owner = owner; @@ -42,108 +46,14 @@ namespace Content.Client.Instruments Title = _owner.Instrument.Owner.Name; - var margin = new MarginContainer() - { - SizeFlagsVertical = SizeFlags.FillExpand, - SizeFlagsHorizontal = SizeFlags.FillExpand, - }; - - var vBox = new VBoxContainer() - { - SizeFlagsVertical = SizeFlags.FillExpand, - SeparationOverride = 5, - }; - - var hBoxTopButtons = new HBoxContainer() - { - SizeFlagsHorizontal = SizeFlags.FillExpand, - SizeFlagsVertical = SizeFlags.FillExpand, - SizeFlagsStretchRatio = 1, - Align = BoxContainer.AlignMode.Center - }; - - _midiInputButton = new Button() - { - Text = Loc.GetString("MIDI Input"), - TextAlign = Label.AlignMode.Center, - SizeFlagsHorizontal = SizeFlags.FillExpand, - SizeFlagsStretchRatio = 1, - ToggleMode = true, - Pressed = _owner.Instrument.IsInputOpen, - }; - - _midiInputButton.OnToggled += MidiInputButtonOnOnToggled; - - var topSpacer = new Control() - { - SizeFlagsHorizontal = SizeFlags.FillExpand, - SizeFlagsStretchRatio = 2, - }; - - var midiFileButton = new Button() - { - Text = Loc.GetString("Play MIDI File"), - TextAlign = Label.AlignMode.Center, - SizeFlagsHorizontal = SizeFlags.FillExpand, - SizeFlagsStretchRatio = 1, - }; - - midiFileButton.OnPressed += MidiFileButtonOnOnPressed; - - var hBoxBottomButtons = new HBoxContainer() - { - SizeFlagsHorizontal = SizeFlags.FillExpand, - SizeFlagsVertical = SizeFlags.FillExpand, - SizeFlagsStretchRatio = 1, - Align = BoxContainer.AlignMode.Center - }; - - _midiLoopButton = new Button() - { - Text = Loc.GetString("Loop"), - TextAlign = Label.AlignMode.Center, - SizeFlagsHorizontal = SizeFlags.FillExpand, - SizeFlagsStretchRatio = 1, - ToggleMode = true, - Disabled = !_owner.Instrument.IsMidiOpen, - Pressed = _owner.Instrument.LoopMidi, - }; - - _midiLoopButton.OnToggled += MidiLoopButtonOnOnToggled; - - var bottomSpacer = new Control() - { - SizeFlagsHorizontal = SizeFlags.FillExpand, - SizeFlagsStretchRatio = 2, - }; - - _midiStopButton = new Button() - { - Text = Loc.GetString("Stop"), - TextAlign = Label.AlignMode.Center, - SizeFlagsHorizontal = SizeFlags.FillExpand, - SizeFlagsStretchRatio = 1, - Disabled = !_owner.Instrument.IsMidiOpen, - }; - - _midiStopButton.OnPressed += MidiStopButtonOnPressed; - - hBoxBottomButtons.AddChild(_midiLoopButton); - hBoxBottomButtons.AddChild(bottomSpacer); - hBoxBottomButtons.AddChild(_midiStopButton); - - hBoxTopButtons.AddChild(_midiInputButton); - hBoxTopButtons.AddChild(topSpacer); - hBoxTopButtons.AddChild(midiFileButton); - - vBox.AddChild(hBoxTopButtons); - vBox.AddChild(hBoxBottomButtons); - - margin.AddChild(vBox); + LoopButton.Disabled = !_owner.Instrument.IsMidiOpen; + LoopButton.Pressed = _owner.Instrument.LoopMidi; + StopButton.Disabled = !_owner.Instrument.IsMidiOpen; + PlaybackSlider.MouseFilter = _owner.Instrument.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore; if (!_midiManager.IsAvailable) { - margin.AddChild(new PanelContainer + Margin.AddChild(new PanelContainer { MouseFilter = MouseFilterMode.Stop, PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Black.WithAlpha(0.90f)}, @@ -159,9 +69,17 @@ namespace Content.Client.Instruments } } }); + + // We return early as to not give the buttons behavior. + return; } - Contents.AddChild(margin); + InputButton.OnToggled += MidiInputButtonOnOnToggled; + FileButton.OnPressed += MidiFileButtonOnOnPressed; + LoopButton.OnToggled += MidiLoopButtonOnOnToggled; + StopButton.OnPressed += MidiStopButtonOnPressed; + PlaybackSlider.OnValueChanged += PlaybackSliderSeek; + PlaybackSlider.OnKeyBindUp += PlaybackSliderKeyUp; } private void InstrumentOnMidiPlaybackEnded() @@ -171,14 +89,17 @@ namespace Content.Client.Instruments public void MidiPlaybackSetButtonsDisabled(bool disabled) { - _midiLoopButton.Disabled = disabled; - _midiStopButton.Disabled = disabled; + LoopButton.Disabled = disabled; + StopButton.Disabled = disabled; + + // Whether to allow the slider to receive events.. + PlaybackSlider.MouseFilter = !disabled ? MouseFilterMode.Pass : MouseFilterMode.Ignore; } private async void MidiFileButtonOnOnPressed(BaseButton.ButtonEventArgs obj) { var filters = new FileDialogFilters(new FileDialogFilters.Group("mid", "midi")); - var file = await _fileDialogManager.OpenFile(filters); + await using var file = await _fileDialogManager.OpenFile(filters); // The following checks are only in place to prevent players from playing MIDI songs locally. // There are equivalents for these checks on the server. @@ -195,7 +116,7 @@ namespace Content.Client.Instruments return; MidiStopButtonOnPressed(null); - var memStream = new MemoryStream((int) file.Length); + await using var memStream = new MemoryStream((int) file.Length); // 100ms delay is due to a race condition or something idk. // While we're waiting, load it into memory. await Task.WhenAll(Timer.Delay(100), file.CopyToAsync(memStream)); @@ -204,8 +125,8 @@ namespace Content.Client.Instruments return; MidiPlaybackSetButtonsDisabled(false); - if (_midiInputButton.Pressed) - _midiInputButton.Pressed = false; + if (InputButton.Pressed) + InputButton.Pressed = false; } private void MidiInputButtonOnOnToggled(BaseButton.ButtonToggledEventArgs obj) @@ -253,5 +174,36 @@ namespace Content.Client.Instruments { _owner.Instrument.LoopMidi = obj.Pressed; } + + private void PlaybackSliderSeek(Range _) + { + // Do not seek while still grabbing. + if (PlaybackSlider.Grabbed) return; + + _owner.Instrument.PlayerTick = (int)Math.Ceiling(PlaybackSlider.Value); + } + + private void PlaybackSliderKeyUp(GUIBoundKeyEventArgs args) + { + if (args.Function != EngineKeyFunctions.UIClick) return; + _owner.Instrument.PlayerTick = (int)Math.Ceiling(PlaybackSlider.Value); + } + + protected override void Update(FrameEventArgs args) + { + base.Update(args); + + if (!_owner.Instrument.IsMidiOpen) + { + PlaybackSlider.MaxValue = 1; + PlaybackSlider.SetValueWithoutEvent(0); + return; + } + + if (PlaybackSlider.Grabbed) return; + + PlaybackSlider.MaxValue = _owner.Instrument.PlayerTotalTick; + PlaybackSlider.SetValueWithoutEvent(_owner.Instrument.PlayerTick); + } } } diff --git a/Content.Client/Parallax/ParallaxManager.cs b/Content.Client/Parallax/ParallaxManager.cs index 9ff1bc08ed..3a17cc2ea6 100644 --- a/Content.Client/Parallax/ParallaxManager.cs +++ b/Content.Client/Parallax/ParallaxManager.cs @@ -54,7 +54,7 @@ namespace Content.Client.Parallax { using (var reader = new StreamReader(configStream, EncodingHelpers.UTF8)) { - contents = reader.ReadToEnd(); + contents = reader.ReadToEnd().Replace(Environment.NewLine, "\n"); } if (!debugParallax && _resourceCache.UserData.Exists(ParallaxConfigOld)) diff --git a/Content.Client/Sandbox/SandboxManager.cs b/Content.Client/Sandbox/SandboxManager.cs index a7a79fe884..aa91bb7264 100644 --- a/Content.Client/Sandbox/SandboxManager.cs +++ b/Content.Client/Sandbox/SandboxManager.cs @@ -102,7 +102,7 @@ namespace Content.Client.Sandbox internal class SandboxManager : SharedSandboxManager, ISandboxManager { - [Dependency] private readonly IClientConsole _console = default!; + [Dependency] private readonly IClientConsoleHost _consoleHost = default!; [Dependency] private readonly IGameHud _gameHud = default!; [Dependency] private readonly IClientNetManager _netManager = default!; [Dependency] private readonly IPlacementManager _placementManager = default!; @@ -314,37 +314,37 @@ namespace Content.Client.Sandbox private void ToggleLight() { - _console.ProcessCommand("togglelight"); + _consoleHost.ExecuteCommand("togglelight"); } private void ToggleFov() { - _console.ProcessCommand("togglefov"); + _consoleHost.ExecuteCommand("togglefov"); } private void ToggleShadows() { - _console.ProcessCommand("toggleshadows"); + _consoleHost.ExecuteCommand("toggleshadows"); } private void ToggleSubFloor() { - _console.ProcessCommand("showsubfloor"); + _consoleHost.ExecuteCommand("showsubfloor"); } private void ShowMarkers() { - _console.ProcessCommand("showmarkers"); + _consoleHost.ExecuteCommand("showmarkers"); } private void ShowBb() { - _console.ProcessCommand("showbb"); + _consoleHost.ExecuteCommand("showbb"); } private void LinkMachines() { - _console.ProcessCommand("signallink"); + _consoleHost.ExecuteCommand("signallink"); } } } diff --git a/Content.Client/State/LobbyState.cs b/Content.Client/State/LobbyState.cs index 866c65c463..6b6ae5d6bf 100644 --- a/Content.Client/State/LobbyState.cs +++ b/Content.Client/State/LobbyState.cs @@ -26,7 +26,7 @@ namespace Content.Client.State public class LobbyState : Robust.Client.State.State { [Dependency] private readonly IBaseClient _baseClient = default!; - [Dependency] private readonly IClientConsole _console = default!; + [Dependency] private readonly IClientConsoleHost _consoleHost = default!; [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IInputManager _inputManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; @@ -87,7 +87,7 @@ namespace Content.Client.State _userInterfaceManager.StateRoot.AddChild(_characterSetup); }; - _lobby.ObserveButton.OnPressed += args => _console.ProcessCommand("observe"); + _lobby.ObserveButton.OnPressed += args => _consoleHost.ExecuteCommand("observe"); _lobby.ReadyButton.OnPressed += args => { if (!_clientGameTicker.IsGameStarted) @@ -104,7 +104,7 @@ namespace Content.Client.State SetReady(args.Pressed); }; - _lobby.LeaveButton.OnPressed += args => _console.ProcessCommand("disconnect"); + _lobby.LeaveButton.OnPressed += args => _consoleHost.ExecuteCommand("disconnect"); _lobby.OptionsButton.OnPressed += args => new OptionsMenu().Open(); UpdatePlayerList(); @@ -259,7 +259,7 @@ namespace Content.Client.State return; } - _console.ProcessCommand($"toggleready {newReady}"); + _consoleHost.ExecuteCommand($"toggleready {newReady}"); UpdatePlayerList(); } } diff --git a/Content.Client/StationEvents/RadiationPulseOverlay.cs b/Content.Client/StationEvents/RadiationPulseOverlay.cs index d8094e3273..91917ea9dc 100644 --- a/Content.Client/StationEvents/RadiationPulseOverlay.cs +++ b/Content.Client/StationEvents/RadiationPulseOverlay.cs @@ -47,7 +47,7 @@ namespace Content.Client.StationEvents // TODO: When worldHandle can do DrawCircle change this. public override OverlaySpace Space => OverlaySpace.ScreenSpace; - public RadiationPulseOverlay() : base(nameof(SharedOverlayID.RadiationPulseOverlay)) + public RadiationPulseOverlay() : base(nameof(RadiationPulseOverlay)) { IoCManager.InjectDependencies(this); _lastTick = _gameTiming.CurTime; @@ -124,7 +124,7 @@ namespace Content.Client.StationEvents _lastTick = _gameTiming.CurTime; var radiationPulses = _componentManager - .EntityQuery() + .EntityQuery(true) .ToList(); var screenHandle = (DrawingHandleScreen) handle; diff --git a/Content.Client/UserInterface/ActionsUI.cs b/Content.Client/UserInterface/ActionsUI.cs index c0c6085279..2c275398e7 100644 --- a/Content.Client/UserInterface/ActionsUI.cs +++ b/Content.Client/UserInterface/ActionsUI.cs @@ -122,23 +122,25 @@ namespace Content.Client.UserInterface hotbarContainer.AddChild(settingsContainer); settingsContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 }); - _lockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock.svg.png"); - _unlockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock_open.svg.png"); + _lockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock.svg.192dpi.png"); + _unlockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock_open.svg.192dpi.png"); _lockButton = new TextureButton { TextureNormal = _unlockTexture, SizeFlagsHorizontal = SizeFlags.ShrinkCenter, SizeFlagsVertical = SizeFlags.ShrinkCenter, - SizeFlagsStretchRatio = 1 + SizeFlagsStretchRatio = 1, + Scale = (0.5f, 0.5f) }; settingsContainer.AddChild(_lockButton); settingsContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 }); _settingsButton = new TextureButton { - TextureNormal = resourceCache.GetTexture("/Textures/Interface/Nano/gear.svg.png"), + TextureNormal = resourceCache.GetTexture("/Textures/Interface/Nano/gear.svg.192dpi.png"), SizeFlagsHorizontal = SizeFlags.ShrinkCenter, SizeFlagsVertical = SizeFlags.ShrinkCenter, - SizeFlagsStretchRatio = 1 + SizeFlagsStretchRatio = 1, + Scale = (0.5f, 0.5f) }; settingsContainer.AddChild(_settingsButton); settingsContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 }); @@ -160,10 +162,11 @@ namespace Content.Client.UserInterface _loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 }); var previousHotbarIcon = new TextureRect() { - Texture = resourceCache.GetTexture("/Textures/Interface/Nano/left_arrow.svg.png"), + Texture = resourceCache.GetTexture("/Textures/Interface/Nano/left_arrow.svg.192dpi.png"), SizeFlagsHorizontal = SizeFlags.ShrinkCenter, SizeFlagsVertical = SizeFlags.ShrinkCenter, - SizeFlagsStretchRatio = 1 + SizeFlagsStretchRatio = 1, + TextureScale = (0.5f, 0.5f) }; _loadoutContainer.AddChild(previousHotbarIcon); _loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 }); @@ -176,10 +179,11 @@ namespace Content.Client.UserInterface _loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 2 }); var nextHotbarIcon = new TextureRect { - Texture = resourceCache.GetTexture("/Textures/Interface/Nano/right_arrow.svg.png"), + Texture = resourceCache.GetTexture("/Textures/Interface/Nano/right_arrow.svg.192dpi.png"), SizeFlagsHorizontal = SizeFlags.ShrinkCenter, SizeFlagsVertical = SizeFlags.ShrinkCenter, - SizeFlagsStretchRatio = 1 + SizeFlagsStretchRatio = 1, + TextureScale = (0.5f, 0.5f) }; _loadoutContainer.AddChild(nextHotbarIcon); _loadoutContainer.AddChild(new Control { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsStretchRatio = 1 }); diff --git a/Content.Client/UserInterface/AdminAddReagentUI.cs b/Content.Client/UserInterface/AdminAddReagentUI.cs new file mode 100644 index 0000000000..adb9986a71 --- /dev/null +++ b/Content.Client/UserInterface/AdminAddReagentUI.cs @@ -0,0 +1,172 @@ +using Content.Client.Eui; +using Content.Shared.Administration; +using Content.Shared.Chemistry; +using Content.Shared.Eui; +using JetBrains.Annotations; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Prototypes; + +namespace Content.Client.UserInterface +{ + [UsedImplicitly] + public sealed class AdminAddReagentEui : BaseEui + { + [Dependency] private readonly IPrototypeManager _prototypes = default!; + + private readonly Menu _window; + private bool _closed; + + public AdminAddReagentEui() + { + _window = new Menu(this); + _window.OnClose += () => SendMessage(new AdminAddReagentEuiMsg.Close()); + } + + public override void Opened() + { + _window.OpenCentered(); + } + + public override void Closed() + { + _closed = true; + + _window.Close(); + } + + public override void HandleState(EuiStateBase state) + { + _window.HandleState((AdminAddReagentEuiState) state); + } + + private void DoAdd(bool close, string reagentId, ReagentUnit amount) + { + SendMessage(new AdminAddReagentEuiMsg.DoAdd + { + Amount = amount, + ReagentId = reagentId, + CloseAfter = close + }); + } + + private sealed class Menu : SS14Window + { + private readonly AdminAddReagentEui _eui; + private readonly Label _volumeLabel; + private readonly LineEdit _reagentIdEdit; + private readonly LineEdit _amountEdit; + private readonly Label _errorLabel; + private readonly Button _addButton; + private readonly Button _addCloseButton; + + public Menu(AdminAddReagentEui eui) + { + _eui = eui; + + Title = Loc.GetString("Add reagent..."); + + Contents.AddChild(new VBoxContainer + { + Children = + { + new GridContainer + { + Columns = 2, + Children = + { + new Label {Text = Loc.GetString("Cur volume: ")}, + (_volumeLabel = new Label()), + new Label {Text = Loc.GetString("Reagent: ")}, + (_reagentIdEdit = new LineEdit {PlaceHolder = Loc.GetString("Reagent ID...")}), + new Label {Text = Loc.GetString("Amount: ")}, + (_amountEdit = new LineEdit + { + PlaceHolder = Loc.GetString("A number..."), + SizeFlagsHorizontal = SizeFlags.FillExpand + }), + }, + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand + }, + new HBoxContainer + { + Children = + { + (_errorLabel = new Label + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + ClipText = true + }), + + (_addButton = new Button {Text = Loc.GetString("Add")}), + (_addCloseButton = new Button {Text = Loc.GetString("Add & Close")}) + } + } + } + }); + + _reagentIdEdit.OnTextChanged += _ => CheckErrors(); + _amountEdit.OnTextChanged += _ => CheckErrors(); + _addButton.OnPressed += _ => DoAdd(false); + _addCloseButton.OnPressed += _ => DoAdd(true); + + CheckErrors(); + } + + private void DoAdd(bool close) + { + _eui.DoAdd( + close, + _reagentIdEdit.Text, + ReagentUnit.New(float.Parse(_amountEdit.Text))); + } + + private void CheckErrors() + { + if (string.IsNullOrWhiteSpace(_reagentIdEdit.Text)) + { + DoError(Loc.GetString("Must specify reagent ID")); + return; + } + + if (!_eui._prototypes.HasIndex(_reagentIdEdit.Text)) + { + DoError(Loc.GetString("'{0}' does not exist.", _reagentIdEdit.Text)); + return; + } + + if (string.IsNullOrWhiteSpace(_amountEdit.Text)) + { + DoError(Loc.GetString("Must specify reagent amount")); + return; + } + + if (!float.TryParse(_amountEdit.Text, out _)) + { + DoError(Loc.GetString("Invalid amount")); + return; + } + + _addButton.Disabled = false; + _addCloseButton.Disabled = false; + _errorLabel.Text = ""; + + void DoError(string text) + { + _errorLabel.Text = text; + + _addButton.Disabled = true; + _addCloseButton.Disabled = true; + } + } + + public void HandleState(AdminAddReagentEuiState state) + { + _volumeLabel.Text = Loc.GetString("{0}/{1}u", state.CurVolume, state.MaxVolume); + } + } + } +} diff --git a/Content.Client/UserInterface/AdminMenu/AdminMenuWindow.cs b/Content.Client/UserInterface/AdminMenu/AdminMenuWindow.cs index c166d2e0d0..56331156ef 100644 --- a/Content.Client/UserInterface/AdminMenu/AdminMenuWindow.cs +++ b/Content.Client/UserInterface/AdminMenu/AdminMenuWindow.cs @@ -440,7 +440,7 @@ namespace Content.Client.UserInterface.AdminMenu public override void ButtonPressed(ButtonEventArgs args) { - IoCManager.Resolve().ProcessCommand(RequiredCommand); + IoCManager.Resolve().ExecuteCommand(RequiredCommand); } } #endregion @@ -504,7 +504,7 @@ namespace Content.Client.UserInterface.AdminMenu Name = "Pause", Handler = () => { - IoCManager.Resolve().ProcessCommand("events pause"); + IoCManager.Resolve().ExecuteCommand("events pause"); }, }, new CommandUIButton @@ -512,14 +512,14 @@ namespace Content.Client.UserInterface.AdminMenu Name = "Resume", Handler = () => { - IoCManager.Resolve().ProcessCommand("events resume"); + IoCManager.Resolve().ExecuteCommand("events resume"); }, }, }; public override void Submit() { - IoCManager.Resolve().ProcessCommand($"events run \"{_eventsDropDown.GetValue()}\""); + IoCManager.Resolve().ExecuteCommand($"events run \"{_eventsDropDown.GetValue()}\""); } } @@ -548,7 +548,7 @@ namespace Content.Client.UserInterface.AdminMenu public override void Submit() { - IoCManager.Resolve().ProcessCommand($"kick \"{_playerDropDown.GetValue()}\" \"{CommandParsing.Escape(_reason.GetValue())}\""); + IoCManager.Resolve().ExecuteCommand($"kick \"{_playerDropDown.GetValue()}\" \"{CommandParsing.Escape(_reason.GetValue())}\""); } } @@ -572,7 +572,7 @@ namespace Content.Client.UserInterface.AdminMenu public override void Submit() { - IoCManager.Resolve().ProcessCommand($"tpto \"{_playerDropDown.GetValue()}\""); + IoCManager.Resolve().ExecuteCommand($"tpto \"{_playerDropDown.GetValue()}\""); } } @@ -596,7 +596,7 @@ namespace Content.Client.UserInterface.AdminMenu public override void Submit() { - IoCManager.Resolve().ProcessCommand($"addatmos {_grid.GetValue()}"); + IoCManager.Resolve().ExecuteCommand($"addatmos {_grid.GetValue()}"); } } @@ -639,7 +639,7 @@ namespace Content.Client.UserInterface.AdminMenu public override void Submit() { - IoCManager.Resolve().ProcessCommand($"fillgas {_grid.GetValue()} {_gas.GetValue()} {_amount.GetValue()}"); + IoCManager.Resolve().ExecuteCommand($"fillgas {_grid.GetValue()} {_gas.GetValue()} {_amount.GetValue()}"); } } #endregion diff --git a/Content.Client/UserInterface/AdminMenu/SetOutfit/SetOutfitMenu.xaml.cs b/Content.Client/UserInterface/AdminMenu/SetOutfit/SetOutfitMenu.xaml.cs index 0f1fba1fbf..9590db8768 100644 --- a/Content.Client/UserInterface/AdminMenu/SetOutfit/SetOutfitMenu.xaml.cs +++ b/Content.Client/UserInterface/AdminMenu/SetOutfit/SetOutfitMenu.xaml.cs @@ -22,7 +22,7 @@ namespace Content.Client.UserInterface.AdminMenu.SetOutfit public partial class SetOutfitMenu : SS14Window { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IClientConsole _console = default!; + [Dependency] private readonly IClientConsoleHost _consoleHost = default!; public EntityUid? TargetEntityId { get; set; } protected override Vector2? CustomSize => (250, 320); @@ -49,7 +49,7 @@ namespace Content.Client.UserInterface.AdminMenu.SetOutfit if (TargetEntityId == null || _selectedOutfit == null) return; var command = $"setoutfit {TargetEntityId} {_selectedOutfit.ID}"; - _console.ProcessCommand(command); + _consoleHost.ExecuteCommand(command); Close(); } diff --git a/Content.Client/UserInterface/Controls/AlertControl.cs b/Content.Client/UserInterface/Controls/AlertControl.cs index 019a899417..383a7db448 100644 --- a/Content.Client/UserInterface/Controls/AlertControl.cs +++ b/Content.Client/UserInterface/Controls/AlertControl.cs @@ -3,7 +3,6 @@ using System; using Content.Shared.Alert; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; -using Robust.Client.Utility; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Maths; @@ -34,11 +33,12 @@ namespace Content.Client.UserInterface.Controls } } } + private (TimeSpan Start, TimeSpan End)? _cooldown; private short? _severity; private readonly IGameTiming _gameTiming; - private readonly TextureRect _icon; + private readonly AnimatedTextureRect _icon; private readonly CooldownGraphic _cooldownGraphic; /// @@ -53,17 +53,17 @@ namespace Content.Client.UserInterface.Controls TooltipSupplier = SupplyTooltip; Alert = alert; _severity = severity; - var texture = alert.GetIcon(_severity).Frame0(); - _icon = new TextureRect + var specifier = alert.GetIcon(_severity); + _icon = new AnimatedTextureRect { - TextureScale = (2, 2), - Texture = texture + DisplayRect = {TextureScale = (2, 2)} }; + _icon.SetFromSpriteSpecifier(specifier); + Children.Add(_icon); _cooldownGraphic = new CooldownGraphic(); Children.Add(_cooldownGraphic); - } private Control SupplyTooltip(Control? sender) @@ -79,7 +79,7 @@ namespace Content.Client.UserInterface.Controls if (_severity != severity) { _severity = severity; - _icon.Texture = Alert.GetIcon(_severity).Frame0(); + _icon.SetFromSpriteSpecifier(Alert.GetIcon(_severity)); } } @@ -99,7 +99,7 @@ namespace Content.Client.UserInterface.Controls var progress = (curTime - Cooldown.Value.Start).TotalSeconds / length; var ratio = (progress <= 1 ? (1 - progress) : (curTime - Cooldown.Value.End).TotalSeconds * -5); - _cooldownGraphic.Progress = MathHelper.Clamp((float)ratio, -1, 1); + _cooldownGraphic.Progress = MathHelper.Clamp((float) ratio, -1, 1); _cooldownGraphic.Visible = ratio > -1f; } } diff --git a/Content.Client/UserInterface/EscapeMenu.cs b/Content.Client/UserInterface/EscapeMenu.cs index 25c8dc85c6..ec346d7522 100644 --- a/Content.Client/UserInterface/EscapeMenu.cs +++ b/Content.Client/UserInterface/EscapeMenu.cs @@ -8,16 +8,16 @@ namespace Content.Client.UserInterface { internal sealed class EscapeMenu : SS14Window { - private readonly IClientConsole _console; + private readonly IClientConsoleHost _consoleHost; private BaseButton DisconnectButton; private BaseButton QuitButton; private BaseButton OptionsButton; private OptionsMenu optionsMenu; - public EscapeMenu(IClientConsole console) + public EscapeMenu(IClientConsoleHost consoleHost) { - _console = console; + _consoleHost = consoleHost; IoCManager.InjectDependencies(this); @@ -50,13 +50,13 @@ namespace Content.Client.UserInterface private void OnQuitButtonClicked(BaseButton.ButtonEventArgs args) { - _console.ProcessCommand("quit"); + _consoleHost.ExecuteCommand("quit"); Dispose(); } private void OnDisconnectButtonClicked(BaseButton.ButtonEventArgs args) { - _console.ProcessCommand("disconnect"); + _consoleHost.ExecuteCommand("disconnect"); Dispose(); } diff --git a/Content.Client/UserInterface/LateJoinGui.cs b/Content.Client/UserInterface/LateJoinGui.cs index c1449ceb11..f4bbc7ecef 100644 --- a/Content.Client/UserInterface/LateJoinGui.cs +++ b/Content.Client/UserInterface/LateJoinGui.cs @@ -21,7 +21,7 @@ namespace Content.Client.UserInterface public sealed class LateJoinGui : SS14Window { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IClientConsole _console = default!; + [Dependency] private readonly IClientConsoleHost _consoleHost = default!; [Dependency] private readonly IClientGameTicker _gameTicker = default!; protected override Vector2? CustomSize => (360, 560); @@ -147,7 +147,7 @@ namespace Content.Client.UserInterface SelectedId += jobId => { Logger.InfoS("latejoin", $"Late joining as ID: {jobId}"); - _console.ProcessCommand($"joingame {CommandParsing.Escape(jobId)}"); + _consoleHost.ExecuteCommand($"joingame {CommandParsing.Escape(jobId)}"); Close(); }; diff --git a/Content.Client/UserInterface/Suspicion/SuspicionGui.xaml b/Content.Client/UserInterface/Suspicion/SuspicionGui.xaml new file mode 100644 index 0000000000..fb22a6d1fa --- /dev/null +++ b/Content.Client/UserInterface/Suspicion/SuspicionGui.xaml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/Content.Client/UserInterface/Suspicion/SuspicionGui.cs b/Content.Client/UserInterface/Suspicion/SuspicionGui.xaml.cs similarity index 61% rename from Content.Client/UserInterface/Suspicion/SuspicionGui.cs rename to Content.Client/UserInterface/Suspicion/SuspicionGui.xaml.cs index d2213379fe..1ac94bc906 100644 --- a/Content.Client/UserInterface/Suspicion/SuspicionGui.cs +++ b/Content.Client/UserInterface/Suspicion/SuspicionGui.xaml.cs @@ -1,48 +1,42 @@ using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using Content.Client.GameObjects.Components.Suspicion; +using Content.Client.GameObjects.EntitySystems; using Content.Shared.Interfaces; +using Robust.Client.AutoGenerated; using Robust.Client.Player; using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Shared.Interfaces.GameObjects; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Maths; using Robust.Shared.Timing; using static Robust.Client.UserInterface.Controls.BaseButton; +#nullable enable + namespace Content.Client.UserInterface.Suspicion { - public class SuspicionGui : Control + [GenerateTypedNameReferences] + public partial class SuspicionGui : Control { [Dependency] private readonly IPlayerManager _playerManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; - private readonly VBoxContainer _container; - private readonly Button _roleButton; - - private string _previousRoleName; + private string? _previousRoleName; private bool _previousAntagonist; public SuspicionGui() { + RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - AddChild(_container = new VBoxContainer - { - SeparationOverride = 0, - Children = - { - (_roleButton = new Button - { - Name = "Suspicion Role Button" - }) - } - }); - - _roleButton.CustomMinimumSize = (200, 60); - _roleButton.OnPressed += RoleButtonPressed; + RoleButton.OnPressed += RoleButtonPressed; + RoleButton.CustomMinimumSize = (200, 60); } private void RoleButtonPressed(ButtonEventArgs obj) @@ -67,11 +61,15 @@ namespace Content.Client.UserInterface.Suspicion role.Owner.PopupMessage(message); } - private bool TryGetComponent(out SuspicionRoleComponent suspicion) + private bool TryGetComponent([NotNullWhen(true)] out SuspicionRoleComponent? suspicion) { suspicion = default; + if (_playerManager.LocalPlayer?.ControlledEntity == null) + { + return false; + } - return _playerManager?.LocalPlayer?.ControlledEntity?.TryGetComponent(out suspicion) == true; + return _playerManager.LocalPlayer.ControlledEntity.TryGetComponent(out suspicion); } public void UpdateLabel() @@ -88,6 +86,22 @@ namespace Content.Client.UserInterface.Suspicion return; } + var endTime = EntitySystem.Get().EndTime; + if (endTime == null) + { + TimerLabel.Visible = false; + } + else + { + var diff = endTime.Value - _timing.CurTime; + if (diff < TimeSpan.Zero) + { + diff = TimeSpan.Zero; + } + TimerLabel.Visible = true; + TimerLabel.Text = $"{diff:mm\\:ss}"; + } + if (_previousRoleName == suspicion.Role && _previousAntagonist == suspicion.Antagonist) { return; @@ -99,8 +113,8 @@ namespace Content.Client.UserInterface.Suspicion var buttonText = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(_previousRoleName); buttonText = Loc.GetString(buttonText); - _roleButton.Text = buttonText; - _roleButton.ModulateSelfOverride = _previousAntagonist ? Color.Red : Color.Green; + RoleButton.Text = buttonText; + RoleButton.ModulateSelfOverride = _previousAntagonist ? Color.Red : Color.Green; Visible = true; } diff --git a/Content.IntegrationTests/DummyGameTicker.cs b/Content.IntegrationTests/DummyGameTicker.cs index 9a98794513..8b8ea88887 100644 --- a/Content.IntegrationTests/DummyGameTicker.cs +++ b/Content.IntegrationTests/DummyGameTicker.cs @@ -6,7 +6,6 @@ using Content.Shared.Roles; using Content.Shared.Preferences; using Content.Server.Mobs; using Robust.Server.Interfaces.Player; -using Robust.Server.Interfaces.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Map; using Robust.Shared.Timing; diff --git a/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs b/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs index bd1484508e..e978f10629 100644 --- a/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs +++ b/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Content.Server.Commands.GameTicking; using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; @@ -40,7 +41,7 @@ namespace Content.IntegrationTests.Tests.Commands tickBeforeRestart = entityManager.CurrentTick; var command = new NewRoundCommand(); - command.Execute(null, null, new string[] { }); + command.Execute(null, string.Empty, Array.Empty()); if (lobbyEnabled) { diff --git a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/CuffUnitTest.cs b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/CuffUnitTest.cs index 96105a3c24..2259df9c43 100644 --- a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/CuffUnitTest.cs +++ b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/CuffUnitTest.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System.Linq; using System.Threading.Tasks; using Content.Client.GameObjects.Components.Items; @@ -7,7 +7,7 @@ using Content.Server.GameObjects.Components.Body; using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Shared.GameObjects.Components.Body; using NUnit.Framework; -using Robust.Server.Interfaces.Console; +using Robust.Server.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -96,8 +96,8 @@ namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking private void AddHand(IEntity to) { - var shell = IoCManager.Resolve(); - shell.ExecuteCommand($"addhand {to.Uid}"); + var host = IoCManager.Resolve(); + host.ExecuteCommand(null, $"addhand {to.Uid}"); } } } diff --git a/Content.IntegrationTests/Tests/Networking/ReconnectTest.cs b/Content.IntegrationTests/Tests/Networking/ReconnectTest.cs index aea01d41c5..780dd49f02 100644 --- a/Content.IntegrationTests/Tests/Networking/ReconnectTest.cs +++ b/Content.IntegrationTests/Tests/Networking/ReconnectTest.cs @@ -27,7 +27,7 @@ namespace Content.IntegrationTests.Tests.Networking await Task.WhenAll(client.WaitIdleAsync(), server.WaitIdleAsync()); - await client.WaitPost(() => IoCManager.Resolve().ProcessCommand("disconnect")); + await client.WaitPost(() => IoCManager.Resolve().ExecuteCommand("disconnect")); // Run some ticks for the disconnect to complete and such. await RunTicksSync(client, server, 5); diff --git a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs index 23ab959a3e..9c1e3e11ab 100644 --- a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs +++ b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs @@ -77,7 +77,7 @@ namespace Content.IntegrationTests.Tests /// Loads the default map, runs it for 5 ticks, then assert that it did not change. /// [Test] - public async Task LoadSaveTicksSaveStationStation() + public async Task LoadSaveTicksSaveSaltern() { var server = StartServerDummyTicker(); await server.WaitIdleAsync(); @@ -92,7 +92,8 @@ namespace Content.IntegrationTests.Tests { var mapId = mapManager.CreateMap(); pauseMgr.AddUninitializedMap(mapId); - grid = mapLoader.LoadBlueprint(mapId, "Maps/stationstation.yml"); + pauseMgr.SetMapPaused(mapId, true); + grid = mapLoader.LoadBlueprint(mapId, "Maps/saltern.yml"); mapLoader.SaveBlueprint(grid.Index, "load save ticks save 1.yml"); }); diff --git a/Content.IntegrationTests/Tests/Tag/TagTest.cs b/Content.IntegrationTests/Tests/Tag/TagTest.cs new file mode 100644 index 0000000000..90b985fb91 --- /dev/null +++ b/Content.IntegrationTests/Tests/Tag/TagTest.cs @@ -0,0 +1,224 @@ +#nullable enable +using System.Collections.Generic; +using System.Threading.Tasks; +using Content.Shared.GameObjects.Components.Tag; +using Content.Shared.Prototypes.Tag; +using NUnit.Framework; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; + +namespace Content.IntegrationTests.Tests.Tag +{ + [TestFixture] + [TestOf(typeof(TagComponent))] + public class TagTest : ContentIntegrationTest + { + private const string TagEntityId = "TagTestDummy"; + + // Register these three into the prototype manager + private const string StartingTag = "A"; + private const string AddedTag = "EIOU"; + private const string UnusedTag = "E"; + + // Do not register this one + private const string UnregisteredTag = "AAAAAAAAA"; + + private static readonly string Prototypes = $@" +- type: Tag + id: {StartingTag} + +- type: Tag + id: {AddedTag} + +- type: Tag + id: {UnusedTag} + +- type: entity + id: {TagEntityId} + name: {TagEntityId} + components: + - type: Tag + tags: + - {StartingTag}"; + + [Test] + public async Task TagComponentTest() + { + var options = new ServerContentIntegrationOption {ExtraPrototypes = Prototypes}; + var server = StartServerDummyTicker(options); + + await server.WaitIdleAsync(); + + var sMapManager = server.ResolveDependency(); + var sEntityManager = server.ResolveDependency(); + var sPrototypeManager = server.ResolveDependency(); + + IEntity sTagDummy = null!; + TagComponent sTagComponent = null!; + + await server.WaitPost(() => + { + sMapManager.CreateNewMapEntity(MapId.Nullspace); + sTagDummy = sEntityManager.SpawnEntity(TagEntityId, MapCoordinates.Nullspace); + sTagComponent = sTagDummy.GetComponent(); + }); + + await server.WaitAssertion(() => + { + // Has one tag, the starting tag + Assert.That(sTagComponent.Tags.Count, Is.EqualTo(1)); + sPrototypeManager.Index(StartingTag); + Assert.That(sTagComponent.Tags, Contains.Item(StartingTag)); + + // Single + Assert.True(sTagDummy.HasTag(StartingTag)); + Assert.True(sTagComponent.HasTag(StartingTag)); + + // Any + Assert.True(sTagDummy.HasAnyTag(StartingTag)); + Assert.True(sTagComponent.HasAnyTag(StartingTag)); + + // All + Assert.True(sTagDummy.HasAllTags(StartingTag)); + Assert.True(sTagComponent.HasAllTags(StartingTag)); + + // Does not have the added tag + var addedTagPrototype = sPrototypeManager.Index(AddedTag); + Assert.That(sTagComponent.Tags, Does.Not.Contains(addedTagPrototype)); + + // Single + Assert.False(sTagDummy.HasTag(AddedTag)); + Assert.False(sTagComponent.HasTag(AddedTag)); + + // Any + Assert.False(sTagDummy.HasAnyTag(AddedTag)); + Assert.False(sTagComponent.HasAnyTag(AddedTag)); + + // All + Assert.False(sTagDummy.HasAllTags(AddedTag)); + Assert.False(sTagComponent.HasAllTags(AddedTag)); + + // Does not have the unused tag + var unusedTagPrototype = sPrototypeManager.Index(UnusedTag); + Assert.That(sTagComponent.Tags, Does.Not.Contains(unusedTagPrototype)); + + // Single + Assert.False(sTagDummy.HasTag(UnusedTag)); + Assert.False(sTagComponent.HasTag(UnusedTag)); + + // Any + Assert.False(sTagDummy.HasAnyTag(UnusedTag)); + Assert.False(sTagComponent.HasAnyTag(UnusedTag)); + + // All + Assert.False(sTagDummy.HasAllTags(UnusedTag)); + Assert.False(sTagComponent.HasAllTags(UnusedTag)); + + // Throws when checking for an unregistered tag + Assert.Throws(() => + { + sPrototypeManager.Index(UnregisteredTag); + }); + + // Single + Assert.Throws(() => + { + sTagDummy.HasTag(UnregisteredTag); + }); + Assert.Throws(() => + { + sTagComponent.HasTag(UnregisteredTag); + }); + + // Any + Assert.Throws(() => + { + sTagDummy.HasAnyTag(UnregisteredTag); + }); + Assert.Throws(() => + { + sTagComponent.HasAnyTag(UnregisteredTag); + }); + + // All + Assert.Throws(() => + { + sTagDummy.HasAllTags(UnregisteredTag); + }); + Assert.Throws(() => + { + sTagComponent.HasAllTags(UnregisteredTag); + }); + + // Cannot add the starting tag again + Assert.That(sTagComponent.AddTag(StartingTag), Is.False); + Assert.That(sTagComponent.AddTags(StartingTag, StartingTag), Is.False); + Assert.That(sTagComponent.AddTags(new List {StartingTag, StartingTag}), Is.False); + + // Has the starting tag + Assert.That(sTagComponent.HasTag(StartingTag), Is.True); + Assert.That(sTagComponent.HasAllTags(StartingTag, StartingTag), Is.True); + Assert.That(sTagComponent.HasAllTags(new List {StartingTag, StartingTag}), Is.True); + Assert.That(sTagComponent.HasAnyTag(StartingTag, StartingTag), Is.True); + Assert.That(sTagComponent.HasAnyTag(new List {StartingTag, StartingTag}), Is.True); + + // Does not have the added tag yet + Assert.That(sTagComponent.HasTag(AddedTag), Is.False); + Assert.That(sTagComponent.HasAllTags(AddedTag, AddedTag), Is.False); + Assert.That(sTagComponent.HasAllTags(new List {AddedTag, AddedTag}), Is.False); + Assert.That(sTagComponent.HasAnyTag(AddedTag, AddedTag), Is.False); + Assert.That(sTagComponent.HasAnyTag(new List {AddedTag, AddedTag}), Is.False); + + // Has a combination of the two tags + Assert.That(sTagComponent.HasAnyTag(StartingTag, AddedTag), Is.True); + Assert.That(sTagComponent.HasAnyTag(new List {StartingTag, AddedTag}), Is.True); + + // Does not have both tags + Assert.That(sTagComponent.HasAllTags(StartingTag, AddedTag), Is.False); + Assert.That(sTagComponent.HasAllTags(new List {StartingTag, AddedTag}), Is.False); + + // Cannot remove a tag that does not exist + Assert.That(sTagComponent.RemoveTag(AddedTag), Is.False); + Assert.That(sTagComponent.RemoveTags(AddedTag, AddedTag), Is.False); + Assert.That(sTagComponent.RemoveTags(new List {AddedTag, AddedTag}), Is.False); + + // Can add the new tag + Assert.That(sTagComponent.AddTag(AddedTag), Is.True); + + // Cannot add it twice + Assert.That(sTagComponent.AddTag(AddedTag), Is.False); + + // Cannot add existing tags + Assert.That(sTagComponent.AddTags(StartingTag, AddedTag), Is.False); + Assert.That(sTagComponent.AddTags(new List {StartingTag, AddedTag}), Is.False); + + // Now has two tags + Assert.That(sTagComponent.Tags.Count, Is.EqualTo(2)); + + // Has both tags + Assert.That(sTagComponent.HasTag(StartingTag), Is.True); + Assert.That(sTagComponent.HasTag(AddedTag), Is.True); + Assert.That(sTagComponent.HasAllTags(StartingTag, StartingTag), Is.True); + Assert.That(sTagComponent.HasAllTags(AddedTag, StartingTag), Is.True); + Assert.That(sTagComponent.HasAllTags(new List {StartingTag, AddedTag}), Is.True); + Assert.That(sTagComponent.HasAllTags(new List {AddedTag, StartingTag}), Is.True); + Assert.That(sTagComponent.HasAnyTag(StartingTag, AddedTag), Is.True); + Assert.That(sTagComponent.HasAnyTag(AddedTag, StartingTag), Is.True); + + // Remove the existing starting tag + Assert.That(sTagComponent.RemoveTag(StartingTag), Is.True); + + // Remove the existing added tag + Assert.That(sTagComponent.RemoveTags(AddedTag, AddedTag), Is.True); + + // No tags left to remove + Assert.That(sTagComponent.RemoveTags(new List {StartingTag, AddedTag}), Is.False); + + // No tags left in the component + Assert.That(sTagComponent.Tags, Is.Empty); + }); + } + } +} diff --git a/Content.Server/Administration/AdminCommandAttribute.cs b/Content.Server/Administration/AdminCommandAttribute.cs index 79ae7fc769..0c9730df82 100644 --- a/Content.Server/Administration/AdminCommandAttribute.cs +++ b/Content.Server/Administration/AdminCommandAttribute.cs @@ -1,7 +1,7 @@ using System; using Content.Shared.Administration; using JetBrains.Annotations; -using Robust.Server.Interfaces.Console; +using Robust.Shared.Console; namespace Content.Server.Administration { @@ -13,7 +13,7 @@ namespace Content.Server.Administration /// /// [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - [BaseTypeRequired(typeof(IClientCommand))] + [BaseTypeRequired(typeof(IConsoleCommand))] [MeansImplicitUse] public sealed class AdminCommandAttribute : Attribute { diff --git a/Content.Server/Administration/AdminManager.cs b/Content.Server/Administration/AdminManager.cs index 4ca81c52fc..c66d4163d1 100644 --- a/Content.Server/Administration/AdminManager.cs +++ b/Content.Server/Administration/AdminManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -12,9 +12,9 @@ using Content.Shared; using Content.Shared.Administration; using Content.Shared.Network.NetMessages; using Robust.Server.Console; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; using Robust.Server.Player; +using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.Network; @@ -37,7 +37,7 @@ namespace Content.Server.Administration [Dependency] private readonly IServerNetManager _netMgr = default!; [Dependency] private readonly IConGroupController _conGroup = default!; [Dependency] private readonly IResourceManager _res = default!; - [Dependency] private readonly IConsoleShell _consoleShell = default!; + [Dependency] private readonly IServerConsoleHost _consoleHost = default!; [Dependency] private readonly IChatManager _chat = default!; private readonly Dictionary _admins = new(); @@ -171,7 +171,7 @@ namespace Content.Server.Administration _netMgr.RegisterNetMessage(MsgUpdateAdminStatus.NAME); // Cache permissions for loaded console commands with the requisite attributes. - foreach (var (cmdName, cmd) in _consoleShell.AvailableCommands) + foreach (var (cmdName, cmd) in _consoleHost.RegisteredCommands) { var (isAvail, flagsReq) = GetRequiredFlag(cmd); @@ -420,7 +420,7 @@ namespace Content.Server.Administration return false; } - private static (bool isAvail, AdminFlags[] flagsReq) GetRequiredFlag(IClientCommand cmd) + private static (bool isAvail, AdminFlags[] flagsReq) GetRequiredFlag(IConsoleCommand cmd) { var type = cmd.GetType(); if (Attribute.IsDefined(type, typeof(AnyCommandAttribute))) diff --git a/Content.Server/Administration/AnyCommandAttribute.cs b/Content.Server/Administration/AnyCommandAttribute.cs index ab9895f728..0185cff723 100644 --- a/Content.Server/Administration/AnyCommandAttribute.cs +++ b/Content.Server/Administration/AnyCommandAttribute.cs @@ -1,6 +1,6 @@ using System; using JetBrains.Annotations; -using Robust.Server.Interfaces.Console; +using Robust.Shared.Console; namespace Content.Server.Administration { @@ -9,7 +9,7 @@ namespace Content.Server.Administration /// /// [AttributeUsage(AttributeTargets.Class)] - [BaseTypeRequired(typeof(IClientCommand))] + [BaseTypeRequired(typeof(IConsoleCommand))] [MeansImplicitUse] public sealed class AnyCommandAttribute : Attribute { diff --git a/Content.Server/Administration/Commands/AGhost.cs b/Content.Server/Administration/Commands/AGhost.cs index eddc879dde..7d7bd0720f 100644 --- a/Content.Server/Administration/Commands/AGhost.cs +++ b/Content.Server/Administration/Commands/AGhost.cs @@ -3,25 +3,26 @@ using Content.Server.GameObjects.Components.Observer; using Content.Server.Interfaces.GameTicking; using Content.Server.Players; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - public class AGhost : IClientCommand + public class AGhost : IConsoleCommand { public string Command => "aghost"; public string Description => "Makes you an admin ghost."; public string Help => "aghost"; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText((IPlayerSession) null, "Nah"); + shell.WriteLine("Nah"); return; } @@ -29,7 +30,7 @@ namespace Content.Server.Administration.Commands if (mind == null) { - shell.SendText(player, "You can't ghost here!"); + shell.WriteLine("You can't ghost here!"); return; } diff --git a/Content.Server/Administration/Commands/BanCommand.cs b/Content.Server/Administration/Commands/BanCommand.cs index f542d1c0c2..3d906be036 100644 --- a/Content.Server/Administration/Commands/BanCommand.cs +++ b/Content.Server/Administration/Commands/BanCommand.cs @@ -1,8 +1,8 @@ -using System; +using System; using Content.Server.Database; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; using Robust.Shared.Network; @@ -11,14 +11,15 @@ using Robust.Shared.Network; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Ban)] - public sealed class BanCommand : IClientCommand + public sealed class BanCommand : IConsoleCommand { public string Command => "ban"; public string Description => "Bans somebody"; public string Help => "Usage: "; - public async void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public async void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; var plyMgr = IoCManager.Resolve(); var dbMan = IoCManager.Resolve(); @@ -37,7 +38,7 @@ namespace Content.Server.Administration.Commands } else { - shell.SendText(player, "Unable to find user with that name."); + shell.WriteLine("Unable to find user with that name."); return; } diff --git a/Content.Server/Administration/Commands/ControlMob.cs b/Content.Server/Administration/Commands/ControlMob.cs index 1e979e633a..2e830269df 100644 --- a/Content.Server/Administration/Commands/ControlMob.cs +++ b/Content.Server/Administration/Commands/ControlMob.cs @@ -2,8 +2,8 @@ using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Observer; using Content.Server.Players; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -12,23 +12,24 @@ using Robust.Shared.Localization; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - class ControlMob : IClientCommand + class ControlMob : IConsoleCommand { public string Command => "controlmob"; public string Description => Loc.GetString("Transfers user mind to the specified entity."); public string Help => Loc.GetString("Usage: controlmob ."); - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText((IPlayerSession) null, "Server cannot do this."); + shell.WriteLine("Server cannot do this."); return; } if (args.Length != 1) { - shell.SendText(player, Loc.GetString("Wrong number of arguments.")); + shell.WriteLine(Loc.GetString("Wrong number of arguments.")); return; } @@ -38,7 +39,7 @@ namespace Content.Server.Administration.Commands if (!int.TryParse(args[0], out var targetId)) { - shell.SendText(player, Loc.GetString("Argument must be a number.")); + shell.WriteLine(Loc.GetString("Argument must be a number.")); return; } @@ -46,14 +47,14 @@ namespace Content.Server.Administration.Commands if (!eUid.IsValid() || !entityManager.EntityExists(eUid)) { - shell.SendText(player, Loc.GetString("Invalid entity ID.")); + shell.WriteLine(Loc.GetString("Invalid entity ID.")); return; } var target = entityManager.GetEntity(eUid); if (!target.TryGetComponent(out MindComponent mindComponent)) { - shell.SendText(player, Loc.GetString("Target entity is not a mob!")); + shell.WriteLine(Loc.GetString("Target entity is not a mob!")); return; } diff --git a/Content.Server/Administration/Commands/DSay.cs b/Content.Server/Administration/Commands/DSay.cs index 40bf93b5b5..b2a1d021af 100644 --- a/Content.Server/Administration/Commands/DSay.cs +++ b/Content.Server/Administration/Commands/DSay.cs @@ -1,14 +1,14 @@ using Content.Server.Interfaces.Chat; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; using Robust.Shared.Localization; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - class DSay : IClientCommand + class DSay : IConsoleCommand { public string Command => "dsay"; @@ -16,11 +16,12 @@ namespace Content.Server.Administration.Commands public string Help => Loc.GetString($"Usage: {Command} "); - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText((IPlayerSession) null, "Only players can use this command"); + shell.WriteLine("Only players can use this command"); return; } diff --git a/Content.Server/Administration/Commands/DeAdminCommand.cs b/Content.Server/Administration/Commands/DeAdminCommand.cs index 81a61194cf..057d942218 100644 --- a/Content.Server/Administration/Commands/DeAdminCommand.cs +++ b/Content.Server/Administration/Commands/DeAdminCommand.cs @@ -1,7 +1,7 @@ -using Content.Shared.Administration; +using Content.Shared.Administration; using JetBrains.Annotations; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; #nullable enable @@ -10,17 +10,18 @@ namespace Content.Server.Administration.Commands { [UsedImplicitly] [AdminCommand(AdminFlags.None)] - public class DeAdminCommand : IClientCommand + public class DeAdminCommand : IConsoleCommand { public string Command => "deadmin"; public string Description => "Temporarily de-admins you so you can experience the round as a normal player."; public string Help => "Usage: deadmin\nUse readmin to re-admin after using this."; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "You cannot use this command from the server console."); + shell.WriteLine("You cannot use this command from the server console."); return; } diff --git a/Content.Server/Administration/Commands/DeleteComponent.cs b/Content.Server/Administration/Commands/DeleteComponent.cs index 2fbeb0ce91..5e6941b52f 100644 --- a/Content.Server/Administration/Commands/DeleteComponent.cs +++ b/Content.Server/Administration/Commands/DeleteComponent.cs @@ -1,25 +1,25 @@ #nullable enable using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - public class DeleteComponent : IClientCommand + public class DeleteComponent : IConsoleCommand { public string Command => "deletecomponent"; public string Description => "Deletes all instances of the specified component."; public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { switch (args.Length) { case 0: - shell.SendText(player, $"Not enough arguments.\n{Help}"); + shell.WriteLine($"Not enough arguments.\n{Help}"); break; default: var name = string.Join(" ", args); @@ -28,12 +28,12 @@ namespace Content.Server.Administration.Commands if (!componentFactory.TryGetRegistration(name, out var registration)) { - shell.SendText(player, $"No component exists with name {name}."); + shell.WriteLine($"No component exists with name {name}."); break; } var componentType = registration.Type; - var components = entityManager.ComponentManager.GetAllComponents(componentType); + var components = entityManager.ComponentManager.GetAllComponents(componentType, true); var i = 0; @@ -44,7 +44,7 @@ namespace Content.Server.Administration.Commands i++; } - shell.SendText(player, $"Removed {i} components with name {name}."); + shell.WriteLine($"Removed {i} components with name {name}."); break; } diff --git a/Content.Server/Administration/Commands/DeleteEntitiesWithComponent.cs b/Content.Server/Administration/Commands/DeleteEntitiesWithComponent.cs index f87bd7a99b..c8849b1e2b 100644 --- a/Content.Server/Administration/Commands/DeleteEntitiesWithComponent.cs +++ b/Content.Server/Administration/Commands/DeleteEntitiesWithComponent.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -11,7 +11,7 @@ using Robust.Shared.Localization; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - class DeleteEntitiesWithComponent : IClientCommand + class DeleteEntitiesWithComponent : IConsoleCommand { public string Command => "deleteewc"; public string Description @@ -29,11 +29,11 @@ namespace Content.Server.Administration.Commands } } - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } @@ -54,7 +54,7 @@ namespace Content.Server.Administration.Commands count += 1; } - shell.SendText(player, Loc.GetString("Deleted {0} entities", count)); + shell.WriteLine(Loc.GetString("Deleted {0} entities", count)); } } } diff --git a/Content.Server/Administration/Commands/DeleteEntitiesWithId.cs b/Content.Server/Administration/Commands/DeleteEntitiesWithId.cs index d7ff635c10..8ff64ce231 100644 --- a/Content.Server/Administration/Commands/DeleteEntitiesWithId.cs +++ b/Content.Server/Administration/Commands/DeleteEntitiesWithId.cs @@ -1,7 +1,7 @@ #nullable enable using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -9,17 +9,17 @@ using Robust.Shared.IoC; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - public class DeleteEntitiesWithId : IClientCommand + public class DeleteEntitiesWithId : IConsoleCommand { public string Command => "deleteewi"; public string Description => "Deletes entities with the specified prototype ID."; public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } @@ -35,7 +35,7 @@ namespace Content.Server.Administration.Commands i++; } - shell.SendText(player, $"Deleted all entities with id {id}. Occurrences: {i}"); + shell.WriteLine($"Deleted all entities with id {id}. Occurrences: {i}"); } } } diff --git a/Content.Server/Administration/Commands/ExplosionCommand.cs b/Content.Server/Administration/Commands/ExplosionCommand.cs new file mode 100644 index 0000000000..eef777b895 --- /dev/null +++ b/Content.Server/Administration/Commands/ExplosionCommand.cs @@ -0,0 +1,42 @@ +using Content.Server.Explosions; +using Content.Shared.Administration; +using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; +using Robust.Shared.Map; + +#nullable enable + +namespace Content.Server.Administration.Commands +{ + [AdminCommand(AdminFlags.Fun)] + public sealed class ExplosionCommand : IConsoleCommand + { + public string Command => "explode"; + public string Description => "Train go boom"; + public string Help => "Usage: explode \n" + + "The explosion happens on the same map as the user."; + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + var player = shell.Player as IPlayerSession; + if (player?.AttachedEntity == null) + { + shell.WriteLine("You must have an attached entity."); + return; + } + + var x = float.Parse(args[0]); + var y = float.Parse(args[1]); + + var dev = int.Parse(args[2]); + var hvy = int.Parse(args[3]); + var lgh = int.Parse(args[4]); + var fla = int.Parse(args[5]); + + var mapTransform = player.AttachedEntity.Transform.GetMapTransform(); + var coords = new EntityCoordinates(mapTransform.Owner.Uid, x, y); + + ExplosionHelper.SpawnExplosion(coords, dev, hvy, lgh, fla); + } + } +} diff --git a/Content.Server/Administration/Commands/OpenPermissionsCommand.cs b/Content.Server/Administration/Commands/OpenPermissionsCommand.cs index 093a10733a..eeb8551f0a 100644 --- a/Content.Server/Administration/Commands/OpenPermissionsCommand.cs +++ b/Content.Server/Administration/Commands/OpenPermissionsCommand.cs @@ -1,7 +1,7 @@ -using Content.Server.Eui; +using Content.Server.Eui; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; #nullable enable @@ -9,17 +9,18 @@ using Robust.Shared.IoC; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Permissions)] - public sealed class OpenPermissionsCommand : IClientCommand + public sealed class OpenPermissionsCommand : IConsoleCommand { public string Command => "permissions"; public string Description => "Opens the admin permissions panel."; public string Help => "Usage: permissions"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "This does not work from the server console."); + shell.WriteLine("This does not work from the server console."); return; } diff --git a/Content.Server/Administration/Commands/PromoteHostCommand.cs b/Content.Server/Administration/Commands/PromoteHostCommand.cs index 058557fa14..b81efefb04 100644 --- a/Content.Server/Administration/Commands/PromoteHostCommand.cs +++ b/Content.Server/Administration/Commands/PromoteHostCommand.cs @@ -1,30 +1,30 @@ #nullable enable using JetBrains.Annotations; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Administration.Commands { [UsedImplicitly] - public sealed class PromoteHostCommand : IClientCommand + public sealed class PromoteHostCommand : IConsoleCommand { public string Command => "promotehost"; public string Description => "Grants client temporary full host admin privileges. Use this to bootstrap admins."; public string Help => "Usage promotehost "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 1) { - shell.SendText(player, "Expected exactly one argument."); + shell.WriteLine("Expected exactly one argument."); return; } var plyMgr = IoCManager.Resolve(); if (!plyMgr.TryGetSessionByUsername(args[0], out var targetPlayer)) { - shell.SendText(player, "Unable to find a player by that name."); + shell.WriteLine("Unable to find a player by that name."); return; } diff --git a/Content.Server/Administration/Commands/ReAdminCommand.cs b/Content.Server/Administration/Commands/ReAdminCommand.cs index 8f78442689..100bdf92ef 100644 --- a/Content.Server/Administration/Commands/ReAdminCommand.cs +++ b/Content.Server/Administration/Commands/ReAdminCommand.cs @@ -1,5 +1,5 @@ -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; #nullable enable @@ -7,17 +7,18 @@ using Robust.Shared.IoC; namespace Content.Server.Administration.Commands { [AnyCommand] - public class ReAdminCommand : IClientCommand + public class ReAdminCommand : IConsoleCommand { public string Command => "readmin"; public string Description => "Re-admins you if you previously de-adminned."; public string Help => "Usage: readmin"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "You cannot use this command from the server console."); + shell.WriteLine("You cannot use this command from the server console."); return; } @@ -25,7 +26,7 @@ namespace Content.Server.Administration.Commands if (mgr.GetAdminData(player, includeDeAdmin: true) == null) { - shell.SendText(player, "You're not an admin."); + shell.WriteLine("You're not an admin."); return; } diff --git a/Content.Server/Administration/Commands/ReadyAll.cs b/Content.Server/Administration/Commands/ReadyAll.cs index ec703bb5b7..f37ef7c7dd 100644 --- a/Content.Server/Administration/Commands/ReadyAll.cs +++ b/Content.Server/Administration/Commands/ReadyAll.cs @@ -2,19 +2,19 @@ using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Server)] - public class ReadyAll : IClientCommand + public class ReadyAll : IConsoleCommand { public string Command => "readyall"; public string Description => "Readies up all players in the lobby."; public string Help => $"{Command} | ̣{Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var ready = true; @@ -29,7 +29,7 @@ namespace Content.Server.Administration.Commands if (gameTicker.RunLevel != GameRunLevel.PreRoundLobby) { - shell.SendText(player, "This command can only be ran while in the lobby!"); + shell.WriteLine("This command can only be ran while in the lobby!"); return; } diff --git a/Content.Server/Administration/Commands/Rejuvenate.cs b/Content.Server/Administration/Commands/Rejuvenate.cs index 69c79a36b8..7134e5d590 100644 --- a/Content.Server/Administration/Commands/Rejuvenate.cs +++ b/Content.Server/Administration/Commands/Rejuvenate.cs @@ -1,7 +1,7 @@ -using Content.Server.GlobalVerbs; +using Content.Server.GlobalVerbs; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -10,7 +10,7 @@ using Robust.Shared.Localization; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - class Rejuvenate : IClientCommand + class Rejuvenate : IConsoleCommand { public string Command => "rejuvenate"; public string Description @@ -28,14 +28,15 @@ namespace Content.Server.Administration.Commands } } - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (args.Length < 1 && player != null) //Try to heal the users mob if applicable { - shell.SendText(player, Loc.GetString("Healing the user's mob since no arguments were provided.")); + shell.WriteLine(Loc.GetString("Healing the user's mob since no arguments were provided.")); if (player.AttachedEntity == null) { - shell.SendText(player, Loc.GetString("There's no entity attached to the user.")); + shell.WriteLine(Loc.GetString("There's no entity attached to the user.")); return; } RejuvenateVerb.PerformRejuvenate(player.AttachedEntity); @@ -46,7 +47,7 @@ namespace Content.Server.Administration.Commands { if(!EntityUid.TryParse(arg, out var uid) || !entityManager.TryGetEntity(uid, out var entity)) { - shell.SendText(player, Loc.GetString("Could not find entity {0}", arg)); + shell.WriteLine(Loc.GetString("Could not find entity {0}", arg)); continue; } RejuvenateVerb.PerformRejuvenate(entity); diff --git a/Content.Server/Administration/Commands/SetMindCommand.cs b/Content.Server/Administration/Commands/SetMindCommand.cs new file mode 100644 index 0000000000..b868c9f20e --- /dev/null +++ b/Content.Server/Administration/Commands/SetMindCommand.cs @@ -0,0 +1,82 @@ +#nullable enable +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.Mobs; +using Content.Server.Players; +using Content.Shared.Administration; +using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; + +namespace Content.Server.Administration.Commands +{ + [AdminCommand(AdminFlags.Admin)] + class SetMindCommand : IConsoleCommand + { + public string Command => "setmind"; + + public string Description => Loc.GetString("Transfers a mind to the specified entity. The entity must have a MindComponent."); + + public string Help => Loc.GetString("Usage: {0} ", Command); + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length != 2) + { + shell.WriteLine(Loc.GetString("Wrong number of arguments.")); + return; + } + + if (!int.TryParse(args[0], out var entityUid)) + { + shell.WriteLine(Loc.GetString("EntityUid must be a number.")); + return; + } + + var entityManager = IoCManager.Resolve(); + + var eUid = new EntityUid(entityUid); + + if (!eUid.IsValid() || !entityManager.EntityExists(eUid)) + { + shell.WriteLine(Loc.GetString("Invalid entity ID.")); + return; + } + + var target = entityManager.GetEntity(eUid); + + if (!target.TryGetComponent(out var mindComponent)) + { + shell.WriteLine(Loc.GetString("Target entity does not have a mind (did you forget to make sentient?)")); + return; + } + + if (!IoCManager.Resolve().TryGetSessionByUsername(args[1], out var session)) + { + shell.WriteLine(Loc.GetString("Target player does not exist")); + return; + } + + // hm, does player have a mind? if not we may need to give them one + var playerCData = session.ContentData(); + if (playerCData == null) + { + shell.WriteLine(Loc.GetString("Target player does not have content data (wtf?)")); + return; + } + + var mind = playerCData.Mind; + if (mind == null) + { + mind = new Mind(session.UserId) + { + CharacterName = target.Name + }; + playerCData.Mind = mind; + } + mind.TransferTo(target); + } + } +} diff --git a/Content.Server/Administration/Commands/SetOutfitCommand.cs b/Content.Server/Administration/Commands/SetOutfitCommand.cs index f6e0b2b064..ea6b84bc8a 100644 --- a/Content.Server/Administration/Commands/SetOutfitCommand.cs +++ b/Content.Server/Administration/Commands/SetOutfitCommand.cs @@ -3,8 +3,8 @@ using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.Items.Storage; using Content.Shared.Administration; using Content.Shared.Roles; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -14,7 +14,7 @@ using Robust.Shared.Prototypes; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - class SetOutfitCommand : IClientCommand + class SetOutfitCommand : IConsoleCommand { public string Command => "setoutfit"; @@ -22,17 +22,17 @@ namespace Content.Server.Administration.Commands public string Help => Loc.GetString("Usage: {0} | {0} ", Command); - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 1) { - shell.SendText(player, Loc.GetString("Wrong number of arguments.")); + shell.WriteLine(Loc.GetString("Wrong number of arguments.")); return; } if (!int.TryParse(args[0], out var entityUid)) { - shell.SendText(player, Loc.GetString("EntityUid must be a number.")); + shell.WriteLine(Loc.GetString("EntityUid must be a number.")); return; } @@ -42,7 +42,7 @@ namespace Content.Server.Administration.Commands if (!eUid.IsValid() || !entityManager.EntityExists(eUid)) { - shell.SendText(player, Loc.GetString("Invalid entity ID.")); + shell.WriteLine(Loc.GetString("Invalid entity ID.")); return; } @@ -50,7 +50,7 @@ namespace Content.Server.Administration.Commands if (!target.TryGetComponent(out var inventoryComponent)) { - shell.SendText(player, Loc.GetString("Target entity does not have an inventory!")); + shell.WriteLine(Loc.GetString("Target entity does not have an inventory!")); return; } @@ -58,6 +58,7 @@ namespace Content.Server.Administration.Commands { var eui = IoCManager.Resolve(); var ui = new SetOutfitEui(target); + var player = shell.Player as IPlayerSession; eui.OpenEui(ui, player); return; } @@ -65,7 +66,7 @@ namespace Content.Server.Administration.Commands var prototypeManager = IoCManager.Resolve(); if (!prototypeManager.TryIndex(args[1], out var startingGear)) { - shell.SendText(player, Loc.GetString("Invalid outfit id")); + shell.WriteLine(Loc.GetString("Invalid outfit id")); return; } diff --git a/Content.Server/Administration/Commands/WarpCommand.cs b/Content.Server/Administration/Commands/WarpCommand.cs index 6e48b9637d..9170dc2da0 100644 --- a/Content.Server/Administration/Commands/WarpCommand.cs +++ b/Content.Server/Administration/Commands/WarpCommand.cs @@ -1,9 +1,9 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Markers; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; @@ -14,7 +14,7 @@ using Robust.Shared.Map; namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Admin)] - public class WarpCommand : IClientCommand + public class WarpCommand : IConsoleCommand { public string Command => "warp"; public string Description => "Teleports you to predefined areas on the map."; @@ -23,17 +23,18 @@ namespace Content.Server.Administration.Commands "warp \nLocations you can teleport to are predefined by the map. " + "You can specify '?' as location to get a list of valid locations."; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText((IPlayerSession) null, "Only players can use this command"); + shell.WriteLine("Only players can use this command"); return; } if (args.Length != 1) { - shell.SendText(player, "Expected a single argument."); + shell.WriteLine("Expected a single argument."); return; } @@ -42,19 +43,19 @@ namespace Content.Server.Administration.Commands if (location == "?") { var locations = string.Join(", ", - comp.EntityQuery() + comp.EntityQuery(true) .Select(p => p.Location) .Where(p => p != null) .OrderBy(p => p) .Distinct()); - shell.SendText(player, locations); + shell.WriteLine(locations); } else { if (player.Status != SessionStatus.InGame || player.AttachedEntity == null) { - shell.SendText(player, "You are not in-game!"); + shell.WriteLine("You are not in-game!"); return; } @@ -63,7 +64,7 @@ namespace Content.Server.Administration.Commands var currentGrid = player.AttachedEntity.Transform.GridID; var entityManager = IoCManager.Resolve(); - var found = comp.EntityQuery() + var found = comp.EntityQuery(true) .Where(p => p.Location == location) .Select(p => p.Owner.Transform.Coordinates) .OrderBy(p => p, Comparer.Create((a, b) => @@ -121,7 +122,7 @@ namespace Content.Server.Administration.Commands } else { - shell.SendText(player, "That location does not exist!"); + shell.WriteLine("That location does not exist!"); } } } diff --git a/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs new file mode 100644 index 0000000000..2079ac32b5 --- /dev/null +++ b/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs @@ -0,0 +1,162 @@ +#nullable enable +using System; +using Content.Server.GameObjects.Components.Chemistry; +using Content.Server.Interfaces.Chemistry; +using Content.Server.Utility; +using Content.Shared.Audio; +using JetBrains.Annotations; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Serialization; + +namespace Content.Server.Chemistry.ReactionEffects +{ + /// + /// Basically smoke and foam reactions. + /// + [UsedImplicitly] + public abstract class AreaReactionEffect : IReactionEffect + { + [Dependency] private readonly IMapManager _mapManager = default!; + + /// + /// Used for calculating the spread range of the effect based on the intensity of the reaction. + /// + private float _rangeConstant; + private float _rangeMultiplier; + private int _maxRange; + + /// + /// If true the reagents get diluted or concentrated depending on the range of the effect + /// + private bool _diluteReagents; + + /// + /// At what range should the reagents volume stay the same. If the effect range is higher than this then the reagents + /// will get diluted. If the effect range is lower than this then the reagents will get concentrated. + /// + private int _reagentDilutionStart; + + /// + /// Used to calculate dilution. Increasing this makes the reagents get more diluted. This means that a lower range + /// will be needed to make the reagents volume get closer to zero. + /// + private float _reagentDilutionFactor; + + /// + /// Used to calculate concentration. Reagents get linearly more concentrated as the range goes from + /// _reagentDilutionStart to zero. When the range is zero the reagents volume gets multiplied by this. + /// + private float _reagentMaxConcentrationFactor; + + /// + /// How many seconds will the effect stay, counting after fully spreading. + /// + private float _duration; + + /// + /// How many seconds between each spread step. + /// + private float _spreadDelay; + + /// + /// How many seconds between each remove step. + /// + private float _removeDelay; + + /// + /// The entity prototype that will be spawned as the effect. It needs a component derived from SolutionAreaEffectComponent. + /// + private string? _prototypeId; + + /// + /// Sound that will get played when this reaction effect occurs. + /// + private string? _sound; + + protected AreaReactionEffect() + { + IoCManager.InjectDependencies(this); + } + + public void ExposeData(ObjectSerializer serializer) + { + serializer.DataField(ref _rangeConstant, "rangeConstant",0f); + serializer.DataField(ref _rangeMultiplier, "rangeMultiplier",1.1f); + serializer.DataField(ref _maxRange, "maxRange", 10); + serializer.DataField(ref _diluteReagents, "diluteReagents", false); + serializer.DataField(ref _reagentDilutionStart, "reagentDilutionStart", 4); + serializer.DataField(ref _reagentDilutionFactor, "reagentDilutionFactor", 1f); + serializer.DataField(ref _reagentMaxConcentrationFactor, "reagentMaxConcentrationFactor",2f); + serializer.DataField(ref _duration, "duration", 10f); + serializer.DataField(ref _spreadDelay, "spreadDelay", 0.5f); + serializer.DataField(ref _removeDelay, "removeDelay", 0.5f); + serializer.DataField(ref _sound, "sound", null); + serializer.DataField(ref _prototypeId, "prototypeId", null); + + if (_prototypeId == null) + Logger.Error("prototypeId wasn't provided to AreaReactionEffect, check yaml"); + } + + public void React(IEntity solutionEntity, double intensity) + { + if (!solutionEntity.TryGetComponent(out SolutionContainerComponent? contents)) + return; + + var solution = contents.SplitSolution(contents.MaxVolume); + // We take the square root so it becomes harder to reach higher amount values + var amount = (int) Math.Round(_rangeConstant + _rangeMultiplier*Math.Sqrt(intensity)); + amount = Math.Min(amount, _maxRange); + + if (_diluteReagents) + { + // The maximum value of solutionFraction is _reagentMaxConcentrationFactor, achieved when amount = 0 + // The infimum of solutionFraction is 0, which is approached when amount tends to infinity + // solutionFraction is equal to 1 only when amount equals _reagentDilutionStart + float solutionFraction; + if (amount >= _reagentDilutionStart) + { + // Weird formulas here but basically when amount increases, solutionFraction gets closer to 0 in a reciprocal manner + // _reagentDilutionFactor defines how fast solutionFraction gets closer to 0 + solutionFraction = 1 / (_reagentDilutionFactor*(amount - _reagentDilutionStart) + 1); + } + else + { + // Here when amount decreases, solutionFraction gets closer to _reagentMaxConcentrationFactor in a linear manner + solutionFraction = amount * (1 - _reagentMaxConcentrationFactor) / _reagentDilutionStart + + _reagentMaxConcentrationFactor; + } + solution.RemoveSolution(solution.TotalVolume*(1-solutionFraction)); + } + + if (!_mapManager.TryFindGridAt(solutionEntity.Transform.MapPosition, out var grid)) return; + + var coords = grid.MapToGrid(solutionEntity.Transform.MapPosition); + + var ent = solutionEntity.EntityManager.SpawnEntity(_prototypeId, coords.SnapToGrid()); + + var areaEffectComponent = GetAreaEffectComponent(ent); + + if (areaEffectComponent == null) + { + Logger.Error("Couldn't get AreaEffectComponent from " + _prototypeId); + ent.Delete(); + return; + } + + areaEffectComponent.TryAddSolution(solution); + areaEffectComponent.Start(amount, _duration, _spreadDelay, _removeDelay); + + if (!string.IsNullOrEmpty(_sound)) + { + EntitySystem.Get().PlayFromEntity(_sound, solutionEntity, AudioHelpers.WithVariation(0.125f)); + } + } + + protected abstract SolutionAreaEffectComponent? GetAreaEffectComponent(IEntity entity); + } +} diff --git a/Content.Server/Chemistry/ReactionEffects/FoamAreaReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/FoamAreaReactionEffect.cs new file mode 100644 index 0000000000..edc6a26285 --- /dev/null +++ b/Content.Server/Chemistry/ReactionEffects/FoamAreaReactionEffect.cs @@ -0,0 +1,16 @@ +#nullable enable +using Content.Server.GameObjects.Components.Chemistry; +using JetBrains.Annotations; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Chemistry.ReactionEffects +{ + [UsedImplicitly] + public class FoamAreaReactionEffect : AreaReactionEffect + { + protected override SolutionAreaEffectComponent? GetAreaEffectComponent(IEntity entity) + { + return entity.GetComponentOrNull(); + } + } +} diff --git a/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs new file mode 100644 index 0000000000..3a78557321 --- /dev/null +++ b/Content.Server/Chemistry/ReactionEffects/SmokeAreaReactionEffect.cs @@ -0,0 +1,16 @@ +#nullable enable +using Content.Server.GameObjects.Components.Chemistry; +using JetBrains.Annotations; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.Chemistry.ReactionEffects +{ + [UsedImplicitly] + public class SmokeAreaReactionEffect : AreaReactionEffect + { + protected override SolutionAreaEffectComponent? GetAreaEffectComponent(IEntity entity) + { + return entity.GetComponentOrNull(); + } + } +} diff --git a/Content.Server/Commands/AI/AddAiCommand.cs b/Content.Server/Commands/AI/AddAiCommand.cs index 395bae79bf..184341fc1f 100644 --- a/Content.Server/Commands/AI/AddAiCommand.cs +++ b/Content.Server/Commands/AI/AddAiCommand.cs @@ -4,8 +4,8 @@ using Content.Server.GameObjects.Components.Movement; using Content.Server.GameObjects.EntitySystems.AI; using Content.Shared.Administration; using Content.Shared.GameObjects.Components.Movement; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; @@ -14,7 +14,7 @@ using Robust.Shared.IoC; namespace Content.Server.Commands.AI { [AdminCommand(AdminFlags.Fun)] - public class AddAiCommand : IClientCommand + public class AddAiCommand : IConsoleCommand { public string Command => "addai"; public string Description => "Add an ai component with a given processor to an entity."; @@ -22,11 +22,11 @@ namespace Content.Server.Commands.AI + "\n processorId: Class that inherits AiLogicProcessor and has an AiLogicProcessor attribute." + "\n entityID: Uid of entity to add the AiControllerComponent to. Open its VV menu to find this."; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if(args.Length != 2) { - shell.SendText(player, "Wrong number of args."); + shell.WriteLine("Wrong number of args."); return; } @@ -37,12 +37,12 @@ namespace Content.Server.Commands.AI if (!aiSystem.ProcessorTypeExists(processorId)) { - shell.SendText(player, "Invalid processor type. Processor must inherit AiLogicProcessor and have an AiLogicProcessor attribute."); + shell.WriteLine("Invalid processor type. Processor must inherit AiLogicProcessor and have an AiLogicProcessor attribute."); return; } if (ent.HasComponent()) { - shell.SendText(player, "Entity already has an AI component."); + shell.WriteLine("Entity already has an AI component."); return; } @@ -53,7 +53,7 @@ namespace Content.Server.Commands.AI var comp = ent.AddComponent(); comp.LogicName = processorId; - shell.SendText(player, "AI component added."); + shell.WriteLine("AI component added."); } } } diff --git a/Content.Server/Commands/AI/FactionCommand.cs b/Content.Server/Commands/AI/FactionCommand.cs index ae0107ff62..a040c082a3 100644 --- a/Content.Server/Commands/AI/FactionCommand.cs +++ b/Content.Server/Commands/AI/FactionCommand.cs @@ -4,22 +4,22 @@ using Content.Server.Administration; using Content.Server.GameObjects.Components.AI; using Content.Server.GameObjects.EntitySystems.AI; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Localization; namespace Content.Server.Commands.AI { [AdminCommand(AdminFlags.Fun)] - public sealed class FactionCommand : IClientCommand + public sealed class FactionCommand : IConsoleCommand { public string Command => "factions"; public string Description => "Update / list factional relationships for NPCs."; public string Help => "faction target\n" + "faction list: hostile factions"; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length == 0) { @@ -31,19 +31,19 @@ namespace Content.Server.Commands.AI result.Append(value + "\n"); } - shell.SendText(player, result.ToString()); + shell.WriteLine(result.ToString()); return; } if (args.Length < 2) { - shell.SendText(player, Loc.GetString("Need more args")); + shell.WriteLine(Loc.GetString("Need more args")); return; } if (!Enum.TryParse(args[0], true, out Faction faction)) { - shell.SendText(player, Loc.GetString("Invalid faction")); + shell.WriteLine(Loc.GetString("Invalid faction")); return; } @@ -54,40 +54,40 @@ namespace Content.Server.Commands.AI case "friendly": if (args.Length < 3) { - shell.SendText(player, Loc.GetString("Need to supply a target faction")); + shell.WriteLine(Loc.GetString("Need to supply a target faction")); return; } if (!Enum.TryParse(args[2], true, out targetFaction)) { - shell.SendText(player, Loc.GetString("Invalid target faction")); + shell.WriteLine(Loc.GetString("Invalid target faction")); return; } EntitySystem.Get().MakeFriendly(faction, targetFaction); - shell.SendText(player, Loc.GetString("Command successful")); + shell.WriteLine(Loc.GetString("Command successful")); break; case "hostile": if (args.Length < 3) { - shell.SendText(player, Loc.GetString("Need to supply a target faction")); + shell.WriteLine(Loc.GetString("Need to supply a target faction")); return; } if (!Enum.TryParse(args[2], true, out targetFaction)) { - shell.SendText(player, Loc.GetString("Invalid target faction")); + shell.WriteLine(Loc.GetString("Invalid target faction")); return; } EntitySystem.Get().MakeHostile(faction, targetFaction); - shell.SendText(player, Loc.GetString("Command successful")); + shell.WriteLine(Loc.GetString("Command successful")); break; case "list": - shell.SendText(player, EntitySystem.Get().GetHostileFactions(faction).ToString()); + shell.WriteLine(EntitySystem.Get().GetHostileFactions(faction).ToString()); break; default: - shell.SendText(player, Loc.GetString("Unknown faction arg")); + shell.WriteLine(Loc.GetString("Unknown faction arg")); break; } diff --git a/Content.Server/Commands/Actions/CooldownAction.cs b/Content.Server/Commands/Actions/CooldownAction.cs index 15c9b9a903..7c8367af09 100644 --- a/Content.Server/Commands/Actions/CooldownAction.cs +++ b/Content.Server/Commands/Actions/CooldownAction.cs @@ -1,25 +1,26 @@ -#nullable enable +#nullable enable using System; using Content.Server.Administration; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.Actions; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; namespace Content.Server.Commands.Actions { [AdminCommand(AdminFlags.Debug)] - public sealed class CooldownAction : IClientCommand + public sealed class CooldownAction : IConsoleCommand { public string Command => "coolaction"; public string Description => "Sets a cooldown on an action for a player, defaulting to current player"; public string Help => "coolaction "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) return; var attachedEntity = player.AttachedEntity; if (args.Length > 2) @@ -31,29 +32,29 @@ namespace Content.Server.Commands.Actions if (attachedEntity == null) return; if (!attachedEntity.TryGetComponent(out ServerActionsComponent? actionsComponent)) { - shell.SendText(player, "user has no actions component"); + shell.WriteLine("user has no actions component"); return; } var actionTypeRaw = args[0]; if (!Enum.TryParse(actionTypeRaw, out var actionType)) { - shell.SendText(player, "unrecognized ActionType enum value, please" + - " ensure you used correct casing: " + actionTypeRaw); + shell.WriteLine("unrecognized ActionType enum value, please" + + " ensure you used correct casing: " + actionTypeRaw); return; } var actionMgr = IoCManager.Resolve(); if (!actionMgr.TryGet(actionType, out var action)) { - shell.SendText(player, "unrecognized actionType " + actionType); + shell.WriteLine("unrecognized actionType " + actionType); return; } var cooldownStart = IoCManager.Resolve().CurTime; if (!uint.TryParse(args[1], out var seconds)) { - shell.SendText(player, "cannot parse seconds: " + args[1]); + shell.WriteLine("cannot parse seconds: " + args[1]); return; } diff --git a/Content.Server/Commands/Actions/GrantAction.cs b/Content.Server/Commands/Actions/GrantAction.cs index fd2cd3d6b8..a6bb3f410b 100644 --- a/Content.Server/Commands/Actions/GrantAction.cs +++ b/Content.Server/Commands/Actions/GrantAction.cs @@ -1,23 +1,24 @@ -#nullable enable +#nullable enable using System; using Content.Server.Administration; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.Actions; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Actions { [AdminCommand(AdminFlags.Debug)] - public sealed class GrantAction : IClientCommand + public sealed class GrantAction : IConsoleCommand { public string Command => "grantaction"; public string Description => "Grants an action to a player, defaulting to current player"; public string Help => "grantaction "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) return; var attachedEntity = player.AttachedEntity; if (args.Length > 1) @@ -29,21 +30,21 @@ namespace Content.Server.Commands.Actions if (attachedEntity == null) return; if (!attachedEntity.TryGetComponent(out ServerActionsComponent? actionsComponent)) { - shell.SendText(player, "user has no actions component"); + shell.WriteLine("user has no actions component"); return; } var actionTypeRaw = args[0]; if (!Enum.TryParse(actionTypeRaw, out var actionType)) { - shell.SendText(player, "unrecognized ActionType enum value, please" + - " ensure you used correct casing: " + actionTypeRaw); + shell.WriteLine("unrecognized ActionType enum value, please" + + " ensure you used correct casing: " + actionTypeRaw); return; } var actionMgr = IoCManager.Resolve(); if (!actionMgr.TryGet(actionType, out var action)) { - shell.SendText(player, "unrecognized actionType " + actionType); + shell.WriteLine("unrecognized actionType " + actionType); return; } actionsComponent.Grant(action.ActionType); diff --git a/Content.Server/Commands/Actions/RevokeAction.cs b/Content.Server/Commands/Actions/RevokeAction.cs index be7ca6082d..78a0d0cae3 100644 --- a/Content.Server/Commands/Actions/RevokeAction.cs +++ b/Content.Server/Commands/Actions/RevokeAction.cs @@ -1,24 +1,25 @@ -#nullable enable +#nullable enable using System; using Content.Server.Administration; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.Actions; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Actions { [AdminCommand(AdminFlags.Debug)] - public sealed class RevokeAction : IClientCommand + public sealed class RevokeAction : IConsoleCommand { public string Command => "revokeaction"; public string Description => "Revokes an action from a player, defaulting to current player"; public string Help => "revokeaction "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) return; var attachedEntity = player.AttachedEntity; if (args.Length > 1) @@ -29,21 +30,21 @@ namespace Content.Server.Commands.Actions if (attachedEntity == null) return; if (!attachedEntity.TryGetComponent(out ServerActionsComponent? actionsComponent)) { - shell.SendText(player, "user has no actions component"); + shell.WriteLine("user has no actions component"); return; } var actionTypeRaw = args[0]; if (!Enum.TryParse(actionTypeRaw, out var actionType)) { - shell.SendText(player, "unrecognized ActionType enum value, please" + - " ensure you used correct casing: " + actionTypeRaw); + shell.WriteLine("unrecognized ActionType enum value, please" + + " ensure you used correct casing: " + actionTypeRaw); return; } var actionMgr = IoCManager.Resolve(); if (!actionMgr.TryGet(actionType, out var action)) { - shell.SendText(player, "unrecognized actionType " + actionType); + shell.WriteLine("unrecognized actionType " + actionType); return; } diff --git a/Content.Server/Commands/Alerts/ClearAlert.cs b/Content.Server/Commands/Alerts/ClearAlert.cs index c8fabad81c..761f08b7c6 100644 --- a/Content.Server/Commands/Alerts/ClearAlert.cs +++ b/Content.Server/Commands/Alerts/ClearAlert.cs @@ -1,27 +1,28 @@ -#nullable enable +#nullable enable using System; using Content.Server.Administration; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.Administration; using Content.Shared.Alert; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Alerts { [AdminCommand(AdminFlags.Debug)] - public sealed class ClearAlert : IClientCommand + public sealed class ClearAlert : IConsoleCommand { public string Command => "clearalert"; public string Description => "Clears an alert for a player, defaulting to current player"; public string Help => "clearalert "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player?.AttachedEntity == null) { - shell.SendText(player, "You don't have an entity."); + shell.WriteLine("You don't have an entity."); return; } @@ -35,7 +36,7 @@ namespace Content.Server.Commands.Alerts if (!attachedEntity.TryGetComponent(out ServerAlertsComponent? alertsComponent)) { - shell.SendText(player, "user has no alerts component"); + shell.WriteLine("user has no alerts component"); return; } @@ -43,7 +44,7 @@ namespace Content.Server.Commands.Alerts var alertMgr = IoCManager.Resolve(); if (!alertMgr.TryGet(Enum.Parse(alertType), out var alert)) { - shell.SendText(player, "unrecognized alertType " + alertType); + shell.WriteLine("unrecognized alertType " + alertType); return; } diff --git a/Content.Server/Commands/Alerts/ShowAlert.cs b/Content.Server/Commands/Alerts/ShowAlert.cs index 20a08cc809..2381c14fa3 100644 --- a/Content.Server/Commands/Alerts/ShowAlert.cs +++ b/Content.Server/Commands/Alerts/ShowAlert.cs @@ -1,27 +1,28 @@ -#nullable enable +#nullable enable using System; using Content.Server.Administration; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.Administration; using Content.Shared.Alert; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Alerts { [AdminCommand(AdminFlags.Debug)] - public sealed class ShowAlert : IClientCommand + public sealed class ShowAlert : IConsoleCommand { public string Command => "showalert"; public string Description => "Shows an alert for a player, defaulting to current player"; public string Help => "showalert "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "You cannot run this command from the server."); + shell.WriteLine("You cannot run this command from the server."); return; } @@ -29,7 +30,7 @@ namespace Content.Server.Commands.Alerts if (attachedEntity == null) { - shell.SendText(player, "You don't have an entity."); + shell.WriteLine("You don't have an entity."); return; } @@ -41,7 +42,7 @@ namespace Content.Server.Commands.Alerts if (!attachedEntity.TryGetComponent(out ServerAlertsComponent? alertsComponent)) { - shell.SendText(player, "user has no alerts component"); + shell.WriteLine("user has no alerts component"); return; } @@ -50,12 +51,12 @@ namespace Content.Server.Commands.Alerts var alertMgr = IoCManager.Resolve(); if (!alertMgr.TryGet(Enum.Parse(alertType), out var alert)) { - shell.SendText(player, "unrecognized alertType " + alertType); + shell.WriteLine("unrecognized alertType " + alertType); return; } if (!short.TryParse(severity, out var sevint)) { - shell.SendText(player, "invalid severity " + sevint); + shell.WriteLine("invalid severity " + sevint); return; } alertsComponent.ShowAlert(alert.AlertType, sevint == -1 ? (short?) null : sevint); diff --git a/Content.Server/Commands/Atmos/AddAtmosCommand.cs b/Content.Server/Commands/Atmos/AddAtmosCommand.cs index 48298d0641..e2e1c2322c 100644 --- a/Content.Server/Commands/Atmos/AddAtmosCommand.cs +++ b/Content.Server/Commands/Atmos/AddAtmosCommand.cs @@ -3,8 +3,8 @@ using Content.Server.Administration; using Content.Server.Atmos; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -13,23 +13,23 @@ using Robust.Shared.Map; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class AddAtmosCommand : IClientCommand + public class AddAtmosCommand : IConsoleCommand { public string Command => "addatmos"; public string Description => "Adds atmos support to a grid."; public string Help => $"{Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } if (!int.TryParse(args[0], out var id)) { - shell.SendText(player, $"{args[0]} is not a valid integer."); + shell.WriteLine($"{args[0]} is not a valid integer."); return; } @@ -39,7 +39,7 @@ namespace Content.Server.Commands.Atmos if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) { - shell.SendText(player, $"{gridId} is not a valid grid id."); + shell.WriteLine($"{gridId} is not a valid grid id."); return; } @@ -47,19 +47,19 @@ namespace Content.Server.Commands.Atmos if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) { - shell.SendText(player, "Failed to get grid entity."); + shell.WriteLine("Failed to get grid entity."); return; } if (grid.HasComponent()) { - shell.SendText(player, "Grid already has an atmosphere."); + shell.WriteLine("Grid already has an atmosphere."); return; } grid.AddComponent(); - shell.SendText(player, $"Added atmosphere to grid {id}."); + shell.WriteLine($"Added atmosphere to grid {id}."); } } } diff --git a/Content.Server/Commands/Atmos/AddGasCommand.cs b/Content.Server/Commands/Atmos/AddGasCommand.cs index 73c3ab28a1..a73d005137 100644 --- a/Content.Server/Commands/Atmos/AddGasCommand.cs +++ b/Content.Server/Commands/Atmos/AddGasCommand.cs @@ -3,8 +3,8 @@ using Content.Server.Administration; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.Administration; using Content.Shared.Atmos; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -14,13 +14,13 @@ using Robust.Shared.Maths; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class AddGasCommand : IClientCommand + public class AddGasCommand : IConsoleCommand { public string Command => "addgas"; public string Description => "Adds gas at a certain position."; public string Help => "addgas "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 5) return; if(!int.TryParse(args[0], out var x) @@ -35,7 +35,7 @@ namespace Content.Server.Commands.Atmos if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) { - shell.SendText(player, "Invalid grid ID."); + shell.WriteLine("Invalid grid ID."); return; } @@ -43,13 +43,13 @@ namespace Content.Server.Commands.Atmos if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) { - shell.SendText(player, "Failed to get grid entity."); + shell.WriteLine("Failed to get grid entity."); return; } if (!grid.HasComponent()) { - shell.SendText(player, "Grid doesn't have an atmosphere."); + shell.WriteLine("Grid doesn't have an atmosphere."); return; } @@ -59,13 +59,13 @@ namespace Content.Server.Commands.Atmos if (tile == null) { - shell.SendText(player, "Invalid coordinates."); + shell.WriteLine("Invalid coordinates."); return; } if (tile.Air == null) { - shell.SendText(player, "Can't add gas to that tile."); + shell.WriteLine("Can't add gas to that tile."); return; } diff --git a/Content.Server/Commands/Atmos/AddUnsimulatedAtmosCommand.cs b/Content.Server/Commands/Atmos/AddUnsimulatedAtmosCommand.cs index 9b39a92653..e6ec43ec27 100644 --- a/Content.Server/Commands/Atmos/AddUnsimulatedAtmosCommand.cs +++ b/Content.Server/Commands/Atmos/AddUnsimulatedAtmosCommand.cs @@ -3,8 +3,8 @@ using Content.Server.Administration; using Content.Server.Atmos; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -13,23 +13,23 @@ using Robust.Shared.Map; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class AddUnsimulatedAtmosCommand : IClientCommand + public class AddUnsimulatedAtmosCommand : IConsoleCommand { public string Command => "addunsimulatedatmos"; public string Description => "Adds unimulated atmos support to a grid."; public string Help => $"{Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } if (!int.TryParse(args[0], out var id)) { - shell.SendText(player, $"{args[0]} is not a valid integer."); + shell.WriteLine($"{args[0]} is not a valid integer."); return; } @@ -39,7 +39,7 @@ namespace Content.Server.Commands.Atmos if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) { - shell.SendText(player, $"{gridId} is not a valid grid id."); + shell.WriteLine($"{gridId} is not a valid grid id."); return; } @@ -47,19 +47,19 @@ namespace Content.Server.Commands.Atmos if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) { - shell.SendText(player, "Failed to get grid entity."); + shell.WriteLine("Failed to get grid entity."); return; } if (grid.HasComponent()) { - shell.SendText(player, "Grid already has an atmosphere."); + shell.WriteLine("Grid already has an atmosphere."); return; } grid.AddComponent(); - shell.SendText(player, $"Added unsimulated atmosphere to grid {id}."); + shell.WriteLine($"Added unsimulated atmosphere to grid {id}."); } } diff --git a/Content.Server/Commands/Atmos/DeleteGasCommand.cs b/Content.Server/Commands/Atmos/DeleteGasCommand.cs index dd92aeb957..ac11c85360 100644 --- a/Content.Server/Commands/Atmos/DeleteGasCommand.cs +++ b/Content.Server/Commands/Atmos/DeleteGasCommand.cs @@ -1,11 +1,11 @@ -#nullable enable +#nullable enable using System; using Content.Server.Administration; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.Administration; using Content.Shared.Atmos; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -14,14 +14,15 @@ using Robust.Shared.Map; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class DeleteGasCommand : IClientCommand + public class DeleteGasCommand : IConsoleCommand { public string Command => "deletegas"; public string Description => "Removes all gases from a grid, or just of one type if specified."; public string Help => $"Usage: {Command} / {Command} / {Command} / {Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; GridId gridId; Gas? gas = null; @@ -30,13 +31,13 @@ namespace Content.Server.Commands.Atmos case 0: if (player == null) { - shell.SendText(player, "A grid must be specified when the command isn't used by a player."); + shell.WriteLine("A grid must be specified when the command isn't used by a player."); return; } if (player.AttachedEntity == null) { - shell.SendText(player, "You have no entity to get a grid from."); + shell.WriteLine("You have no entity to get a grid from."); return; } @@ -44,7 +45,7 @@ namespace Content.Server.Commands.Atmos if (gridId == GridId.Invalid) { - shell.SendText(player, "You aren't on a grid to delete gas from."); + shell.WriteLine("You aren't on a grid to delete gas from."); return; } @@ -56,13 +57,13 @@ namespace Content.Server.Commands.Atmos // Argument is a gas if (player == null) { - shell.SendText(player, "A grid id must be specified if not using this command as a player."); + shell.WriteLine("A grid id must be specified if not using this command as a player."); return; } if (player.AttachedEntity == null) { - shell.SendText(player, "You have no entity from which to get a grid id."); + shell.WriteLine("You have no entity from which to get a grid id."); return; } @@ -70,13 +71,13 @@ namespace Content.Server.Commands.Atmos if (gridId == GridId.Invalid) { - shell.SendText(player, "You aren't on a grid to delete gas from."); + shell.WriteLine("You aren't on a grid to delete gas from."); return; } if (!Enum.TryParse(args[0], true, out var parsedGas)) { - shell.SendText(player, $"{args[0]} is not a valid gas name."); + shell.WriteLine($"{args[0]} is not a valid gas name."); return; } @@ -89,7 +90,7 @@ namespace Content.Server.Commands.Atmos if (gridId == GridId.Invalid) { - shell.SendText(player, $"{gridId} is not a valid grid id."); + shell.WriteLine($"{gridId} is not a valid grid id."); return; } @@ -99,7 +100,7 @@ namespace Content.Server.Commands.Atmos { if (!int.TryParse(args[0], out var first)) { - shell.SendText(player, $"{args[0]} is not a valid integer for a grid id."); + shell.WriteLine($"{args[0]} is not a valid integer for a grid id."); return; } @@ -107,13 +108,13 @@ namespace Content.Server.Commands.Atmos if (gridId == GridId.Invalid) { - shell.SendText(player, $"{gridId} is not a valid grid id."); + shell.WriteLine($"{gridId} is not a valid grid id."); return; } if (!Enum.TryParse(args[1], true, out var parsedGas)) { - shell.SendText(player, $"{args[1]} is not a valid gas."); + shell.WriteLine($"{args[1]} is not a valid gas."); return; } @@ -122,7 +123,7 @@ namespace Content.Server.Commands.Atmos break; } default: - shell.SendText(player, Help); + shell.WriteLine(Help); return; } @@ -130,7 +131,7 @@ namespace Content.Server.Commands.Atmos if (!mapManager.TryGetGrid(gridId, out var grid)) { - shell.SendText(player, $"No grid exists with id {gridId}"); + shell.WriteLine($"No grid exists with id {gridId}"); return; } @@ -138,13 +139,13 @@ namespace Content.Server.Commands.Atmos if (!entityManager.TryGetEntity(grid.GridEntityId, out var gridEntity)) { - shell.SendText(player, $"Grid {gridId} has no entity."); + shell.WriteLine($"Grid {gridId} has no entity."); return; } if (!gridEntity.TryGetComponent(out GridAtmosphereComponent? atmosphere)) { - shell.SendText(player, $"Grid {gridId} has no {nameof(GridAtmosphereComponent)}"); + shell.WriteLine($"Grid {gridId} has no {nameof(GridAtmosphereComponent)}"); return; } @@ -182,11 +183,11 @@ namespace Content.Server.Commands.Atmos if (gas == null) { - shell.SendText(player, $"Removed {moles} moles from {tiles} tiles."); + shell.WriteLine($"Removed {moles} moles from {tiles} tiles."); return; } - shell.SendText(player, $"Removed {moles} moles of gas {gas} from {tiles} tiles."); + shell.WriteLine($"Removed {moles} moles of gas {gas} from {tiles} tiles."); } } diff --git a/Content.Server/Commands/Atmos/FillGasCommand.cs b/Content.Server/Commands/Atmos/FillGasCommand.cs index 63efd89b63..1bac6ace5d 100644 --- a/Content.Server/Commands/Atmos/FillGasCommand.cs +++ b/Content.Server/Commands/Atmos/FillGasCommand.cs @@ -3,8 +3,8 @@ using Content.Server.Administration; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.Administration; using Content.Shared.Atmos; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -13,13 +13,13 @@ using Robust.Shared.Map; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class FillGas : IClientCommand + public class FillGas : IConsoleCommand { public string Command => "fillgas"; public string Description => "Adds gas to all tiles in a grid."; public string Help => "fillgas "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 3) return; if(!int.TryParse(args[0], out var id) @@ -32,7 +32,7 @@ namespace Content.Server.Commands.Atmos if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) { - shell.SendText(player, "Invalid grid ID."); + shell.WriteLine("Invalid grid ID."); return; } @@ -40,13 +40,13 @@ namespace Content.Server.Commands.Atmos if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) { - shell.SendText(player, "Failed to get grid entity."); + shell.WriteLine("Failed to get grid entity."); return; } if (!grid.HasComponent()) { - shell.SendText(player, "Grid doesn't have an atmosphere."); + shell.WriteLine("Grid doesn't have an atmosphere."); return; } diff --git a/Content.Server/Commands/Atmos/ListGasesCommand.cs b/Content.Server/Commands/Atmos/ListGasesCommand.cs index 57c56c5420..129719e866 100644 --- a/Content.Server/Commands/Atmos/ListGasesCommand.cs +++ b/Content.Server/Commands/Atmos/ListGasesCommand.cs @@ -2,26 +2,26 @@ using Content.Server.Administration; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class ListGasesCommand : IClientCommand + public class ListGasesCommand : IConsoleCommand { public string Command => "listgases"; public string Description => "Prints a list of gases and their indices."; public string Help => "listgases"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var atmosSystem = EntitySystem.Get(); foreach (var gasPrototype in atmosSystem.Gases) { - shell.SendText(player, $"{gasPrototype.Name} ID: {gasPrototype.ID}"); + shell.WriteLine($"{gasPrototype.Name} ID: {gasPrototype.ID}"); } } } diff --git a/Content.Server/Commands/Atmos/RemoveGasCommand.cs b/Content.Server/Commands/Atmos/RemoveGasCommand.cs index 7bf83f33dd..84f0cadcee 100644 --- a/Content.Server/Commands/Atmos/RemoveGasCommand.cs +++ b/Content.Server/Commands/Atmos/RemoveGasCommand.cs @@ -2,8 +2,8 @@ using Content.Server.Administration; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -13,13 +13,13 @@ using Robust.Shared.Maths; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class RemoveGasCommand : IClientCommand + public class RemoveGasCommand : IConsoleCommand { public string Command => "removegas"; public string Description => "Removes an amount of gases."; public string Help => "removegas \nIf is true, amount will be treated as the ratio of gas to be removed."; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 5) return; if(!int.TryParse(args[0], out var x) @@ -34,7 +34,7 @@ namespace Content.Server.Commands.Atmos if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) { - shell.SendText(player, "Invalid grid ID."); + shell.WriteLine("Invalid grid ID."); return; } @@ -42,13 +42,13 @@ namespace Content.Server.Commands.Atmos if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) { - shell.SendText(player, "Failed to get grid entity."); + shell.WriteLine("Failed to get grid entity."); return; } if (!grid.HasComponent()) { - shell.SendText(player, "Grid doesn't have an atmosphere."); + shell.WriteLine("Grid doesn't have an atmosphere."); return; } @@ -58,13 +58,13 @@ namespace Content.Server.Commands.Atmos if (tile == null) { - shell.SendText(player, "Invalid coordinates."); + shell.WriteLine("Invalid coordinates."); return; } if (tile.Air == null) { - shell.SendText(player, "Can't remove gas from that tile."); + shell.WriteLine("Can't remove gas from that tile."); return; } diff --git a/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs b/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs index 6d935e004a..28b2452397 100644 --- a/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs +++ b/Content.Server/Commands/Atmos/SetAtmosTemperatureCommand.cs @@ -3,8 +3,8 @@ using Content.Server.Administration; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.Administration; using Content.Shared.Atmos; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -13,13 +13,13 @@ using Robust.Shared.Map; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class SetAtmosTemperatureCommand : IClientCommand + public class SetAtmosTemperatureCommand : IConsoleCommand { public string Command => "setatmostemp"; public string Description => "Sets a grid's temperature (in kelvin)."; public string Help => "Usage: setatmostemp "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 2) return; if(!int.TryParse(args[0], out var id) @@ -31,13 +31,13 @@ namespace Content.Server.Commands.Atmos if (temperature < Atmospherics.TCMB) { - shell.SendText(player, "Invalid temperature."); + shell.WriteLine("Invalid temperature."); return; } if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) { - shell.SendText(player, "Invalid grid ID."); + shell.WriteLine("Invalid grid ID."); return; } @@ -45,13 +45,13 @@ namespace Content.Server.Commands.Atmos if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) { - shell.SendText(player, "Failed to get grid entity."); + shell.WriteLine("Failed to get grid entity."); return; } if (!grid.HasComponent()) { - shell.SendText(player, "Grid doesn't have an atmosphere."); + shell.WriteLine("Grid doesn't have an atmosphere."); return; } @@ -69,7 +69,7 @@ namespace Content.Server.Commands.Atmos tile.Invalidate(); } - shell.SendText(player, $"Changed the temperature of {tiles} tiles."); + shell.WriteLine($"Changed the temperature of {tiles} tiles."); } } } diff --git a/Content.Server/Commands/Atmos/SetTemperatureCommand.cs b/Content.Server/Commands/Atmos/SetTemperatureCommand.cs index c761c9cac4..33be481d12 100644 --- a/Content.Server/Commands/Atmos/SetTemperatureCommand.cs +++ b/Content.Server/Commands/Atmos/SetTemperatureCommand.cs @@ -3,8 +3,8 @@ using Content.Server.Administration; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.Administration; using Content.Shared.Atmos; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -14,13 +14,13 @@ using Robust.Shared.Maths; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class SetTemperatureCommand : IClientCommand + public class SetTemperatureCommand : IConsoleCommand { public string Command => "settemp"; public string Description => "Sets a tile's temperature (in kelvin)."; public string Help => "Usage: settemp "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length < 4) return; if(!int.TryParse(args[0], out var x) @@ -34,13 +34,13 @@ namespace Content.Server.Commands.Atmos if (temperature < Atmospherics.TCMB) { - shell.SendText(player, "Invalid temperature."); + shell.WriteLine("Invalid temperature."); return; } if (!gridId.IsValid() || !mapMan.TryGetGrid(gridId, out var gridComp)) { - shell.SendText(player, "Invalid grid ID."); + shell.WriteLine("Invalid grid ID."); return; } @@ -48,13 +48,13 @@ namespace Content.Server.Commands.Atmos if (!entMan.TryGetEntity(gridComp.GridEntityId, out var grid)) { - shell.SendText(player, "Failed to get grid entity."); + shell.WriteLine("Failed to get grid entity."); return; } if (!grid.HasComponent()) { - shell.SendText(player, "Grid doesn't have an atmosphere."); + shell.WriteLine("Grid doesn't have an atmosphere."); return; } @@ -64,13 +64,13 @@ namespace Content.Server.Commands.Atmos if (tile == null) { - shell.SendText(player, "Invalid coordinates."); + shell.WriteLine("Invalid coordinates."); return; } if (tile.Air == null) { - shell.SendText(player, "Can't change that tile's temperature."); + shell.WriteLine("Can't change that tile's temperature."); return; } diff --git a/Content.Server/Commands/Atmos/ShowAtmosCommand.cs b/Content.Server/Commands/Atmos/ShowAtmosCommand.cs index 01e1ccc61d..bd3f8cf6ca 100644 --- a/Content.Server/Commands/Atmos/ShowAtmosCommand.cs +++ b/Content.Server/Commands/Atmos/ShowAtmosCommand.cs @@ -1,32 +1,33 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.EntitySystems.Atmos; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; namespace Content.Server.Commands.Atmos { [AdminCommand(AdminFlags.Debug)] - public class ShowAtmos : IClientCommand + public class ShowAtmos : IConsoleCommand { public string Command => "showatmos"; public string Description => "Toggles seeing atmos debug overlay."; public string Help => $"Usage: {Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "You must be a player to use this command."); + shell.WriteLine("You must be a player to use this command."); return; } var atmosDebug = EntitySystem.Get(); var enabled = atmosDebug.ToggleObserver(player); - shell.SendText(player, enabled + shell.WriteLine(enabled ? "Enabled the atmospherics debug overlay." : "Disabled the atmospherics debug overlay."); } diff --git a/Content.Server/Commands/AttachBodyPartCommand.cs b/Content.Server/Commands/AttachBodyPartCommand.cs index 72128390b5..07b9e92fdd 100644 --- a/Content.Server/Commands/AttachBodyPartCommand.cs +++ b/Content.Server/Commands/AttachBodyPartCommand.cs @@ -1,11 +1,11 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.Components.Body.Part; using Content.Shared.Administration; using Content.Shared.GameObjects.Components.Body; using Content.Shared.GameObjects.Components.Body.Part; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -13,14 +13,15 @@ using Robust.Shared.IoC; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Fun)] - public class AttachBodyPartCommand : IClientCommand + public class AttachBodyPartCommand : IConsoleCommand { public string Command => "attachbodypart"; public string Description => "Attaches a body part to you or someone else."; public string Help => $"{Command} / {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; var entityManager = IoCManager.Resolve(); IEntity entity; @@ -31,19 +32,19 @@ namespace Content.Server.Commands case 1: if (player == null) { - shell.SendText(player, $"You need to specify an entity to attach the part to if you aren't a player.\n{Help}"); + shell.WriteLine($"You need to specify an entity to attach the part to if you aren't a player.\n{Help}"); return; } if (player.AttachedEntity == null) { - shell.SendText(player, $"You need to specify an entity to attach the part to if you aren't attached to an entity.\n{Help}"); + shell.WriteLine($"You need to specify an entity to attach the part to if you aren't attached to an entity.\n{Help}"); return; } if (!EntityUid.TryParse(args[0], out partUid)) { - shell.SendText(player, $"{args[0]} is not a valid entity uid."); + shell.WriteLine($"{args[0]} is not a valid entity uid."); return; } @@ -53,50 +54,50 @@ namespace Content.Server.Commands case 2: if (!EntityUid.TryParse(args[0], out var entityUid)) { - shell.SendText(player, $"{args[0]} is not a valid entity uid."); + shell.WriteLine($"{args[0]} is not a valid entity uid."); return; } if (!EntityUid.TryParse(args[1], out partUid)) { - shell.SendText(player, $"{args[1]} is not a valid entity uid."); + shell.WriteLine($"{args[1]} is not a valid entity uid."); return; } if (!entityManager.TryGetEntity(entityUid, out var tempEntity)) { - shell.SendText(player, $"{entityUid} is not a valid entity."); + shell.WriteLine($"{entityUid} is not a valid entity."); return; } entity = tempEntity; break; default: - shell.SendText(player, Help); + shell.WriteLine(Help); return; } if (!entity.TryGetComponent(out IBody? body)) { - shell.SendText(player, $"Entity {entity.Name} with uid {entity.Uid} does not have a {nameof(IBody)} component."); + shell.WriteLine($"Entity {entity.Name} with uid {entity.Uid} does not have a {nameof(IBody)} component."); return; } if (!entityManager.TryGetEntity(partUid, out var partEntity)) { - shell.SendText(player, $"{partUid} is not a valid entity."); + shell.WriteLine($"{partUid} is not a valid entity."); return; } if (!partEntity.TryGetComponent(out IBodyPart? part)) { - shell.SendText(player, $"Entity {partEntity.Name} with uid {args[0]} does not have a {nameof(IBodyPart)} component."); + shell.WriteLine($"Entity {partEntity.Name} with uid {args[0]} does not have a {nameof(IBodyPart)} component."); return; } if (body.HasPart(part)) { - shell.SendText(player, $"Body part {partEntity.Name} with uid {partEntity.Uid} is already attached to entity {entity.Name} with uid {entity.Uid}"); + shell.WriteLine($"Body part {partEntity.Name} with uid {partEntity.Uid} is already attached to entity {entity.Name} with uid {entity.Uid}"); return; } diff --git a/Content.Server/Commands/Body/AddHandCommand.cs b/Content.Server/Commands/Body/AddHandCommand.cs index a448df85f7..e0dedf53af 100644 --- a/Content.Server/Commands/Body/AddHandCommand.cs +++ b/Content.Server/Commands/Body/AddHandCommand.cs @@ -1,10 +1,10 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.GameObjects.Components.Body; using Content.Shared.GameObjects.Components.Body.Part; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Random; @@ -15,7 +15,7 @@ using Robust.Shared.Random; namespace Content.Server.Commands.Body { [AdminCommand(AdminFlags.Fun)] - class AddHandCommand : IClientCommand + class AddHandCommand : IConsoleCommand { public const string DefaultHandPrototype = "LeftHandHuman"; @@ -23,11 +23,12 @@ namespace Content.Server.Commands.Body public string Description => "Adds a hand to your entity."; public string Help => $"Usage: {Command} / {Command} / {Command} / {Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (args.Length > 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } @@ -43,13 +44,13 @@ namespace Content.Server.Commands.Body { if (player == null) { - shell.SendText(player, "Only a player can run this command without arguments."); + shell.WriteLine("Only a player can run this command without arguments."); return; } if (player.AttachedEntity == null) { - shell.SendText(player, "You don't have an entity to add a hand to."); + shell.WriteLine("You don't have an entity to add a hand to."); return; } @@ -63,7 +64,7 @@ namespace Content.Server.Commands.Body { if (!entityManager.TryGetEntity(uid, out var parsedEntity)) { - shell.SendText(player, $"No entity found with uid {uid}"); + shell.WriteLine($"No entity found with uid {uid}"); return; } @@ -74,14 +75,13 @@ namespace Content.Server.Commands.Body { if (player == null) { - shell.SendText(player, - "You must specify an entity to add a hand to when using this command from the server terminal."); + shell.WriteLine("You must specify an entity to add a hand to when using this command from the server terminal."); return; } if (player.AttachedEntity == null) { - shell.SendText(player, "You don't have an entity to add a hand to."); + shell.WriteLine("You don't have an entity to add a hand to."); return; } @@ -95,13 +95,13 @@ namespace Content.Server.Commands.Body { if (!EntityUid.TryParse(args[0], out var uid)) { - shell.SendText(player, $"{args[0]} is not a valid entity uid."); + shell.WriteLine($"{args[0]} is not a valid entity uid."); return; } if (!entityManager.TryGetEntity(uid, out var parsedEntity)) { - shell.SendText(player, $"No entity exists with uid {uid}."); + shell.WriteLine($"No entity exists with uid {uid}."); return; } @@ -109,7 +109,7 @@ namespace Content.Server.Commands.Body if (!prototypeManager.HasIndex(args[1])) { - shell.SendText(player, $"No hand entity exists with id {args[1]}."); + shell.WriteLine($"No hand entity exists with id {args[1]}."); return; } @@ -119,7 +119,7 @@ namespace Content.Server.Commands.Body } default: { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } } @@ -129,13 +129,13 @@ namespace Content.Server.Commands.Body var random = IoCManager.Resolve(); var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}"; - shell.SendText(player, text); + shell.WriteLine(text); return; } if (!hand.TryGetComponent(out IBodyPart? part)) { - shell.SendText(player, $"Hand entity {hand} does not have a {nameof(IBodyPart)} component."); + shell.WriteLine($"Hand entity {hand} does not have a {nameof(IBodyPart)} component."); return; } @@ -144,7 +144,7 @@ namespace Content.Server.Commands.Body ? $"Added hand to entity {entity.Name}" : $"Error occurred trying to add a hand to entity {entity.Name}"; - shell.SendText(player, response); + shell.WriteLine(response); } } } diff --git a/Content.Server/Commands/Body/DestroyMechanismCommand.cs b/Content.Server/Commands/Body/DestroyMechanismCommand.cs index 76fe801165..59aa109a10 100644 --- a/Content.Server/Commands/Body/DestroyMechanismCommand.cs +++ b/Content.Server/Commands/Body/DestroyMechanismCommand.cs @@ -1,9 +1,9 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.GameObjects.Components.Body; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; using Robust.Shared.Random; @@ -11,29 +11,30 @@ using Robust.Shared.Random; namespace Content.Server.Commands.Body { [AdminCommand(AdminFlags.Fun)] - class DestroyMechanismCommand : IClientCommand + class DestroyMechanismCommand : IConsoleCommand { public string Command => "destroymechanism"; public string Description => "Destroys a mechanism from your entity"; public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "Only a player can run this command."); + shell.WriteLine("Only a player can run this command."); return; } if (args.Length == 0) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } if (player.AttachedEntity == null) { - shell.SendText(player, "You have no entity."); + shell.WriteLine("You have no entity."); return; } @@ -42,7 +43,7 @@ namespace Content.Server.Commands.Body var random = IoCManager.Resolve(); var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}"; - shell.SendText(player, text); + shell.WriteLine(text); return; } @@ -54,12 +55,12 @@ namespace Content.Server.Commands.Body if (mechanism.Name.ToLowerInvariant() == mechanismName) { part.DeleteMechanism(mechanism); - shell.SendText(player, $"Mechanism with name {mechanismName} has been destroyed."); + shell.WriteLine($"Mechanism with name {mechanismName} has been destroyed."); return; } } - shell.SendText(player, $"No mechanism was found with name {mechanismName}."); + shell.WriteLine($"No mechanism was found with name {mechanismName}."); } } } diff --git a/Content.Server/Commands/Body/RemoveHandCommand.cs b/Content.Server/Commands/Body/RemoveHandCommand.cs index 6491c5525e..9a3bcd87fa 100644 --- a/Content.Server/Commands/Body/RemoveHandCommand.cs +++ b/Content.Server/Commands/Body/RemoveHandCommand.cs @@ -1,11 +1,11 @@ -#nullable enable +#nullable enable using System.Linq; using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.GameObjects.Components.Body; using Content.Shared.GameObjects.Components.Body.Part; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.Random; using Robust.Shared.IoC; using Robust.Shared.Random; @@ -13,23 +13,24 @@ using Robust.Shared.Random; namespace Content.Server.Commands.Body { [AdminCommand(AdminFlags.Fun)] - class RemoveHandCommand : IClientCommand + class RemoveHandCommand : IConsoleCommand { public string Command => "removehand"; public string Description => "Removes a hand from your entity."; public string Help => $"Usage: {Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "Only a player can run this command."); + shell.WriteLine("Only a player can run this command."); return; } if (player.AttachedEntity == null) { - shell.SendText(player, "You have no entity."); + shell.WriteLine("You have no entity."); return; } @@ -38,14 +39,14 @@ namespace Content.Server.Commands.Body var random = IoCManager.Resolve(); var text = $"You have no body{(random.Prob(0.2f) ? " and you must scream." : ".")}"; - shell.SendText(player, text); + shell.WriteLine(text); return; } var (_, hand) = body.Parts.FirstOrDefault(x => x.Value.PartType == BodyPartType.Hand); if (hand == null) { - shell.SendText(player, "You have no hands."); + shell.WriteLine("You have no hands."); } else { diff --git a/Content.Server/Commands/Chat/AdminChatCommand.cs b/Content.Server/Commands/Chat/AdminChatCommand.cs index 9c793b2125..a138ac68ae 100644 --- a/Content.Server/Commands/Chat/AdminChatCommand.cs +++ b/Content.Server/Commands/Chat/AdminChatCommand.cs @@ -1,22 +1,23 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.Interfaces.Chat; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Chat { [AdminCommand(AdminFlags.Admin)] - internal class AdminChatCommand : IClientCommand + internal class AdminChatCommand : IConsoleCommand { public string Command => "asay"; public string Description => "Send chat messages to the private admin chat channel."; public string Help => "asay "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (args.Length < 1) return; diff --git a/Content.Server/Commands/Chat/MeCommand.cs b/Content.Server/Commands/Chat/MeCommand.cs index bb371a6c7c..f22d82f054 100644 --- a/Content.Server/Commands/Chat/MeCommand.cs +++ b/Content.Server/Commands/Chat/MeCommand.cs @@ -1,26 +1,27 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.Interfaces.Chat; using Content.Server.Players; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.IoC; namespace Content.Server.Commands.Chat { [AnyCommand] - internal class MeCommand : IClientCommand + internal class MeCommand : IConsoleCommand { public string Command => "me"; public string Description => "Perform an action."; public string Help => "me "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "This command cannot be run from the server."); + shell.WriteLine("This command cannot be run from the server."); return; } @@ -39,7 +40,7 @@ namespace Content.Server.Commands.Chat if (mindComponent == null) { - shell.SendText(player, "You don't have a mind!"); + shell.WriteLine("You don't have a mind!"); return; } diff --git a/Content.Server/Commands/Chat/OOCCommand.cs b/Content.Server/Commands/Chat/OOCCommand.cs index 1c7d85ce53..7233d2f96a 100644 --- a/Content.Server/Commands/Chat/OOCCommand.cs +++ b/Content.Server/Commands/Chat/OOCCommand.cs @@ -1,21 +1,22 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.Interfaces.Chat; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Chat { [AnyCommand] - internal class OOCCommand : IClientCommand + internal class OOCCommand : IConsoleCommand { public string Command => "ooc"; public string Description => "Send Out Of Character chat messages."; public string Help => "ooc "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (args.Length < 1) return; diff --git a/Content.Server/Commands/Chat/SayCommand.cs b/Content.Server/Commands/Chat/SayCommand.cs index ed01c97006..530e029636 100644 --- a/Content.Server/Commands/Chat/SayCommand.cs +++ b/Content.Server/Commands/Chat/SayCommand.cs @@ -1,27 +1,28 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.Components.Observer; using Content.Server.Interfaces.Chat; using Content.Server.Players; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.IoC; namespace Content.Server.Commands.Chat { [AnyCommand] - internal class SayCommand : IClientCommand + internal class SayCommand : IConsoleCommand { public string Command => "say"; public string Description => "Send chat messages to the local channel or a specified radio channel."; public string Help => "say "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "This command cannot be run from the server."); + shell.WriteLine("This command cannot be run from the server."); return; } @@ -40,7 +41,7 @@ namespace Content.Server.Commands.Chat if (playerEntity == null) { - shell.SendText(player, "You don't have an entity!"); + shell.WriteLine("You don't have an entity!"); return; } @@ -52,7 +53,7 @@ namespace Content.Server.Commands.Chat if (mindComponent == null) { - shell.SendText(player, "You don't have a mind!"); + shell.WriteLine("You don't have a mind!"); return; } diff --git a/Content.Server/Commands/Chat/SuicideCommand.cs b/Content.Server/Commands/Chat/SuicideCommand.cs index aa73ff4913..c20e82f8a7 100644 --- a/Content.Server/Commands/Chat/SuicideCommand.cs +++ b/Content.Server/Commands/Chat/SuicideCommand.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Linq; using Content.Server.Administration; @@ -12,8 +12,8 @@ using Content.Server.Utility; using Content.Shared.Damage; using Content.Shared.GameObjects.Components.Damage; using Content.Shared.Interfaces; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -22,7 +22,7 @@ using Robust.Shared.Localization; namespace Content.Server.Commands.Chat { [AnyCommand] - internal class SuicideCommand : IClientCommand + internal class SuicideCommand : IConsoleCommand { public string Command => "suicide"; @@ -56,11 +56,12 @@ namespace Content.Server.Commands.Chat } } - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "You cannot run this command from the server."); + shell.WriteLine("You cannot run this command from the server."); return; } @@ -72,7 +73,7 @@ namespace Content.Server.Commands.Chat if (owner == null) { - shell.SendText(player, "You don't have a mind!"); + shell.WriteLine("You don't have a mind!"); return; } @@ -122,7 +123,7 @@ namespace Content.Server.Commands.Chat // Prevent the player from returning to the body. Yes, this is an ugly hack. var ghost = new Ghost(){CanReturn = false}; - ghost.Execute(shell, player, Array.Empty()); + ghost.Execute(shell, argStr, Array.Empty()); } } } diff --git a/Content.Server/Commands/CommandUtils.cs b/Content.Server/Commands/CommandUtils.cs index 66e36773fb..c291c0b36c 100644 --- a/Content.Server/Commands/CommandUtils.cs +++ b/Content.Server/Commands/CommandUtils.cs @@ -1,8 +1,9 @@ #nullable enable using System; using System.Diagnostics.CodeAnalysis; -using Robust.Server.Interfaces.Console; +using Robust.Server.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Network; @@ -26,11 +27,11 @@ namespace Content.Server.Commands if (Guid.TryParse(usernameOrId, out var targetGuid)) { if (plyMgr.TryGetSessionById(new NetUserId(targetGuid), out session)) return true; - shell.SendText(performer, "Unable to find user with that name/id."); + shell.WriteLine("Unable to find user with that name/id."); return false; } - shell.SendText(performer, "Unable to find user with that name/id."); + shell.WriteLine("Unable to find user with that name/id."); return false; } @@ -45,7 +46,7 @@ namespace Content.Server.Commands if (!TryGetSessionByUsernameOrId(shell, usernameOrId, performer, out var session)) return false; if (session.AttachedEntity == null) { - shell.SendText(performer, "User has no attached entity."); + shell.WriteLine("User has no attached entity."); return false; } diff --git a/Content.Server/Commands/Damage/AddDamageFlagCommand.cs b/Content.Server/Commands/Damage/AddDamageFlagCommand.cs index 21d353b078..698a9a4b07 100644 --- a/Content.Server/Commands/Damage/AddDamageFlagCommand.cs +++ b/Content.Server/Commands/Damage/AddDamageFlagCommand.cs @@ -1,8 +1,9 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; +using Robust.Server.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; namespace Content.Server.Commands.Damage { @@ -13,15 +14,16 @@ namespace Content.Server.Commands.Damage public override string Description => "Adds a damage flag to your entity or another."; public override string Help => $"Usage: {Command} / {Command} "; - public override void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public override void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (!TryGetEntity(shell, player, args, true, out var entity, out var flag, out var damageable)) { return; } damageable.AddFlag(flag); - shell.SendText(player, $"Added damage flag {flag} to entity {entity.Name}"); + shell.WriteLine($"Added damage flag {flag} to entity {entity.Name}"); } } } diff --git a/Content.Server/Commands/Damage/DamageFlagCommand.cs b/Content.Server/Commands/Damage/DamageFlagCommand.cs index 1edf0e973b..b1eee70281 100644 --- a/Content.Server/Commands/Damage/DamageFlagCommand.cs +++ b/Content.Server/Commands/Damage/DamageFlagCommand.cs @@ -2,21 +2,21 @@ using System; using System.Diagnostics.CodeAnalysis; using Content.Shared.GameObjects.Components.Damage; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; namespace Content.Server.Commands.Damage { - public abstract class DamageFlagCommand : IClientCommand + public abstract class DamageFlagCommand : IConsoleCommand { public abstract string Command { get; } public abstract string Description { get; } public abstract string Help { get; } - public abstract void Execute(IConsoleShell shell, IPlayerSession? player, string[] args); + public abstract void Execute(IConsoleShell shell, string argStr, string[] args); public bool TryGetEntity( IConsoleShell shell, @@ -41,19 +41,19 @@ namespace Content.Server.Commands.Damage { if (player == null) { - shell.SendText(player, "An entity needs to be specified when the command isn't used by a player."); + shell.WriteLine("An entity needs to be specified when the command isn't used by a player."); return false; } if (player.AttachedEntity == null) { - shell.SendText(player, "An entity needs to be specified when you aren't attached to an entity."); + shell.WriteLine("An entity needs to be specified when you aren't attached to an entity."); return false; } if (!Enum.TryParse(args[0], true, out parsedFlag)) { - shell.SendText(player, $"{args[0]} is not a valid damage flag."); + shell.WriteLine($"{args[0]} is not a valid damage flag."); return false; } @@ -65,44 +65,44 @@ namespace Content.Server.Commands.Damage { if (!EntityUid.TryParse(args[0], out var id)) { - shell.SendText(player, $"{args[0]} isn't a valid entity id."); + shell.WriteLine($"{args[0]} isn't a valid entity id."); return false; } var entityManager = IoCManager.Resolve(); if (!entityManager.TryGetEntity(id, out parsedEntity)) { - shell.SendText(player, $"No entity found with id {id}."); + shell.WriteLine($"No entity found with id {id}."); return false; } if (!Enum.TryParse(args[1], true, out parsedFlag)) { - shell.SendText(player, $"{args[1]} is not a valid damage flag."); + shell.WriteLine($"{args[1]} is not a valid damage flag."); return false; } break; } default: - shell.SendText(player, Help); + shell.WriteLine(Help); return false; } if (!parsedEntity.TryGetComponent(out parsedDamageable)) { - shell.SendText(player, $"Entity {parsedEntity.Name} doesn't have a {nameof(IDamageableComponent)}"); + shell.WriteLine($"Entity {parsedEntity.Name} doesn't have a {nameof(IDamageableComponent)}"); return false; } if (parsedDamageable.HasFlag(parsedFlag) && adding) { - shell.SendText(player, $"Entity {parsedEntity.Name} already has damage flag {parsedFlag}."); + shell.WriteLine($"Entity {parsedEntity.Name} already has damage flag {parsedFlag}."); return false; } else if (!parsedDamageable.HasFlag(parsedFlag) && !adding) { - shell.SendText(player, $"Entity {parsedEntity.Name} doesn't have damage flag {parsedFlag}."); + shell.WriteLine($"Entity {parsedEntity.Name} doesn't have damage flag {parsedFlag}."); return false; } diff --git a/Content.Server/Commands/Damage/GodModeCommand.cs b/Content.Server/Commands/Damage/GodModeCommand.cs index 77c05fc24c..cedd3b1fb1 100644 --- a/Content.Server/Commands/Damage/GodModeCommand.cs +++ b/Content.Server/Commands/Damage/GodModeCommand.cs @@ -1,9 +1,9 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; @@ -12,14 +12,15 @@ using Robust.Shared.IoC; namespace Content.Server.Commands.Damage { [AdminCommand(AdminFlags.Admin)] - public class GodModeCommand : IClientCommand + public class GodModeCommand : IConsoleCommand { public string Command => "godmode"; public string Description => "Makes your entity or another invulnerable to almost anything. May have irreversible changes."; public string Help => $"Usage: {Command} / {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; IEntity entity; switch (args.Length) @@ -27,13 +28,13 @@ namespace Content.Server.Commands.Damage case 0: if (player == null) { - shell.SendText(player, "An entity needs to be specified when the command isn't used by a player."); + shell.WriteLine("An entity needs to be specified when the command isn't used by a player."); return; } if (player.AttachedEntity == null) { - shell.SendText(player, "An entity needs to be specified when you aren't attached to an entity."); + shell.WriteLine("An entity needs to be specified when you aren't attached to an entity."); return; } @@ -42,28 +43,28 @@ namespace Content.Server.Commands.Damage case 1: if (!EntityUid.TryParse(args[0], out var id)) { - shell.SendText(player, $"{args[0]} isn't a valid entity id."); + shell.WriteLine($"{args[0]} isn't a valid entity id."); return; } var entityManager = IoCManager.Resolve(); if (!entityManager.TryGetEntity(id, out var parsedEntity)) { - shell.SendText(player, $"No entity found with id {id}."); + shell.WriteLine($"No entity found with id {id}."); return; } entity = parsedEntity; break; default: - shell.SendText(player, Help); + shell.WriteLine(Help); return; } var godmodeSystem = EntitySystem.Get(); var enabled = godmodeSystem.ToggleGodmode(entity); - shell.SendText(player, enabled + shell.WriteLine(enabled ? $"Enabled godmode for entity {entity.Name} with id {entity.Uid}" : $"Disabled godmode for entity {entity.Name} with id {entity.Uid}"); } diff --git a/Content.Server/Commands/Damage/RemoveDamageFlagCommand.cs b/Content.Server/Commands/Damage/RemoveDamageFlagCommand.cs index 631eaae370..c315723273 100644 --- a/Content.Server/Commands/Damage/RemoveDamageFlagCommand.cs +++ b/Content.Server/Commands/Damage/RemoveDamageFlagCommand.cs @@ -1,8 +1,9 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; +using Robust.Server.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; namespace Content.Server.Commands.Damage { @@ -13,15 +14,16 @@ namespace Content.Server.Commands.Damage public override string Description => "Removes a damage flag from your entity or another."; public override string Help => $"Usage: {Command} / {Command} "; - public override void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public override void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (!TryGetEntity(shell, player, args, false, out var entity, out var flag, out var damageable)) { return; } damageable.RemoveFlag(flag); - shell.SendText(player, $"Removed damage flag {flag} from entity {entity.Name}"); + shell.WriteLine($"Removed damage flag {flag} from entity {entity.Name}"); } } } diff --git a/Content.Server/Commands/Disposal/TubeConnectionsCommand.cs b/Content.Server/Commands/Disposal/TubeConnectionsCommand.cs index eb13975d74..5188893165 100644 --- a/Content.Server/Commands/Disposal/TubeConnectionsCommand.cs +++ b/Content.Server/Commands/Disposal/TubeConnectionsCommand.cs @@ -1,9 +1,9 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.Components.Disposal; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -12,42 +12,43 @@ using Robust.Shared.Localization; namespace Content.Server.Commands.Disposal { [AdminCommand(AdminFlags.Debug)] - public class TubeConnectionsCommand : IClientCommand + public class TubeConnectionsCommand : IConsoleCommand { public string Command => "tubeconnections"; public string Description => Loc.GetString("Shows all the directions that a tube can connect in."); public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player?.AttachedEntity == null) { - shell.SendText(player, Loc.GetString("Only players can use this command")); + shell.WriteLine(Loc.GetString("Only players can use this command")); return; } if (args.Length < 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } if (!EntityUid.TryParse(args[0], out var id)) { - shell.SendText(player, Loc.GetString("{0} isn't a valid entity uid", args[0])); + shell.WriteLine(Loc.GetString("{0} isn't a valid entity uid", args[0])); return; } var entityManager = IoCManager.Resolve(); if (!entityManager.TryGetEntity(id, out var entity)) { - shell.SendText(player, Loc.GetString("No entity exists with uid {0}", id)); + shell.WriteLine(Loc.GetString("No entity exists with uid {0}", id)); return; } if (!entity.TryGetComponent(out IDisposalTubeComponent? tube)) { - shell.SendText(player, Loc.GetString("Entity with uid {0} doesn't have a {1} component", id, nameof(IDisposalTubeComponent))); + shell.WriteLine(Loc.GetString("Entity with uid {0} doesn't have a {1} component", id, nameof(IDisposalTubeComponent))); return; } diff --git a/Content.Server/Commands/FindEntitiesWithComponents.cs b/Content.Server/Commands/FindEntitiesWithComponents.cs index 947ab82def..85daab24c6 100644 --- a/Content.Server/Commands/FindEntitiesWithComponents.cs +++ b/Content.Server/Commands/FindEntitiesWithComponents.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; using Content.Server.Administration; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -12,17 +12,17 @@ using Robust.Shared.IoC; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Mapping)] - public class FindEntitiesWithComponents : IClientCommand + public class FindEntitiesWithComponents : IConsoleCommand { public string Command => "findentitieswithcomponents"; public string Description => "Finds entities with all of the specified components."; public string Help => $"{Command} ..."; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length == 0) { - shell.SendText(player, $"Invalid amount of arguments: {args.Length}.\n{Help}"); + shell.WriteLine($"Invalid amount of arguments: {args.Length}.\n{Help}"); return; } @@ -43,7 +43,7 @@ namespace Content.Server.Commands if (invalidArgs.Count > 0) { - shell.SendText(player, $"No component found for component names: {string.Join(", ", invalidArgs)}"); + shell.WriteLine($"No component found for component names: {string.Join(", ", invalidArgs)}"); return; } @@ -63,11 +63,11 @@ namespace Content.Server.Commands if (entityIds.Count == 0) { - shell.SendText(player, $"No entities found with components {string.Join(", ", args)}."); + shell.WriteLine($"No entities found with components {string.Join(", ", args)}."); return; } - shell.SendText(player, $"{entityIds.Count} entities found:\n{string.Join("\n", entityIds)}"); + shell.WriteLine($"{entityIds.Count} entities found:\n{string.Join("\n", entityIds)}"); } } } diff --git a/Content.Server/Commands/GameTicking/DelayStartCommand.cs b/Content.Server/Commands/GameTicking/DelayStartCommand.cs index ff9a219d58..a74293779f 100644 --- a/Content.Server/Commands/GameTicking/DelayStartCommand.cs +++ b/Content.Server/Commands/GameTicking/DelayStartCommand.cs @@ -3,51 +3,51 @@ using Content.Server.Administration; using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server)] - class DelayStartCommand : IClientCommand + class DelayStartCommand : IConsoleCommand { public string Command => "delaystart"; public string Description => "Delays the round start."; public string Help => $"Usage: {Command} \nPauses/Resumes the countdown if no argument is provided."; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var ticker = IoCManager.Resolve(); if (ticker.RunLevel != GameRunLevel.PreRoundLobby) { - shell.SendText(player, "This can only be executed while the game is in the pre-round lobby."); + shell.WriteLine("This can only be executed while the game is in the pre-round lobby."); return; } if (args.Length == 0) { var paused = ticker.TogglePause(); - shell.SendText(player, paused ? "Paused the countdown." : "Resumed the countdown."); + shell.WriteLine(paused ? "Paused the countdown." : "Resumed the countdown."); return; } if (args.Length != 1) { - shell.SendText(player, "Need zero or one arguments."); + shell.WriteLine("Need zero or one arguments."); return; } if (!uint.TryParse(args[0], out var seconds) || seconds == 0) { - shell.SendText(player, $"{args[0]} isn't a valid amount of seconds."); + shell.WriteLine($"{args[0]} isn't a valid amount of seconds."); return; } var time = TimeSpan.FromSeconds(seconds); if (!ticker.DelayStart(time)) { - shell.SendText(player, "An unknown error has occurred."); + shell.WriteLine("An unknown error has occurred."); } } } diff --git a/Content.Server/Commands/GameTicking/EndRoundCommand.cs b/Content.Server/Commands/GameTicking/EndRoundCommand.cs index b274ed61cf..12afa279cb 100644 --- a/Content.Server/Commands/GameTicking/EndRoundCommand.cs +++ b/Content.Server/Commands/GameTicking/EndRoundCommand.cs @@ -3,26 +3,26 @@ using Content.Server.Administration; using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server)] - class EndRoundCommand : IClientCommand + class EndRoundCommand : IConsoleCommand { public string Command => "endround"; public string Description => "Ends the round and moves the server to PostRound."; public string Help => String.Empty; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var ticker = IoCManager.Resolve(); if (ticker.RunLevel != GameRunLevel.InRound) { - shell.SendText(player, "This can only be executed while the game is in a round."); + shell.WriteLine("This can only be executed while the game is in a round."); return; } diff --git a/Content.Server/Commands/GameTicking/ForcePresetCommand.cs b/Content.Server/Commands/GameTicking/ForcePresetCommand.cs index 06c7cd67e4..bdd92c6500 100644 --- a/Content.Server/Commands/GameTicking/ForcePresetCommand.cs +++ b/Content.Server/Commands/GameTicking/ForcePresetCommand.cs @@ -2,43 +2,43 @@ using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server)] - class ForcePresetCommand : IClientCommand + class ForcePresetCommand : IConsoleCommand { public string Command => "forcepreset"; public string Description => "Forces a specific game preset to start for the current lobby."; public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var ticker = IoCManager.Resolve(); if (ticker.RunLevel != GameRunLevel.PreRoundLobby) { - shell.SendText(player, "This can only be executed while the game is in the pre-round lobby."); + shell.WriteLine("This can only be executed while the game is in the pre-round lobby."); return; } if (args.Length != 1) { - shell.SendText(player, "Need exactly one argument."); + shell.WriteLine("Need exactly one argument."); return; } var name = args[0]; if (!ticker.TryGetPreset(name, out var type)) { - shell.SendText(player, $"No preset exists with name {name}."); + shell.WriteLine($"No preset exists with name {name}."); return; } ticker.SetStartPreset(type, true); - shell.SendText(player, $"Forced the game to start with preset {name}."); + shell.WriteLine($"Forced the game to start with preset {name}."); } } } \ No newline at end of file diff --git a/Content.Server/Commands/GameTicking/GoLobbyCommand.cs b/Content.Server/Commands/GameTicking/GoLobbyCommand.cs index 35d2691f00..7ca9c0c76b 100644 --- a/Content.Server/Commands/GameTicking/GoLobbyCommand.cs +++ b/Content.Server/Commands/GameTicking/GoLobbyCommand.cs @@ -4,8 +4,8 @@ using Content.Server.Administration; using Content.Server.Interfaces.GameTicking; using Content.Shared; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.Configuration; using Robust.Shared.IoC; using Robust.Shared.Localization; @@ -13,12 +13,12 @@ using Robust.Shared.Localization; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server)] - public class GoLobbyCommand : IClientCommand + public class GoLobbyCommand : IConsoleCommand { public string Command => "golobby"; public string Description => "Enables the lobby and restarts the round."; public string Help => $"Usage: {Command} / {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { Type? preset = null; var presetName = string.Join(" ", args); @@ -29,7 +29,7 @@ namespace Content.Server.Commands.GameTicking { if (!ticker.TryGetPreset(presetName, out preset)) { - shell.SendText(player, $"No preset found with name {presetName}"); + shell.WriteLine($"No preset found with name {presetName}"); return; } } @@ -44,7 +44,7 @@ namespace Content.Server.Commands.GameTicking ticker.SetStartPreset(preset); } - shell.SendText(player, $"Enabling the lobby and restarting the round.{(preset == null ? "" : $"\nPreset set to {presetName}")}"); + shell.WriteLine($"Enabling the lobby and restarting the round.{(preset == null ? "" : $"\nPreset set to {presetName}")}"); } } } diff --git a/Content.Server/Commands/GameTicking/JoinGameCommand.cs b/Content.Server/Commands/GameTicking/JoinGameCommand.cs index 95006d5781..b160a1fe08 100644 --- a/Content.Server/Commands/GameTicking/JoinGameCommand.cs +++ b/Content.Server/Commands/GameTicking/JoinGameCommand.cs @@ -1,17 +1,17 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Content.Server.Administration; using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; using Content.Shared.Roles; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; using Robust.Shared.Prototypes; namespace Content.Server.Commands.GameTicking { [AnyCommand] - class JoinGameCommand : IClientCommand + class JoinGameCommand : IConsoleCommand { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -23,8 +23,9 @@ namespace Content.Server.Commands.GameTicking { IoCManager.InjectDependencies(this); } - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; var output = string.Join(".", args); if (player == null) { @@ -34,7 +35,7 @@ namespace Content.Server.Commands.GameTicking var ticker = IoCManager.Resolve(); if (ticker.RunLevel == GameRunLevel.PreRoundLobby) { - shell.SendText(player, "Round has not started."); + shell.WriteLine("Round has not started."); return; } else if(ticker.RunLevel == GameRunLevel.InRound) @@ -45,7 +46,7 @@ namespace Content.Server.Commands.GameTicking if(positions.GetValueOrDefault(ID, 0) == 0) //n < 0 is treated as infinite { var jobPrototype = _prototypeManager.Index(ID); - shell.SendText(player, $"{jobPrototype.Name} has no available slots."); + shell.WriteLine($"{jobPrototype.Name} has no available slots."); return; } ticker.MakeJoinGame(player, args[0].ToString()); @@ -55,4 +56,4 @@ namespace Content.Server.Commands.GameTicking ticker.MakeJoinGame(player, null); } } -} \ No newline at end of file +} diff --git a/Content.Server/Commands/GameTicking/MappingCommand.cs b/Content.Server/Commands/GameTicking/MappingCommand.cs index abf94258b5..332e5d57c5 100644 --- a/Content.Server/Commands/GameTicking/MappingCommand.cs +++ b/Content.Server/Commands/GameTicking/MappingCommand.cs @@ -1,9 +1,9 @@ -using System.Linq; +using System.Linq; using Content.Server.Administration; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Timing; +using Robust.Shared.Console; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; using Robust.Shared.Utility; @@ -11,17 +11,18 @@ using Robust.Shared.Utility; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server | AdminFlags.Mapping)] - class MappingCommand : IClientCommand + class MappingCommand : IConsoleCommand { public string Command => "mapping"; public string Description => "Creates and teleports you to a new uninitialized map for mapping."; public string Help => $"Usage: {Command} / {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "Only players can use this command"); + shell.WriteLine("Only players can use this command"); return; } @@ -34,7 +35,7 @@ namespace Content.Server.Commands.GameTicking case 1: if (player.AttachedEntity == null) { - shell.SendText(player, "The map name argument cannot be omitted if you have no entity."); + shell.WriteLine("The map name argument cannot be omitted if you have no entity."); return; } @@ -44,7 +45,7 @@ namespace Content.Server.Commands.GameTicking case 2: if (!int.TryParse(args[0], out var id)) { - shell.SendText(player, $"{args[0]} is not a valid integer."); + shell.WriteLine($"{args[0]} is not a valid integer."); return; } @@ -52,21 +53,21 @@ namespace Content.Server.Commands.GameTicking mapName = args[1]; break; default: - shell.SendText(player, Help); + shell.WriteLine(Help); return; } - shell.ExecuteCommand(player, $"addmap {mapId} false"); - shell.ExecuteCommand(player, $"loadbp {mapId} \"{CommandParsing.Escape(mapName)}\" true"); - shell.ExecuteCommand(player, "aghost"); - shell.ExecuteCommand(player, $"tp 0 0 {mapId}"); + shell.ExecuteCommand($"addmap {mapId} false"); + shell.ExecuteCommand($"loadbp {mapId} \"{CommandParsing.Escape(mapName)}\" true"); + shell.ExecuteCommand("aghost"); + shell.ExecuteCommand($"tp 0 0 {mapId}"); var newGrid = mapManager.GetAllGrids().OrderByDescending(g => (int) g.Index).First(); var pauseManager = IoCManager.Resolve(); pauseManager.SetMapPaused(newGrid.ParentMapId, true); - shell.SendText(player, $"Created unloaded map from file {mapName} with id {mapId}. Use \"savebp {newGrid.Index} foo.yml\" to save the new grid as a map."); + shell.WriteLine($"Created unloaded map from file {mapName} with id {mapId}. Use \"savebp {newGrid.Index} foo.yml\" to save the new grid as a map."); } } } diff --git a/Content.Server/Commands/GameTicking/NewRoundCommand.cs b/Content.Server/Commands/GameTicking/NewRoundCommand.cs index da10407a77..98d90cfab4 100644 --- a/Content.Server/Commands/GameTicking/NewRoundCommand.cs +++ b/Content.Server/Commands/GameTicking/NewRoundCommand.cs @@ -2,20 +2,20 @@ using Content.Server.Administration; using Content.Server.Interfaces.GameTicking; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server)] - public class NewRoundCommand : IClientCommand + public class NewRoundCommand : IConsoleCommand { public string Command => "restartround"; public string Description => "Moves the server from PostRound to a new PreRoundLobby."; public string Help => String.Empty; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var ticker = IoCManager.Resolve(); ticker.RestartRound(); diff --git a/Content.Server/Commands/GameTicking/ObserveCommand.cs b/Content.Server/Commands/GameTicking/ObserveCommand.cs index 4596418418..fcc0e867a6 100644 --- a/Content.Server/Commands/GameTicking/ObserveCommand.cs +++ b/Content.Server/Commands/GameTicking/ObserveCommand.cs @@ -1,20 +1,21 @@ -using Content.Server.Administration; +using Content.Server.Administration; using Content.Server.Interfaces.GameTicking; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AnyCommand] - class ObserveCommand : IClientCommand + class ObserveCommand : IConsoleCommand { public string Command => "observe"; public string Description => ""; public string Help => ""; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { return; @@ -24,4 +25,4 @@ namespace Content.Server.Commands.GameTicking ticker.MakeObserve(player); } } -} \ No newline at end of file +} diff --git a/Content.Server/Commands/GameTicking/RespawnCommand.cs b/Content.Server/Commands/GameTicking/RespawnCommand.cs index 94286c3bcd..9af7ed05d8 100644 --- a/Content.Server/Commands/GameTicking/RespawnCommand.cs +++ b/Content.Server/Commands/GameTicking/RespawnCommand.cs @@ -1,23 +1,24 @@ -using Content.Server.Interfaces.GameTicking; +using Content.Server.Interfaces.GameTicking; using Content.Server.Players; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; using Robust.Shared.Network; namespace Content.Server.Commands.GameTicking { - class RespawnCommand : IClientCommand + class RespawnCommand : IConsoleCommand { public string Command => "respawn"; public string Description => "Respawns a player, kicking them back to the lobby."; public string Help => "respawn [player]"; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (args.Length > 1) { - shell.SendText(player, "Must provide <= 1 argument."); + shell.WriteLine("Must provide <= 1 argument."); return; } @@ -29,7 +30,7 @@ namespace Content.Server.Commands.GameTicking { if (player == null) { - shell.SendText((IPlayerSession)null, "If not a player, an argument must be given."); + shell.WriteLine("If not a player, an argument must be given."); return; } @@ -37,7 +38,7 @@ namespace Content.Server.Commands.GameTicking } else if (!playerMgr.TryGetUserId(args[0], out userId)) { - shell.SendText(player, "Unknown player"); + shell.WriteLine("Unknown player"); return; } @@ -45,17 +46,16 @@ namespace Content.Server.Commands.GameTicking { if (!playerMgr.TryGetPlayerData(userId, out var data)) { - shell.SendText(player, "Unknown player"); + shell.WriteLine("Unknown player"); return; } data.ContentData().WipeMind(); - shell.SendText(player, - "Player is not currently online, but they will respawn if they come back online"); + shell.WriteLine("Player is not currently online, but they will respawn if they come back online"); return; } ticker.Respawn(targetPlayer); } } -} \ No newline at end of file +} diff --git a/Content.Server/Commands/GameTicking/SetGamePresetCommand.cs b/Content.Server/Commands/GameTicking/SetGamePresetCommand.cs index 5a5c1c7f90..b085164e96 100644 --- a/Content.Server/Commands/GameTicking/SetGamePresetCommand.cs +++ b/Content.Server/Commands/GameTicking/SetGamePresetCommand.cs @@ -1,24 +1,24 @@ using Content.Server.Administration; using Content.Server.Interfaces.GameTicking; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server)] - class SetGamePresetCommand : IClientCommand + class SetGamePresetCommand : IConsoleCommand { public string Command => "setgamepreset"; public string Description => ""; public string Help => ""; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 1) { - shell.SendText(player, "Need exactly one argument."); + shell.WriteLine("Need exactly one argument."); return; } diff --git a/Content.Server/Commands/GameTicking/StartRoundCommand.cs b/Content.Server/Commands/GameTicking/StartRoundCommand.cs index b8f3804bbe..14a74caf86 100644 --- a/Content.Server/Commands/GameTicking/StartRoundCommand.cs +++ b/Content.Server/Commands/GameTicking/StartRoundCommand.cs @@ -3,26 +3,26 @@ using Content.Server.Administration; using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server)] - class StartRoundCommand : IClientCommand + class StartRoundCommand : IConsoleCommand { public string Command => "startround"; public string Description => "Ends PreRoundLobby state and starts the round."; public string Help => String.Empty; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var ticker = IoCManager.Resolve(); if (ticker.RunLevel != GameRunLevel.PreRoundLobby) { - shell.SendText(player, "This can only be executed while the game is in the pre-round lobby."); + shell.WriteLine("This can only be executed while the game is in the pre-round lobby."); return; } diff --git a/Content.Server/Commands/GameTicking/TileWallsCommand.cs b/Content.Server/Commands/GameTicking/TileWallsCommand.cs index 668ea461c1..e2c7445763 100644 --- a/Content.Server/Commands/GameTicking/TileWallsCommand.cs +++ b/Content.Server/Commands/GameTicking/TileWallsCommand.cs @@ -1,8 +1,8 @@ -using Content.Server.Administration; +using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.Maps; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; @@ -12,15 +12,16 @@ using Robust.Shared.Map; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Mapping)] - class TileWallsCommand : IClientCommand + class TileWallsCommand : IConsoleCommand { // ReSharper disable once StringLiteralTypo public string Command => "tilewalls"; public string Description => "Puts an underplating tile below every wall on a grid."; public string Help => $"Usage: {Command} | {Command}"; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; GridId gridId; switch (args.Length) @@ -28,7 +29,7 @@ namespace Content.Server.Commands.GameTicking case 0: if (player?.AttachedEntity == null) { - shell.SendText((IPlayerSession) null, "Only a player can run this command."); + shell.WriteLine("Only a player can run this command."); return; } @@ -37,28 +38,28 @@ namespace Content.Server.Commands.GameTicking case 1: if (!int.TryParse(args[0], out var id)) { - shell.SendText(player, $"{args[0]} is not a valid integer."); + shell.WriteLine($"{args[0]} is not a valid integer."); return; } gridId = new GridId(id); break; default: - shell.SendText(player, Help); + shell.WriteLine(Help); return; } var mapManager = IoCManager.Resolve(); if (!mapManager.TryGetGrid(gridId, out var grid)) { - shell.SendText(player, $"No grid exists with id {gridId}"); + shell.WriteLine($"No grid exists with id {gridId}"); return; } var entityManager = IoCManager.Resolve(); if (!entityManager.TryGetEntity(grid.GridEntityId, out var gridEntity)) { - shell.SendText(player, $"Grid {gridId} doesn't have an associated grid entity."); + shell.WriteLine($"Grid {gridId} doesn't have an associated grid entity."); return; } @@ -106,7 +107,7 @@ namespace Content.Server.Commands.GameTicking changed++; } - shell.SendText(player, $"Changed {changed} tiles."); + shell.WriteLine($"Changed {changed} tiles."); } } } diff --git a/Content.Server/Commands/GameTicking/ToggleDisallowLateJoinCommand.cs b/Content.Server/Commands/GameTicking/ToggleDisallowLateJoinCommand.cs index ffb1be19c0..d519ba5754 100644 --- a/Content.Server/Commands/GameTicking/ToggleDisallowLateJoinCommand.cs +++ b/Content.Server/Commands/GameTicking/ToggleDisallowLateJoinCommand.cs @@ -1,24 +1,24 @@ using Content.Server.Administration; using Content.Server.Interfaces.GameTicking; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AdminCommand(AdminFlags.Server)] - class ToggleDisallowLateJoinCommand : IClientCommand + class ToggleDisallowLateJoinCommand : IConsoleCommand { public string Command => "toggledisallowlatejoin"; public string Description => "Allows or disallows latejoining during mid-game."; public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 1) { - shell.SendText(player, "Need exactly one argument."); + shell.WriteLine("Need exactly one argument."); return; } @@ -27,11 +27,11 @@ namespace Content.Server.Commands.GameTicking if (bool.TryParse(args[0], out var result)) { ticker.ToggleDisallowLateJoin(bool.Parse(args[0])); - shell.SendText(player, result ? "Late joining has been disabled." : "Late joining has been enabled."); + shell.WriteLine(result ? "Late joining has been disabled." : "Late joining has been enabled."); } else { - shell.SendText(player, "Invalid argument."); + shell.WriteLine("Invalid argument."); } } } diff --git a/Content.Server/Commands/GameTicking/ToggleReadyCommand.cs b/Content.Server/Commands/GameTicking/ToggleReadyCommand.cs index 0f56e148ce..f710c59fb1 100644 --- a/Content.Server/Commands/GameTicking/ToggleReadyCommand.cs +++ b/Content.Server/Commands/GameTicking/ToggleReadyCommand.cs @@ -1,20 +1,21 @@ -using Content.Server.Administration; +using Content.Server.Administration; using Content.Server.Interfaces.GameTicking; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.GameTicking { [AnyCommand] - class ToggleReadyCommand : IClientCommand + class ToggleReadyCommand : IConsoleCommand { public string Command => "toggleready"; public string Description => ""; public string Help => ""; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { return; @@ -24,4 +25,4 @@ namespace Content.Server.Commands.GameTicking ticker.ToggleReady(player, bool.Parse(args[0])); } } -} \ No newline at end of file +} diff --git a/Content.Server/Commands/HideContainedContextCommand.cs b/Content.Server/Commands/HideContainedContextCommand.cs index ad975313a1..caf3384abe 100644 --- a/Content.Server/Commands/HideContainedContextCommand.cs +++ b/Content.Server/Commands/HideContainedContextCommand.cs @@ -1,25 +1,26 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Debug)] - public class HideContainedContextCommand : IClientCommand + public class HideContainedContextCommand : IConsoleCommand { public string Command => "hidecontainedcontext"; public string Description => $"Reverts the effects of {ShowContainedContextCommand.CommandName}"; public string Help => $"{Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "You need to be a player to use this command."); + shell.WriteLine("You need to be a player to use this command."); return; } diff --git a/Content.Server/Commands/Hungry.cs b/Content.Server/Commands/Hungry.cs index 39daf0caf9..02ddebe18c 100644 --- a/Content.Server/Commands/Hungry.cs +++ b/Content.Server/Commands/Hungry.cs @@ -1,37 +1,38 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.Components.Nutrition; using Content.Shared.Administration; using Content.Shared.GameObjects.Components.Nutrition; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Debug)] - public class Hungry : IClientCommand + public class Hungry : IConsoleCommand { public string Command => "hungry"; public string Description => "Makes you hungry."; public string Help => $"{Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "You cannot use this command unless you are a player."); + shell.WriteLine("You cannot use this command unless you are a player."); return; } if (player.AttachedEntity == null) { - shell.SendText(player, "You cannot use this command without an entity."); + shell.WriteLine("You cannot use this command without an entity."); return; } if (!player.AttachedEntity.TryGetComponent(out HungerComponent? hunger)) { - shell.SendText(player, $"Your entity does not have a {nameof(HungerComponent)} component."); + shell.WriteLine($"Your entity does not have a {nameof(HungerComponent)} component."); return; } diff --git a/Content.Server/Commands/HurtCommand.cs b/Content.Server/Commands/HurtCommand.cs index 1810852aaf..532af0304e 100644 --- a/Content.Server/Commands/HurtCommand.cs +++ b/Content.Server/Commands/HurtCommand.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Diagnostics.CodeAnalysis; using System.Text; @@ -6,8 +6,8 @@ using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.Damage; using Content.Shared.GameObjects.Components.Damage; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -15,7 +15,7 @@ using Robust.Shared.IoC; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Fun)] - class HurtCommand : IClientCommand + class HurtCommand : IConsoleCommand { public string Command => "hurt"; public string Description => "Ouch"; @@ -53,7 +53,7 @@ namespace Content.Server.Commands if (playerEntity == null) { - shell.SendText(player, $"You must have a player entity to use this command without specifying an entity.\n{Help}"); + shell.WriteLine($"You must have a player entity to use this command without specifying an entity.\n{Help}"); return false; } @@ -63,7 +63,7 @@ namespace Content.Server.Commands if (!EntityUid.TryParse(arg, out var entityUid)) { - shell.SendText(player, $"{arg} is not a valid entity uid.\n{Help}"); + shell.WriteLine($"{arg} is not a valid entity uid.\n{Help}"); return false; } @@ -72,7 +72,7 @@ namespace Content.Server.Commands if (!entityManager.TryGetEntity(entityUid, out var parsedEntity)) { - shell.SendText(player, $"No entity found with uid {entityUid}"); + shell.WriteLine($"No entity found with uid {entityUid}"); return false; } @@ -89,7 +89,7 @@ namespace Content.Server.Commands { if (!int.TryParse(args[1], out var amount)) { - shell.SendText(player, $"{args[1]} is not a valid damage integer."); + shell.WriteLine($"{args[1]} is not a valid damage integer."); func = null; return false; @@ -101,20 +101,19 @@ namespace Content.Server.Commands { if (!damageable.DamageClasses.ContainsKey(damageClass)) { - shell.SendText(player, $"Entity {damageable.Owner.Name} with id {damageable.Owner.Uid} can not be damaged with damage class {damageClass}"); + shell.WriteLine($"Entity {damageable.Owner.Name} with id {damageable.Owner.Uid} can not be damaged with damage class {damageClass}"); return; } if (!damageable.ChangeDamage(damageClass, amount, ignoreResistances)) { - shell.SendText(player, $"Entity {damageable.Owner.Name} with id {damageable.Owner.Uid} received no damage."); + shell.WriteLine($"Entity {damageable.Owner.Name} with id {damageable.Owner.Uid} received no damage."); return; } - shell.SendText(player, - $"Damaged entity {damageable.Owner.Name} with id {damageable.Owner.Uid} for {amount} {damageClass} damage{(ignoreResistances ? ", ignoring resistances." : ".")}"); + shell.WriteLine($"Damaged entity {damageable.Owner.Name} with id {damageable.Owner.Uid} for {amount} {damageClass} damage{(ignoreResistances ? ", ignoring resistances." : ".")}"); }; return true; @@ -126,37 +125,38 @@ namespace Content.Server.Commands { if (!damageable.DamageTypes.ContainsKey(damageType)) { - shell.SendText(player, $"Entity {damageable.Owner.Name} with id {damageable.Owner.Uid} can not be damaged with damage class {damageType}"); + shell.WriteLine($"Entity {damageable.Owner.Name} with id {damageable.Owner.Uid} can not be damaged with damage class {damageType}"); return; } if (!damageable.ChangeDamage(damageType, amount, ignoreResistances)) { - shell.SendText(player, $"Entity {damageable.Owner.Name} with id {damageable.Owner.Uid} received no damage."); + shell.WriteLine($"Entity {damageable.Owner.Name} with id {damageable.Owner.Uid} received no damage."); return; } - shell.SendText(player, $"Damaged entity {damageable.Owner.Name} with id {damageable.Owner.Uid} for {amount} {damageType} damage{(ignoreResistances ? ", ignoring resistances." : ".")}"); + shell.WriteLine($"Damaged entity {damageable.Owner.Name} with id {damageable.Owner.Uid} for {amount} {damageType} damage{(ignoreResistances ? ", ignoring resistances." : ".")}"); }; return true; } else { - shell.SendText(player, $"{args[0]} is not a valid damage class or type."); + shell.WriteLine($"{args[0]} is not a valid damage class or type."); var types = DamageTypes(); - shell.SendText(player, types); + shell.WriteLine(types); func = null; return false; } } - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; bool ignoreResistances; IEntity entity; Damage? damageFunc; @@ -172,12 +172,12 @@ namespace Content.Server.Commands types = types.Replace('e', 'é'); } - shell.SendText(player, types); + shell.WriteLine(types); return; // Not enough args case var n when n < 2: - shell.SendText(player, $"Invalid number of arguments ({args.Length}).\n{Help}"); + shell.WriteLine($"Invalid number of arguments ({args.Length}).\n{Help}"); return; case var n when n >= 2 && n <= 4: if (!TryParseDamageArgs(shell, player, args, out damageFunc)) @@ -198,7 +198,7 @@ namespace Content.Server.Commands { if (!bool.TryParse(args[3], out ignoreResistances)) { - shell.SendText(player, $"{args[3]} is not a valid boolean value for ignoreResistances.\n{Help}"); + shell.WriteLine($"{args[3]} is not a valid boolean value for ignoreResistances.\n{Help}"); return; } } @@ -209,13 +209,13 @@ namespace Content.Server.Commands break; default: - shell.SendText(player, $"Invalid amount of arguments ({args.Length}).\n{Help}"); + shell.WriteLine($"Invalid amount of arguments ({args.Length}).\n{Help}"); return; } if (!entity.TryGetComponent(out IDamageableComponent? damageable)) { - shell.SendText(player, $"Entity {entity.Name} with id {entity.Uid} does not have a {nameof(IDamageableComponent)}."); + shell.WriteLine($"Entity {entity.Name} with id {entity.Uid} does not have a {nameof(IDamageableComponent)}."); return; } diff --git a/Content.Server/Commands/Interactable/AnchorCommand.cs b/Content.Server/Commands/Interactable/AnchorCommand.cs index c84637ebb9..1d891fbb43 100644 --- a/Content.Server/Commands/Interactable/AnchorCommand.cs +++ b/Content.Server/Commands/Interactable/AnchorCommand.cs @@ -1,24 +1,25 @@ -#nullable enable +#nullable enable using System.Linq; using Content.Server.Administration; using Content.Server.GameObjects.Components; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Interactable { [AdminCommand(AdminFlags.Debug)] - class AnchorCommand : IClientCommand + class AnchorCommand : IConsoleCommand { public string Command => "anchor"; public string Description => "Anchors all entities in a radius around the user"; public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player?.AttachedEntity == null) { return; @@ -26,19 +27,19 @@ namespace Content.Server.Commands.Interactable if (args.Length != 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } if (!int.TryParse(args[0], out var radius)) { - shell.SendText(player, $"{args[0]} isn't a valid integer."); + shell.WriteLine($"{args[0]} isn't a valid integer."); return; } if (radius < 0) { - shell.SendText(player, "Radius must be positive."); + shell.WriteLine("Radius must be positive."); return; } diff --git a/Content.Server/Commands/Interactable/TilePryCommand.cs b/Content.Server/Commands/Interactable/TilePryCommand.cs index 06c390373b..9691736f51 100644 --- a/Content.Server/Commands/Interactable/TilePryCommand.cs +++ b/Content.Server/Commands/Interactable/TilePryCommand.cs @@ -1,10 +1,10 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.Components.Interactable; using Content.Shared.Administration; using Content.Shared.Maps; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; using Robust.Shared.Map; @@ -15,14 +15,15 @@ namespace Content.Server.Commands.Interactable /// /// [AdminCommand(AdminFlags.Debug)] - class TilePryCommand : IClientCommand + class TilePryCommand : IConsoleCommand { public string Command => "tilepry"; public string Description => "Pries up all tiles in a radius around the user."; public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player?.AttachedEntity == null) { return; @@ -30,19 +31,19 @@ namespace Content.Server.Commands.Interactable if (args.Length != 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } if (!int.TryParse(args[0], out var radius)) { - shell.SendText(player, $"{args[0]} isn't a valid integer."); + shell.WriteLine($"{args[0]} isn't a valid integer."); return; } if (radius < 0) { - shell.SendText(player, "Radius must be positive."); + shell.WriteLine("Radius must be positive."); return; } diff --git a/Content.Server/Commands/Interactable/UnAnchorCommand.cs b/Content.Server/Commands/Interactable/UnAnchorCommand.cs index 3eca799b2e..5fdf8c23f0 100644 --- a/Content.Server/Commands/Interactable/UnAnchorCommand.cs +++ b/Content.Server/Commands/Interactable/UnAnchorCommand.cs @@ -1,24 +1,25 @@ -#nullable enable +#nullable enable using System.Linq; using Content.Server.Administration; using Content.Server.GameObjects.Components; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Interactable { [AdminCommand(AdminFlags.Debug)] - class UnAnchorCommand : IClientCommand + class UnAnchorCommand : IConsoleCommand { public string Command => "unanchor"; public string Description => "Unanchors all anchorable entities in a radius around the user"; public string Help => $"Usage: {Command} "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player?.AttachedEntity == null) { return; @@ -26,19 +27,19 @@ namespace Content.Server.Commands.Interactable if (args.Length != 1) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } if (!int.TryParse(args[0], out var radius)) { - shell.SendText(player, $"{args[0]} isn't a valid integer."); + shell.WriteLine($"{args[0]} isn't a valid integer."); return; } if (radius < 0) { - shell.SendText(player, "Radius must be positive."); + shell.WriteLine("Radius must be positive."); return; } diff --git a/Content.Server/Commands/MachineLinking/SignalLinkerCommand.cs b/Content.Server/Commands/MachineLinking/SignalLinkerCommand.cs index a836885fe5..d729edddff 100644 --- a/Content.Server/Commands/MachineLinking/SignalLinkerCommand.cs +++ b/Content.Server/Commands/MachineLinking/SignalLinkerCommand.cs @@ -1,15 +1,15 @@ -using Content.Server.Administration; +using Content.Server.Administration; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; namespace Content.Server.Commands.MachineLinking { [AdminCommand(AdminFlags.Debug)] - public class SignalLinkerCommand : IClientCommand + public class SignalLinkerCommand : IConsoleCommand { public string Command => "signallink"; @@ -17,8 +17,9 @@ namespace Content.Server.Commands.MachineLinking public string Help => "signallink (on/off)"; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; bool? enable = null; if (args.Length > 0) { @@ -43,7 +44,7 @@ namespace Content.Server.Commands.MachineLinking } var ret = system.SignalLinkerKeybind(player.UserId, enable); - shell.SendText(player, ret ? "Enabled" : "Disabled"); + shell.WriteLine(ret ? "Enabled" : "Disabled"); } } -} \ No newline at end of file +} diff --git a/Content.Server/Commands/MakeSentientCommand.cs b/Content.Server/Commands/MakeSentientCommand.cs index 53197b3908..aa9c99cdb0 100644 --- a/Content.Server/Commands/MakeSentientCommand.cs +++ b/Content.Server/Commands/MakeSentientCommand.cs @@ -3,8 +3,8 @@ using Content.Server.Administration; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Movement; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -12,23 +12,23 @@ using Robust.Shared.IoC; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Fun)] - public class MakeSentientCommand : IClientCommand + public class MakeSentientCommand : IConsoleCommand { public string Command => "makesentient"; public string Description => "Makes an entity sentient (able to be controlled by a player)"; public string Help => "makesentient "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 1) { - shell.SendText(player, "Wrong number of arguments."); + shell.WriteLine("Wrong number of arguments."); return; } if (!int.TryParse(args[0], out var id)) { - shell.SendText(player, "Invalid argument."); + shell.WriteLine("Invalid argument."); return; } @@ -38,7 +38,7 @@ namespace Content.Server.Commands if (!entityManager.TryGetEntity(entId, out var entity) || entity.Deleted) { - shell.SendText(player, "Invalid entity specified!"); + shell.WriteLine("Invalid entity specified!"); return; } diff --git a/Content.Server/Commands/Mobs/AddOverlayCommand.cs b/Content.Server/Commands/Mobs/AddOverlayCommand.cs deleted file mode 100644 index 4bbf196e48..0000000000 --- a/Content.Server/Commands/Mobs/AddOverlayCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Content.Server.Administration; -using Content.Server.GameObjects.Components.Mobs; -using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; -using Robust.Server.Interfaces.Player; - -namespace Content.Server.Commands.Mobs -{ - [AdminCommand(AdminFlags.Debug)] - public class AddOverlayCommand : IClientCommand - { - public string Command => "addoverlay"; - public string Description => "Adds an overlay by its ID"; - public string Help => "addoverlay "; - - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) - { - if (args.Length != 1) - { - shell.SendText(player, "Expected 1 argument."); - return; - } - - if (player?.AttachedEntity != null) - { - if (player.AttachedEntity.TryGetComponent(out ServerOverlayEffectsComponent overlayEffectsComponent)) - { - overlayEffectsComponent.AddOverlay(args[0]); - } - } - } - } -} \ No newline at end of file diff --git a/Content.Server/Commands/Mobs/AddRoleCommand.cs b/Content.Server/Commands/Mobs/AddRoleCommand.cs index af714411f1..eedec5dfbc 100644 --- a/Content.Server/Commands/Mobs/AddRoleCommand.cs +++ b/Content.Server/Commands/Mobs/AddRoleCommand.cs @@ -3,15 +3,15 @@ using Content.Server.Mobs.Roles; using Content.Server.Players; using Content.Shared.Administration; using Content.Shared.Roles; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; using Robust.Shared.Prototypes; namespace Content.Server.Commands.Mobs { [AdminCommand(AdminFlags.Fun)] - public class AddRoleCommand : IClientCommand + public class AddRoleCommand : IConsoleCommand { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -21,11 +21,11 @@ namespace Content.Server.Commands.Mobs public string Help => "addrole \nThat role type is the actual C# type name."; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 2) { - shell.SendText(player, "Expected exactly 2 arguments."); + shell.WriteLine("Expected exactly 2 arguments."); return; } @@ -38,7 +38,7 @@ namespace Content.Server.Commands.Mobs } else { - shell.SendText(player, "Can't find that mind"); + shell.WriteLine("Can't find that mind"); } } } diff --git a/Content.Server/Commands/Mobs/MindInfoCommand.cs b/Content.Server/Commands/Mobs/MindInfoCommand.cs index 9a546b7ce9..520fdde43a 100644 --- a/Content.Server/Commands/Mobs/MindInfoCommand.cs +++ b/Content.Server/Commands/Mobs/MindInfoCommand.cs @@ -2,14 +2,14 @@ using Content.Server.Administration; using Content.Server.Players; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Mobs { [AdminCommand(AdminFlags.Admin)] - public class MindInfoCommand : IClientCommand + public class MindInfoCommand : IConsoleCommand { public string Command => "mindinfo"; @@ -17,11 +17,11 @@ namespace Content.Server.Commands.Mobs public string Help => "mindinfo "; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 1) { - shell.SendText(player, "Expected exactly 1 argument."); + shell.WriteLine("Expected exactly 1 argument."); return; } @@ -37,11 +37,11 @@ namespace Content.Server.Commands.Mobs builder.AppendFormat("{0} ", role.Name); } - shell.SendText(player, builder.ToString()); + shell.WriteLine(builder.ToString()); } else { - shell.SendText(player, "Can't find that mind"); + shell.WriteLine("Can't find that mind"); } } } diff --git a/Content.Server/Commands/Mobs/RemoveOverlayCommand.cs b/Content.Server/Commands/Mobs/RemoveOverlayCommand.cs deleted file mode 100644 index c08e8f4ff6..0000000000 --- a/Content.Server/Commands/Mobs/RemoveOverlayCommand.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Content.Server.Administration; -using Content.Server.GameObjects.Components.Mobs; -using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; -using Robust.Server.Interfaces.Player; - -namespace Content.Server.Commands.Mobs -{ - [AdminCommand(AdminFlags.Debug)] - public class RemoveOverlayCommand : IClientCommand - { - public string Command => "rmoverlay"; - public string Description => "Removes an overlay by its ID"; - public string Help => "rmoverlay "; - - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) - { - if (args.Length != 1) - { - shell.SendText(player, "Expected 1 argument."); - return; - } - - if (player?.AttachedEntity != null) - { - if (player.AttachedEntity.TryGetComponent(out ServerOverlayEffectsComponent overlayEffectsComponent)) - { - overlayEffectsComponent.RemoveOverlay(args[0]); - } - } - } - } -} diff --git a/Content.Server/Commands/Mobs/RemoveRoleCommand.cs b/Content.Server/Commands/Mobs/RemoveRoleCommand.cs index 691082f849..11763ea74e 100644 --- a/Content.Server/Commands/Mobs/RemoveRoleCommand.cs +++ b/Content.Server/Commands/Mobs/RemoveRoleCommand.cs @@ -3,15 +3,15 @@ using Content.Server.Mobs.Roles; using Content.Server.Players; using Content.Shared.Administration; using Content.Shared.Roles; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; using Robust.Shared.Prototypes; namespace Content.Server.Commands.Mobs { [AdminCommand(AdminFlags.Fun)] - public class RemoveRoleCommand : IClientCommand + public class RemoveRoleCommand : IConsoleCommand { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; @@ -21,11 +21,11 @@ namespace Content.Server.Commands.Mobs public string Help => "rmrole \nThat role type is the actual C# type name."; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 2) { - shell.SendText(player, "Expected exactly 2 arguments."); + shell.WriteLine("Expected exactly 2 arguments."); return; } @@ -38,7 +38,7 @@ namespace Content.Server.Commands.Mobs } else { - shell.SendText(player, "Can't find that mind"); + shell.WriteLine("Can't find that mind"); } } } diff --git a/Content.Server/Commands/Notify/PopupMsgCommand.cs b/Content.Server/Commands/Notify/PopupMsgCommand.cs index a86e07e217..524439e34e 100644 --- a/Content.Server/Commands/Notify/PopupMsgCommand.cs +++ b/Content.Server/Commands/Notify/PopupMsgCommand.cs @@ -1,8 +1,8 @@ using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.Interfaces; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -10,13 +10,13 @@ using Robust.Shared.IoC; namespace Content.Server.Commands.Notify { [AdminCommand(AdminFlags.Debug)] - public class PopupMsgCommand : IClientCommand + public class PopupMsgCommand : IConsoleCommand { public string Command => "srvpopupmsg"; public string Description => ""; public string Help => ""; - public void Execute(IConsoleShell shell, IPlayerSession player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var entityMgr = IoCManager.Resolve(); diff --git a/Content.Server/Commands/Objectives/AddObjectiveCommand.cs b/Content.Server/Commands/Objectives/AddObjectiveCommand.cs index 233a2d1650..24785024e3 100644 --- a/Content.Server/Commands/Objectives/AddObjectiveCommand.cs +++ b/Content.Server/Commands/Objectives/AddObjectiveCommand.cs @@ -3,31 +3,31 @@ using Content.Server.Administration; using Content.Server.Objectives; using Content.Server.Players; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; using Robust.Shared.Prototypes; namespace Content.Server.Commands.Objectives { [AdminCommand(AdminFlags.Admin)] - public class AddObjectiveCommand : IClientCommand + public class AddObjectiveCommand : IConsoleCommand { public string Command => "addobjective"; public string Description => "Adds an objective to the player's mind."; public string Help => "addobjective "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 2) { - shell.SendText(player, "Expected exactly 2 arguments."); + shell.WriteLine("Expected exactly 2 arguments."); return; } var mgr = IoCManager.Resolve(); if (!mgr.TryGetPlayerDataByUsername(args[0], out var data)) { - shell.SendText(player, "Can't find the playerdata."); + shell.WriteLine("Can't find the playerdata."); return; } @@ -35,20 +35,20 @@ namespace Content.Server.Commands.Objectives var mind = data.ContentData()?.Mind; if (mind == null) { - shell.SendText(player, "Can't find the mind."); + shell.WriteLine("Can't find the mind."); return; } if (!IoCManager.Resolve() .TryIndex(args[1], out var objectivePrototype)) { - shell.SendText(player, $"Can't find matching ObjectivePrototype {objectivePrototype}"); + shell.WriteLine($"Can't find matching ObjectivePrototype {objectivePrototype}"); return; } if (!mind.TryAddObjective(objectivePrototype)) { - shell.SendText(player, "Objective requirements dont allow that objective to be added."); + shell.WriteLine("Objective requirements dont allow that objective to be added."); } } diff --git a/Content.Server/Commands/Objectives/ListObjectivesCommand.cs b/Content.Server/Commands/Objectives/ListObjectivesCommand.cs index c7b4338a14..536b4e536f 100644 --- a/Content.Server/Commands/Objectives/ListObjectivesCommand.cs +++ b/Content.Server/Commands/Objectives/ListObjectivesCommand.cs @@ -1,22 +1,23 @@ -#nullable enable +#nullable enable using System.Linq; using Content.Server.Administration; using Content.Server.Players; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Objectives { [AdminCommand(AdminFlags.Admin)] - public class ListObjectivesCommand : IClientCommand + public class ListObjectivesCommand : IConsoleCommand { public string Command => "lsobjectives"; public string Description => "Lists all objectives in a players mind."; public string Help => "lsobjectives []"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; IPlayerData? data; if (args.Length == 0 && player != null) { @@ -24,26 +25,26 @@ namespace Content.Server.Commands.Objectives } else if (player == null || !IoCManager.Resolve().TryGetPlayerDataByUsername(args[0], out data)) { - shell.SendText(player, "Can't find the playerdata."); + shell.WriteLine("Can't find the playerdata."); return; } var mind = data.ContentData()?.Mind; if (mind == null) { - shell.SendText(player, "Can't find the mind."); + shell.WriteLine("Can't find the mind."); return; } - shell.SendText(player, $"Objectives for player {data.UserId}:"); + shell.WriteLine($"Objectives for player {data.UserId}:"); var objectives = mind.AllObjectives.ToList(); if (objectives.Count == 0) { - shell.SendText(player, "None."); + shell.WriteLine("None."); } for (var i = 0; i < objectives.Count; i++) { - shell.SendText(player, $"- [{i}] {objectives[i]}"); + shell.WriteLine($"- [{i}] {objectives[i]}"); } } diff --git a/Content.Server/Commands/Objectives/RemoveObjectiveCommand.cs b/Content.Server/Commands/Objectives/RemoveObjectiveCommand.cs index 2fcc87f646..988090c25d 100644 --- a/Content.Server/Commands/Objectives/RemoveObjectiveCommand.cs +++ b/Content.Server/Commands/Objectives/RemoveObjectiveCommand.cs @@ -2,23 +2,23 @@ using Content.Server.Administration; using Content.Server.Players; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.IoC; namespace Content.Server.Commands.Objectives { [AdminCommand(AdminFlags.Admin)] - public class RemoveObjectiveCommand : IClientCommand + public class RemoveObjectiveCommand : IConsoleCommand { public string Command => "rmobjective"; public string Description => "Removes an objective from the player's mind."; public string Help => "rmobjective "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 2) { - shell.SendText(player, "Expected exactly 2 arguments."); + shell.WriteLine("Expected exactly 2 arguments."); return; } @@ -28,25 +28,24 @@ namespace Content.Server.Commands.Objectives var mind = data.ContentData()?.Mind; if (mind == null) { - shell.SendText(player, "Can't find the mind."); + shell.WriteLine("Can't find the mind."); return; } if (int.TryParse(args[1], out var i)) { - shell.SendText(player, - mind.TryRemoveObjective(i) - ? "Objective successfully removed!" - : "Objective removing failed. Maybe the index is out of bounds? Check lsobjectives!"); + shell.WriteLine(mind.TryRemoveObjective(i) + ? "Objective successfully removed!" + : "Objective removing failed. Maybe the index is out of bounds? Check lsobjectives!"); } else { - shell.SendText(player, $"Invalid index {args[1]}!"); + shell.WriteLine($"Invalid index {args[1]}!"); } } else { - shell.SendText(player, "Can't find the playerdata."); + shell.WriteLine("Can't find the playerdata."); } } } diff --git a/Content.Server/Commands/Observer/Ghost.cs b/Content.Server/Commands/Observer/Ghost.cs index 6aa887dd47..18be076486 100644 --- a/Content.Server/Commands/Observer/Ghost.cs +++ b/Content.Server/Commands/Observer/Ghost.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Observer; @@ -8,39 +8,40 @@ using Content.Shared.Damage; using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Mobs.State; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; namespace Content.Server.Commands.Observer { [AnyCommand] - public class Ghost : IClientCommand + public class Ghost : IConsoleCommand { public string Command => "ghost"; public string Description => "Give up on life and become a ghost."; public string Help => "ghost"; public bool CanReturn { get; set; } = true; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell?.SendText(player, "You have no session, you can't ghost."); + shell?.WriteLine("You have no session, you can't ghost."); return; } var mind = player.ContentData()?.Mind; if (mind == null) { - shell?.SendText(player, "You have no Mind, you can't ghost."); + shell?.WriteLine("You have no Mind, you can't ghost."); return; } if (!IoCManager.Resolve().OnGhostAttempt(mind, CanReturn)) { - shell?.SendText(player, "You can't ghost right now."); + shell?.WriteLine("You can't ghost right now."); return; } } diff --git a/Content.Server/Commands/RemoveExtraComponents.cs b/Content.Server/Commands/RemoveExtraComponents.cs index b5b269fb83..d2bb8bb2ce 100644 --- a/Content.Server/Commands/RemoveExtraComponents.cs +++ b/Content.Server/Commands/RemoveExtraComponents.cs @@ -1,8 +1,8 @@ #nullable enable using Content.Server.Administration; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -11,12 +11,12 @@ using Robust.Shared.Prototypes; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Mapping)] - public class RemoveExtraComponents : IClientCommand + public class RemoveExtraComponents : IConsoleCommand { public string Command => "removeextracomponents"; public string Description => "Removes all components from all entities of the specified id if that component is not in its prototype.\nIf no id is specified, it matches all entities."; public string Help => $"{Command} / {Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { var id = args.Length == 0 ? null : string.Join(" ", args); var entityManager = IoCManager.Resolve(); @@ -32,7 +32,7 @@ namespace Content.Server.Commands { if (!prototypeManager.TryIndex(id, out EntityPrototype prototype)) { - shell.SendText(player, $"No entity prototype found with id {id}."); + shell.WriteLine($"No entity prototype found with id {id}."); return; } @@ -68,7 +68,7 @@ namespace Content.Server.Commands } } - shell.SendText(player, $"Removed {components} components from {entities} entities{(id == null ? "." : $" with id {id}")}"); + shell.WriteLine($"Removed {components} components from {entities} entities{(id == null ? "." : $" with id {id}")}"); } } } diff --git a/Content.Server/Commands/SetAnchorCommand.cs b/Content.Server/Commands/SetAnchorCommand.cs index 532458d55e..3dc2a16cf5 100644 --- a/Content.Server/Commands/SetAnchorCommand.cs +++ b/Content.Server/Commands/SetAnchorCommand.cs @@ -1,8 +1,8 @@ #nullable enable using Content.Server.Administration; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; @@ -11,22 +11,22 @@ using Robust.Shared.IoC; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Debug)] - public class SetAnchorCommand : IClientCommand + public class SetAnchorCommand : IConsoleCommand { public string Command => "setanchor"; public string Description => "Sets the anchoring state of an entity."; public string Help => "setanchor "; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length == 0 || args.Length > 2) { - shell.SendText(player, "Invalid number of argument!"); + shell.WriteLine("Invalid number of argument!"); return; } if (!int.TryParse(args[0], out var id)) { - shell.SendText(player, "Invalid argument specified!"); + shell.WriteLine("Invalid argument specified!"); return; } @@ -36,7 +36,7 @@ namespace Content.Server.Commands if (!entityManager.TryGetEntity(entId, out var entity) || entity.Deleted || !entity.TryGetComponent(out PhysicsComponent? physics)) { - shell.SendText(player, "Invalid entity specified!"); + shell.WriteLine("Invalid entity specified!"); return; } @@ -44,7 +44,7 @@ namespace Content.Server.Commands { if (!bool.TryParse(args[1], out var value)) { - shell.SendText(player, "Invalid argument specified!"); + shell.WriteLine("Invalid argument specified!"); return; } diff --git a/Content.Server/Commands/ShowContainedContextCommand.cs b/Content.Server/Commands/ShowContainedContextCommand.cs index 8afcc5501b..fc93c08a7f 100644 --- a/Content.Server/Commands/ShowContainedContextCommand.cs +++ b/Content.Server/Commands/ShowContainedContextCommand.cs @@ -1,15 +1,15 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.EntitySystems; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Debug)] - public class ShowContainedContextCommand : IClientCommand + public class ShowContainedContextCommand : IConsoleCommand { public const string CommandName = "showcontainedcontext"; @@ -18,11 +18,12 @@ namespace Content.Server.Commands public string Description => "Makes contained entities visible on the context menu, even when they shouldn't be."; public string Help => $"{Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player == null) { - shell.SendText(player, "You need to be a player to use this command."); + shell.WriteLine("You need to be a player to use this command."); return; } diff --git a/Content.Server/Commands/Speech/AddAccent.cs b/Content.Server/Commands/Speech/AddAccent.cs index 530049c124..df410a8248 100644 --- a/Content.Server/Commands/Speech/AddAccent.cs +++ b/Content.Server/Commands/Speech/AddAccent.cs @@ -1,34 +1,35 @@ -#nullable enable +#nullable enable using System; using System.Linq; using Content.Server.Administration; using Content.Server.GameObjects.Components.Mobs.Speech; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; namespace Content.Server.Commands.Speech { [AdminCommand(AdminFlags.Fun)] - public class AddAccent : IClientCommand + public class AddAccent : IConsoleCommand { public string Command => "addaccent"; public string Description => "Add a speech component to the current player"; public string Help => $"{Command} /?"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (player?.AttachedEntity == null) { - shell.SendText(player, "You don't have an entity!"); + shell.WriteLine("You don't have an entity!"); return; } if (args.Length == 0) { - shell.SendText(player, Help); + shell.WriteLine(Help); return; } @@ -44,7 +45,7 @@ namespace Content.Server.Commands.Speech { msg += $"{compFactory.GetRegistration(s).Name}\n"; } - shell.SendText(player, msg); + shell.WriteLine(msg); } else { @@ -58,7 +59,7 @@ namespace Content.Server.Commands.Speech } catch (Exception) { - shell.SendText(player, $"Accent {name} not found. Try {Command} ? to get a list of all appliable accents."); + shell.WriteLine($"Accent {name} not found. Try {Command} ? to get a list of all appliable accents."); return; } @@ -66,7 +67,7 @@ namespace Content.Server.Commands.Speech try { var comp = player.AttachedEntity.GetComponent(type); - shell.SendText(player, "You already have this accent!"); + shell.WriteLine("You already have this accent!"); return; } catch (Exception) diff --git a/Content.Server/Commands/StartSingularityEngineCommand.cs b/Content.Server/Commands/StartSingularityEngineCommand.cs index 1a0b703434..4a9695fae4 100644 --- a/Content.Server/Commands/StartSingularityEngineCommand.cs +++ b/Content.Server/Commands/StartSingularityEngineCommand.cs @@ -6,8 +6,8 @@ using Content.Server.GameObjects.Components.Singularity; using Content.Server.GameObjects.Components.PA; using Content.Shared.Administration; using Content.Shared.GameObjects.Components; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; @@ -15,17 +15,17 @@ using Robust.Shared.IoC; namespace Content.Server.Commands { [AdminCommand(AdminFlags.Admin)] - public class StartSingularityEngineCommand : IClientCommand + public class StartSingularityEngineCommand : IConsoleCommand { public string Command => "startsingularityengine"; public string Description => "Automatically turns on the particle accelerator and containment field emitters."; public string Help => $"{Command}"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 0) { - shell.SendText(player, $"Invalid amount of arguments: {args.Length}.\n{Help}"); + shell.WriteLine($"Invalid amount of arguments: {args.Length}.\n{Help}"); return; } @@ -41,7 +41,7 @@ namespace Content.Server.Commands pacb.SetStrength(ParticleAcceleratorPowerState.Level1); pacb.SwitchOn(); } - shell.SendText(player, "Done!"); + shell.WriteLine("Done!"); } } } diff --git a/Content.Server/Commands/StationEvents/StationEventCommand.cs b/Content.Server/Commands/StationEvents/StationEventCommand.cs index 95c8b910fd..99f28ce5a0 100644 --- a/Content.Server/Commands/StationEvents/StationEventCommand.cs +++ b/Content.Server/Commands/StationEvents/StationEventCommand.cs @@ -1,16 +1,16 @@ -#nullable enable +#nullable enable using Content.Server.Administration; using Content.Server.GameObjects.EntitySystems.StationEvents; using Content.Shared.Administration; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; +using Robust.Shared.Console; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Localization; namespace Content.Server.Commands.StationEvents { [AdminCommand(AdminFlags.Server)] - public sealed class StationEventCommand : IClientCommand + public sealed class StationEventCommand : IConsoleCommand { public string Command => "events"; public string Description => "Provides admin control to station events"; @@ -27,11 +27,12 @@ namespace Content.Server.Commands.StationEvents private const string RunHelp = "run : start a particular event now; is case-insensitive and not localized"; - public void Execute(IConsoleShell shell, IPlayerSession? player, string[] args) + public void Execute(IConsoleShell shell, string argStr, string[] args) { + var player = shell.Player as IPlayerSession; if (args.Length == 0) { - shell.SendText(player, $"Invalid amount of arguments.\n{Help}"); + shell.WriteLine($"Invalid amount of arguments.\n{Help}"); return; } @@ -56,14 +57,14 @@ namespace Content.Server.Commands.StationEvents case "run": if (args.Length != 2) { - shell.SendText(player, $"Need 2 arguments, there were {args.Length}.\n{RunHelp}"); + shell.WriteLine($"Need 2 arguments, there were {args.Length}.\n{RunHelp}"); break; } Run(shell, player, args[1]); break; default: - shell.SendText(player, Loc.GetString($"Invalid events command.\n{Help}")); + shell.WriteLine(Loc.GetString($"Invalid events command.\n{Help}")); break; } } @@ -76,7 +77,7 @@ namespace Content.Server.Commands.StationEvents ? stationSystem.RunRandomEvent() : stationSystem.RunEvent(eventName); - shell.SendText(player, resultText); + shell.WriteLine(resultText); } private void Running(IConsoleShell shell, IPlayerSession? player) @@ -84,18 +85,18 @@ namespace Content.Server.Commands.StationEvents var eventName = EntitySystem.Get().CurrentEvent?.Name; if (!string.IsNullOrEmpty(eventName)) { - shell.SendText(player, eventName); + shell.WriteLine(eventName); } else { - shell.SendText(player, Loc.GetString("No station event running")); + shell.WriteLine(Loc.GetString("No station event running")); } } private void List(IConsoleShell shell, IPlayerSession? player) { var resultText = "Random\n" + EntitySystem.Get().GetEventNames(); - shell.SendText(player, resultText); + shell.WriteLine(resultText); } private void Pause(IConsoleShell shell, IPlayerSession? player) @@ -104,12 +105,12 @@ namespace Content.Server.Commands.StationEvents if (!stationEventSystem.Enabled) { - shell.SendText(player, Loc.GetString("Station events are already paused")); + shell.WriteLine(Loc.GetString("Station events are already paused")); } else { stationEventSystem.Enabled = false; - shell.SendText(player, Loc.GetString("Station events paused")); + shell.WriteLine(Loc.GetString("Station events paused")); } } @@ -119,19 +120,19 @@ namespace Content.Server.Commands.StationEvents if (stationEventSystem.Enabled) { - shell.SendText(player, Loc.GetString("Station events are already running")); + shell.WriteLine(Loc.GetString("Station events are already running")); } else { stationEventSystem.Enabled = true; - shell.SendText(player, Loc.GetString("Station events resumed")); + shell.WriteLine(Loc.GetString("Station events resumed")); } } private void Stop(IConsoleShell shell, IPlayerSession? player) { var resultText = EntitySystem.Get().StopEvent(); - shell.SendText(player, resultText); + shell.WriteLine(resultText); } } } diff --git a/Content.Server/Construction/Completions/SnapToGrid.cs b/Content.Server/Construction/Completions/SnapToGrid.cs index 473b463776..dbb5c12636 100644 --- a/Content.Server/Construction/Completions/SnapToGrid.cs +++ b/Content.Server/Construction/Completions/SnapToGrid.cs @@ -7,6 +7,7 @@ using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Serialization; using Robust.Shared.Serialization; +using Robust.Shared.Maths; namespace Content.Server.Construction.Completions { @@ -14,10 +15,12 @@ namespace Content.Server.Construction.Completions public class SnapToGrid : IGraphAction { public SnapGridOffset Offset { get; private set; } = SnapGridOffset.Center; + public bool SouthRotation { get; private set; } = false; void IExposeData.ExposeData(ObjectSerializer serializer) { serializer.DataField(this, x => x.Offset, "offset", SnapGridOffset.Center); + serializer.DataField(this, x => x.SouthRotation, "southRotation", false); } public async Task PerformAction(IEntity entity, IEntity? user) @@ -25,6 +28,10 @@ namespace Content.Server.Construction.Completions if (entity.Deleted) return; entity.SnapToGrid(Offset); + if (SouthRotation) + { + entity.Transform.LocalRotation = Angle.South; + } } } } diff --git a/Content.Server/Explosions/ExplosionHelper.cs b/Content.Server/Explosions/ExplosionHelper.cs index 5479db7b3a..60962b67ec 100644 --- a/Content.Server/Explosions/ExplosionHelper.cs +++ b/Content.Server/Explosions/ExplosionHelper.cs @@ -1,33 +1,27 @@ using System; using System.Collections.Generic; using System.Linq; -using Content.Server.GameObjects.Components.Atmos; using Content.Server.GameObjects.Components.Explosion; -using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Maps; using Content.Shared.Physics; using Content.Shared.Utility; -using Microsoft.Extensions.Logging; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.Player; using Robust.Shared.Containers; -using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.EntitySystemMessages; +using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Random; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; -using Robust.Shared.Log; using Robust.Shared.Map; using Robust.Shared.Maths; -using Robust.Shared.Physics; using Robust.Shared.Random; -using Robust.Shared.Timing; namespace Content.Server.Explosions { @@ -151,7 +145,7 @@ namespace Content.Server.Explosions /// damage bracket [light, heavy, devastation], the distance from the epicenter and /// a probabilty bracket [, , 1.0]. /// - /// + /// private static void DamageTilesInRange(EntityCoordinates epicenter, GridId gridId, Box2 boundingBox, @@ -281,9 +275,31 @@ namespace Content.Server.Explosions } } - private static void Detonate(IEntity source, int devastationRange, int heavyImpactRange, int lightImpactRange, int flashRange) + public static void SpawnExplosion(this IEntity entity, int devastationRange = 0, int heavyImpactRange = 0, + int lightImpactRange = 0, int flashRange = 0) { - var mapId = source.Transform.MapID; + // If you want to directly set off the explosive + if (!entity.Deleted && entity.TryGetComponent(out ExplosiveComponent explosive) && !explosive.Exploding) + { + explosive.Explosion(); + } + else + { + while (entity.TryGetContainer(out var cont)) + { + entity = cont.Owner; + } + + var epicenter = entity.Transform.Coordinates; + + SpawnExplosion(epicenter, devastationRange, heavyImpactRange, lightImpactRange, flashRange); + } + } + + public static void SpawnExplosion(EntityCoordinates epicenter, int devastationRange = 0, + int heavyImpactRange = 0, int lightImpactRange = 0, int flashRange = 0) + { + var mapId = epicenter.GetMapId(IoCManager.Resolve()); if (mapId == MapId.Nullspace) { return; @@ -291,18 +307,14 @@ namespace Content.Server.Explosions var maxRange = MathHelper.Max(devastationRange, heavyImpactRange, lightImpactRange, 0); - while(source.TryGetContainer(out var cont)) - { - source = cont.Owner; - } - var epicenter = source.Transform.Coordinates; - var entityManager = IoCManager.Resolve(); var mapManager = IoCManager.Resolve(); var epicenterMapPos = epicenter.ToMapPos(entityManager); - var boundingBox = new Box2(epicenterMapPos - new Vector2(maxRange, maxRange), epicenterMapPos + new Vector2(maxRange, maxRange)); + var boundingBox = new Box2(epicenterMapPos - new Vector2(maxRange, maxRange), + epicenterMapPos + new Vector2(maxRange, maxRange)); + EntitySystem.Get().PlayAtCoords("/Audio/Effects/explosion.ogg", epicenter); DamageEntitiesInRange(epicenter, boundingBox, devastationRange, heavyImpactRange, maxRange, mapId); var mapGridsNear = mapManager.FindGridsIntersecting(mapId, boundingBox); @@ -315,18 +327,5 @@ namespace Content.Server.Explosions CameraShakeInRange(epicenter, maxRange); FlashInRange(epicenter, flashRange); } - - public static void SpawnExplosion(this IEntity entity, int devastationRange = 0, int heavyImpactRange = 0, int lightImpactRange = 0, int flashRange = 0) - { - // If you want to directly set off the explosive - if (!entity.Deleted && entity.TryGetComponent(out ExplosiveComponent explosive) && !explosive.Exploding) - { - explosive.Explosion(); - } - else - { - Detonate(entity, devastationRange, heavyImpactRange, lightImpactRange, flashRange); - } - } } } diff --git a/Content.Server/GameObjects/Components/ActionBlocking/HandcuffComponent.cs b/Content.Server/GameObjects/Components/ActionBlocking/HandcuffComponent.cs index 18f4892d11..9e05ab7cd1 100644 --- a/Content.Server/GameObjects/Components/ActionBlocking/HandcuffComponent.cs +++ b/Content.Server/GameObjects/Components/ActionBlocking/HandcuffComponent.cs @@ -148,41 +148,41 @@ namespace Content.Server.GameObjects.Components.ActionBlocking return new HandcuffedComponentState(Broken ? BrokenState : string.Empty); } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (eventArgs.Target == null || !ActionBlockerSystem.CanUse(eventArgs.User) || !eventArgs.Target.TryGetComponent(out var cuffed)) { - return; + return false; } if (eventArgs.Target == eventArgs.User) { eventArgs.User.PopupMessage(Loc.GetString("You can't cuff yourself!")); - return; + return true; } if (Broken) { eventArgs.User.PopupMessage(Loc.GetString("The cuffs are broken!")); - return; + return true; } if (!eventArgs.Target.TryGetComponent(out var hands)) { eventArgs.User.PopupMessage(Loc.GetString("{0:theName} has no hands!", eventArgs.Target)); - return; + return true; } if (cuffed.CuffedHandCount == hands.Count) { eventArgs.User.PopupMessage(Loc.GetString("{0:theName} has no free hands to handcuff!", eventArgs.Target)); - return; + return true; } if (!eventArgs.InRangeUnobstructed(_interactRange, ignoreInsideBlocker: true)) { eventArgs.User.PopupMessage(Loc.GetString("You are too far away to use the cuffs!")); - return; + return true; } eventArgs.User.PopupMessage(Loc.GetString("You start cuffing {0:theName}.", eventArgs.Target)); @@ -190,6 +190,7 @@ namespace Content.Server.GameObjects.Components.ActionBlocking _audioSystem.PlayFromEntity(StartCuffSound, Owner); TryUpdateCuff(eventArgs.User, eventArgs.Target, cuffed); + return true; } /// diff --git a/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs b/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs index a63a27d274..586a332bdb 100644 --- a/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/GasAnalyzerComponent.cs @@ -253,18 +253,20 @@ namespace Content.Server.GameObjects.Components.Atmos } } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (!eventArgs.CanReach) { eventArgs.User.PopupMessage(Loc.GetString("You can't reach there!")); - return; + return true; } if (eventArgs.User.TryGetComponent(out IActorComponent? actor)) { OpenInterface(actor.playerSession, eventArgs.ClickLocation); } + + return true; } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs index cdc701d36d..a5fbc16b0c 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs @@ -83,13 +83,13 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping { if (!Owner.TryGetComponent(out var container)) { - Logger.Error($"{typeof(GasCanisterPortComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(GasCanisterPortComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); return; } _gasPort = container.Nodes.OfType().FirstOrDefault(); if (_gasPort == null) { - Logger.Error($"{typeof(GasCanisterPortComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(GasCanisterPortComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/GasFilterComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/GasFilterComponent.cs index 8a6cd18f1d..461647fd43 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/GasFilterComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/GasFilterComponent.cs @@ -171,7 +171,7 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Filters if (_inletPipe == null || _filterOutletPipe == null || _outletPipe == null) { - Logger.Error($"{typeof(GasFilterComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(GasFilterComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/GasGeneratorComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/GasGeneratorComponent.cs new file mode 100644 index 0000000000..5a37d7a669 --- /dev/null +++ b/Content.Server/GameObjects/Components/Atmos/Piping/GasGeneratorComponent.cs @@ -0,0 +1,105 @@ +#nullable enable +using Content.Server.GameObjects.Components.NodeContainer; +using Content.Server.GameObjects.Components.NodeContainer.Nodes; +using Content.Shared.Atmos; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Log; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; +using System.Linq; + +namespace Content.Server.GameObjects.Components.Atmos.Piping +{ + /// + /// Generates gas in the attached pipe. + /// + [RegisterComponent] + public class GasGeneratorComponent : Component + { + public override string Name => "GasGenerator"; + + /// + /// If the generator is producing gas. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool GeneratorEnabled { get; set; } + + /// + /// What gas is being generated. + /// + [ViewVariables(VVAccess.ReadWrite)] + public Gas GeneratedGas { get; set; } + + /// + /// Molar rate of gas generation. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float GasGenerationRate { get; set; } + + /// + /// The pipe pressure above which the generator stops producing gas. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float GeneratorPressureCap { get; set; } + + /// + /// The pipe to which generated gas is added. + /// + [ViewVariables] + private PipeNode? Pipe { get; set; } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(this, x => x.GeneratorEnabled, "generatorEnabled", true); + serializer.DataField(this, x => x.GeneratedGas, "generatedGas", Gas.Oxygen); + serializer.DataField(this, x => x.GasGenerationRate, "gasGenerationRate", 10); + serializer.DataField(this, x => x.GeneratorPressureCap, "generatorPressureCap", 10); + } + + public override void Initialize() + { + base.Initialize(); + Owner.EnsureComponentWarn(); + SetPipes(); + } + + public override void HandleMessage(ComponentMessage message, IComponent? component) + { + base.HandleMessage(message, component); + switch (message) + { + case PipeNetUpdateMessage: + Update(); + break; + } + } + + private void Update() + { + if (!GeneratorEnabled) + return; + + if (Pipe == null || Pipe.Air.Pressure > GeneratorPressureCap) + return; + + Pipe.Air.AdjustMoles(GeneratedGas, GasGenerationRate); + } + + private void SetPipes() + { + if (!Owner.TryGetComponent(out var container)) + { + Logger.Error($"{nameof(GasGeneratorComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); + return; + } + Pipe = container.Nodes.OfType().FirstOrDefault(); + if (Pipe == null) + { + Logger.Error($"{nameof(GasGeneratorComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + return; + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs index a4c3d6a8e9..2cf6ed46ff 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs @@ -4,6 +4,7 @@ using Content.Server.Atmos; using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Shared.GameObjects.Components.Atmos; +using Content.Shared.Interfaces.GameObjects.Components; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; @@ -16,7 +17,7 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps /// /// Transfer gas from one to another. /// - public abstract class BasePumpComponent : Component + public abstract class BasePumpComponent : Component, IActivate { /// /// If the pump is currently pumping. @@ -100,6 +101,11 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps _appearance?.SetData(PumpVisuals.VisualState, new PumpVisualState(_initialInletDirection, _initialOutletDirection, PumpEnabled)); } + public void Activate(ActivateEventArgs eventArgs) + { + PumpEnabled = !PumpEnabled; + } + private void SetPipes() { _inletPipe = null; @@ -107,7 +113,7 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps if (!Owner.TryGetComponent(out var container)) { - Logger.Error($"{typeof(BasePumpComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(BasePumpComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); return; } var pipeNodes = container.Nodes.OfType(); @@ -115,7 +121,7 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps _outletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _initialOutletDirection).FirstOrDefault(); if (_inletPipe == null || _outletPipe == null) { - Logger.Error($"{typeof(BasePumpComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(BasePumpComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/PressurePumpComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/PressurePumpComponent.cs index 33c1ceaa2d..4135ef4389 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/PressurePumpComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/PressurePumpComponent.cs @@ -1,5 +1,7 @@ -using System; +#nullable enable +using System; using Content.Server.Atmos; +using Content.Shared.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -8,6 +10,7 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps { [RegisterComponent] [ComponentReference(typeof(BasePumpComponent))] + [ComponentReference(typeof(IActivate))] public class PressurePumpComponent : BasePumpComponent { public override string Name => "PressurePump"; diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/VolumePumpComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/VolumePumpComponent.cs index 614a7487af..51824e1738 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/VolumePumpComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/VolumePumpComponent.cs @@ -1,5 +1,7 @@ -using System; +#nullable enable +using System; using Content.Server.Atmos; +using Content.Shared.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -8,6 +10,7 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps { [RegisterComponent] [ComponentReference(typeof(BasePumpComponent))] + [ComponentReference(typeof(IActivate))] public class VolumePumpComponent : BasePumpComponent { [ViewVariables(VVAccess.ReadWrite)] diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs index fe30881d58..a67e354a4d 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs @@ -80,13 +80,13 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Scrubbers { if (!Owner.TryGetComponent(out var container)) { - Logger.Error($"{typeof(BaseSiphonComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(BaseSiphonComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); return; } _scrubberOutlet = container.Nodes.OfType().FirstOrDefault(); if (_scrubberOutlet == null) { - Logger.Error($"{typeof(BaseSiphonComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(BaseSiphonComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/PressureSiphon.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/PressureSiphon.cs index a48537d6f5..dd66336038 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/PressureSiphon.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/PressureSiphon.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using Content.Server.Atmos; using Content.Shared.Atmos; using Robust.Shared.GameObjects; diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs index db4508959b..c9b9e48f86 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs @@ -80,13 +80,13 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Vents { if (!Owner.TryGetComponent(out var container)) { - Logger.Error($"{typeof(BaseVentComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(BaseVentComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); return; } _ventInlet = container.Nodes.OfType().FirstOrDefault(); if (_ventInlet == null) { - Logger.Error($"{typeof(BaseVentComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + Logger.Error($"{nameof(BaseVentComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/PressureVentComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/PressureVentComponent.cs index 7f853a7761..e84c67ec9f 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/PressureVentComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/PressureVentComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.Atmos; +#nullable enable +using Content.Server.Atmos; using Content.Shared.Atmos; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; diff --git a/Content.Server/GameObjects/Components/Body/Behavior/LungBehavior.cs b/Content.Server/GameObjects/Components/Body/Behavior/LungBehavior.cs index 4c60bdecfb..cf402231ec 100644 --- a/Content.Server/GameObjects/Components/Body/Behavior/LungBehavior.cs +++ b/Content.Server/GameObjects/Components/Body/Behavior/LungBehavior.cs @@ -8,6 +8,7 @@ using Content.Server.GameObjects.Components.Body.Respiratory; using Content.Server.Utility; using Content.Shared.Atmos; using Content.Shared.GameObjects.Components.Body.Behavior; +using Content.Shared.GameObjects.Components.Mobs.State; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Localization; @@ -99,6 +100,11 @@ namespace Content.Server.GameObjects.Components.Body.Behavior public override void Update(float frameTime) { + if (Body != null && Body.Owner.TryGetComponent(out IMobStateComponent? mobState) && mobState.IsCritical()) + { + return; + } + if (Status == LungStatus.None) { Status = LungStatus.Inhaling; diff --git a/Content.Server/GameObjects/Components/Body/BodyComponent.cs b/Content.Server/GameObjects/Components/Body/BodyComponent.cs index 000832af1d..8f9eea9aac 100644 --- a/Content.Server/GameObjects/Components/Body/BodyComponent.cs +++ b/Content.Server/GameObjects/Components/Body/BodyComponent.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using Content.Server.Commands.Observer; using Content.Shared.Audio; @@ -8,11 +8,12 @@ using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Mobs.State; using Content.Shared.GameObjects.Components.Movement; using Content.Shared.Utility; +using Robust.Server.Console; using Robust.Server.GameObjects.Components.Container; using Robust.Server.GameObjects.EntitySystems; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; using Robust.Shared.Audio; +using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.IoC; @@ -89,9 +90,9 @@ namespace Content.Server.GameObjects.Components.Body if (Owner.TryGetComponent(out IMobStateComponent? mobState) && mobState.IsDead()) { - var shell = IoCManager.Resolve(); + var host = IoCManager.Resolve(); - new Ghost().Execute(shell, (IPlayerSession) session, Array.Empty()); + new Ghost().Execute(new ConsoleShell(host, session), string.Empty, Array.Empty()); } } diff --git a/Content.Server/GameObjects/Components/Body/MechanismComponent.cs b/Content.Server/GameObjects/Components/Body/MechanismComponent.cs index 1ff3f77f52..8dd4658573 100644 --- a/Content.Server/GameObjects/Components/Body/MechanismComponent.cs +++ b/Content.Server/GameObjects/Components/Body/MechanismComponent.cs @@ -36,11 +36,11 @@ namespace Content.Server.GameObjects.Components.Body } } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (eventArgs.Target == null) { - return; + return false; } CloseAllSurgeryUIs(); @@ -61,6 +61,8 @@ namespace Content.Server.GameObjects.Components.Body eventArgs.Target.PopupMessage(eventArgs.User, Loc.GetString("You can't fit it in!")); } } + + return true; } private void SendBodyPartListToUser(AfterInteractEventArgs eventArgs, IBody body) diff --git a/Content.Server/GameObjects/Components/Body/Part/BodyPartComponent.cs b/Content.Server/GameObjects/Components/Body/Part/BodyPartComponent.cs index c6f995e4cd..dfa0ee67fe 100644 --- a/Content.Server/GameObjects/Components/Body/Part/BodyPartComponent.cs +++ b/Content.Server/GameObjects/Components/Body/Part/BodyPartComponent.cs @@ -99,12 +99,12 @@ namespace Content.Server.GameObjects.Components.Body.Part } } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { // TODO BODY if (eventArgs.Target == null) { - return; + return false; } CloseAllSurgeryUIs(); @@ -116,6 +116,8 @@ namespace Content.Server.GameObjects.Components.Body.Part { SendSlots(eventArgs, body); } + + return true; } private void SendSlots(AfterInteractEventArgs eventArgs, IBody body) diff --git a/Content.Server/GameObjects/Components/Body/Respiratory/InternalsComponent.cs b/Content.Server/GameObjects/Components/Body/Respiratory/InternalsComponent.cs index 6c3380da4e..63594ffcee 100644 --- a/Content.Server/GameObjects/Components/Body/Respiratory/InternalsComponent.cs +++ b/Content.Server/GameObjects/Components/Body/Respiratory/InternalsComponent.cs @@ -59,5 +59,15 @@ namespace Content.Server.GameObjects.Components.Body.Respiratory return true; } + public bool AreInternalsWorking() + { + return BreathToolEntity != null && + GasTankEntity != null && + BreathToolEntity.TryGetComponent(out BreathToolComponent? breathTool) && + breathTool.IsFunctional && + GasTankEntity.TryGetComponent(out GasTankComponent? gasTank) && + gasTank.Air != null; + } + } } diff --git a/Content.Server/GameObjects/Components/Body/Surgery/SurgeryToolComponent.cs b/Content.Server/GameObjects/Components/Body/Surgery/SurgeryToolComponent.cs index ac1aaa3ad7..717bbccd99 100644 --- a/Content.Server/GameObjects/Components/Body/Surgery/SurgeryToolComponent.cs +++ b/Content.Server/GameObjects/Components/Body/Surgery/SurgeryToolComponent.cs @@ -50,16 +50,16 @@ namespace Content.Server.GameObjects.Components.Body.Surgery public IEntity? PerformerCache { get; private set; } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (eventArgs.Target == null) { - return; + return false; } if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) { - return; + return false; } CloseAllSurgeryUIs(); @@ -101,20 +101,22 @@ namespace Content.Server.GameObjects.Components.Body.Surgery if (!part.SurgeryCheck(_surgeryType)) { NotUsefulPopup(); - return; + return true; } // ...do the surgery. if (part.AttemptSurgery(_surgeryType, part, this, eventArgs.User)) { - return; + return true; } // Log error if the surgery fails somehow. Logger.Debug($"Error when trying to perform surgery on ${nameof(IBodyPart)} {eventArgs.User.Name}"); throw new InvalidOperationException(); } + + return true; } public float BaseOperationTime { get => _baseOperateTime; set => _baseOperateTime = value; } diff --git a/Content.Server/GameObjects/Components/Botany/PlantHolderComponent.cs b/Content.Server/GameObjects/Components/Botany/PlantHolderComponent.cs index 7a7c1afbe7..a77e48bf1b 100644 --- a/Content.Server/GameObjects/Components/Botany/PlantHolderComponent.cs +++ b/Content.Server/GameObjects/Components/Botany/PlantHolderComponent.cs @@ -12,6 +12,7 @@ using Content.Server.Utility; using Content.Shared.Audio; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Botany; +using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.Interfaces; @@ -639,6 +640,13 @@ namespace Content.Server.GameObjects.Components.Botany Seed = Seed.Diverge(modified); } + private void ForceUpdateByExternalCause() + { + SkipAging++; // We're forcing an update cycle, so one age hasn't passed. + ForceUpdate = true; + Update(); + } + async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) { var user = eventArgs.User; @@ -695,29 +703,48 @@ namespace Content.Server.GameObjects.Components.Botany return true; } - if (usingItem.TryGetComponent(out SolutionContainerComponent? solution) && solution.CanRemoveSolutions) + if (usingItem.HasComponent()) { - var amount = 5f; + if (Seed != null) + { + user.PopupMessageCursor(Loc.GetString("You remove the plant from the {0}.", Owner.Name)); + user.PopupMessageOtherClients(Loc.GetString("{0} removes the plant.", user.Name)); + RemovePlant(); + } + else + { + user.PopupMessageCursor(Loc.GetString("There is no plant to remove.")); + } + + return true; + } + + if (usingItem.TryGetComponent(out ISolutionInteractionsComponent? solution) && solution.CanDrain) + { + var amount = ReagentUnit.New(5); var sprayed = false; if (usingItem.TryGetComponent(out SprayComponent? spray)) { sprayed = true; - amount = 1f; + amount = ReagentUnit.New(1); EntitySystem.Get().PlayFromEntity(spray.SpraySound, usingItem, AudioHelpers.WithVariation(0.125f)); } - var chemAmount = ReagentUnit.New(amount); + var split = solution.Drain(amount); + if (split.TotalVolume == 0) + { + user.PopupMessageCursor(Loc.GetString("{0:TheName} is empty!", usingItem)); + return true; + } - var split = solution.Solution.SplitSolution(chemAmount <= solution.Solution.TotalVolume ? chemAmount : solution.Solution.TotalVolume); - - user.PopupMessageCursor(Loc.GetString(sprayed ? $"You spray {Owner.Name} with {usingItem.Name}." : $"You transfer {split.TotalVolume.ToString()}u to {Owner.Name}")); + user.PopupMessageCursor(Loc.GetString( + sprayed ? "You spray {0:TheName}" : "You transfer {1}u to {0:TheName}", + Owner, split.TotalVolume)); _solutionContainer?.TryAddSolution(split); - SkipAging++; // We're forcing an update cycle, so one age hasn't passed. - ForceUpdate = true; - Update(); + ForceUpdateByExternalCause(); return true; } @@ -752,9 +779,7 @@ namespace Content.Server.GameObjects.Components.Botany // Just in case. CheckLevelSanity(); - SkipAging++; // We're forcing an update cycle, so one age hasn't passed. - ForceUpdate = true; - Update(); + ForceUpdateByExternalCause(); return true; } @@ -764,6 +789,24 @@ namespace Content.Server.GameObjects.Components.Botany return DoHarvest(user); } + if (usingItem.HasComponent()) + { + user.PopupMessageCursor(Loc.GetString("You compost {1:theName} into {0:theName}.", Owner, usingItem)); + user.PopupMessageOtherClients(Loc.GetString("{0:TheName} composts {1:theName} into {2:theName}.", user, usingItem, Owner)); + + if (usingItem.TryGetComponent(out SolutionContainerComponent? solution2)) + { + // This deliberately discards overfill. + _solutionContainer?.TryAddSolution(solution2.SplitSolution(solution2.Solution.TotalVolume)); + + ForceUpdateByExternalCause(); + } + + usingItem.Delete(); + + return true; + } + return false; } diff --git a/Content.Server/GameObjects/Components/Botany/ShovelComponent.cs b/Content.Server/GameObjects/Components/Botany/ShovelComponent.cs new file mode 100644 index 0000000000..be6afbb8a1 --- /dev/null +++ b/Content.Server/GameObjects/Components/Botany/ShovelComponent.cs @@ -0,0 +1,11 @@ +#nullable enable +using Robust.Shared.GameObjects; + +namespace Content.Server.GameObjects.Components.Botany +{ + [RegisterComponent] + public class ShovelComponent : Component + { + public override string Name => "Shovel"; + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/FoamSolutionAreaEffectComponent.cs b/Content.Server/GameObjects/Components/Chemistry/FoamSolutionAreaEffectComponent.cs new file mode 100644 index 0000000000..6b9e6dd3b5 --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/FoamSolutionAreaEffectComponent.cs @@ -0,0 +1,90 @@ +#nullable enable +using Content.Server.GameObjects.Components.Body.Circulatory; +using Content.Server.GameObjects.Components.GUI; +using Content.Server.GameObjects.Components.Items.Storage; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Chemistry; +using Content.Shared.GameObjects.Components.Inventory; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.Timers; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.Chemistry +{ + [RegisterComponent] + [ComponentReference(typeof(SolutionAreaEffectComponent))] + public class FoamSolutionAreaEffectComponent : SolutionAreaEffectComponent + { + public override string Name => "FoamSolutionAreaEffect"; + + private string? _foamedMetalPrototype; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _foamedMetalPrototype, "foamedMetalPrototype", null); + } + + protected override void UpdateVisuals() + { + if (Owner.TryGetComponent(out AppearanceComponent? appearance) && + SolutionContainerComponent != null) + { + appearance.SetData(FoamVisuals.Color, SolutionContainerComponent.Color.WithAlpha(0.80f)); + } + } + + protected override void ReactWithEntity(IEntity entity, double solutionFraction) + { + if (SolutionContainerComponent == null) + return; + + if (!entity.TryGetComponent(out BloodstreamComponent? bloodstream)) + return; + + // TODO: Add a permeability property to clothing + // For now it just adds to protection for each clothing equipped + var protection = 0f; + if (entity.TryGetComponent(out InventoryComponent? inventory)) + { + foreach (var slot in inventory.Slots) + { + if (slot == EquipmentSlotDefines.Slots.BACKPACK || + slot == EquipmentSlotDefines.Slots.POCKET1 || + slot == EquipmentSlotDefines.Slots.POCKET2 || + slot == EquipmentSlotDefines.Slots.IDCARD) + continue; + + if (inventory.TryGetSlotItem(slot, out ItemComponent _)) + protection += 0.025f; + } + } + + var cloneSolution = SolutionContainerComponent.Solution.Clone(); + var transferAmount = ReagentUnit.Min(cloneSolution.TotalVolume * solutionFraction * (1 - protection), bloodstream.EmptyVolume); + var transferSolution = cloneSolution.SplitSolution(transferAmount); + + bloodstream.TryTransferSolution(transferSolution); + } + + protected override void OnKill() + { + if (Owner.Deleted) + return; + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(FoamVisuals.State, true); + } + Owner.SpawnTimer(600, () => + { + if (!string.IsNullOrEmpty(_foamedMetalPrototype)) + { + Owner.EntityManager.SpawnEntity(_foamedMetalPrototype, Owner.Transform.Coordinates); + } + Owner.Delete(); + }); + } + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/HyposprayComponent.cs b/Content.Server/GameObjects/Components/Chemistry/HyposprayComponent.cs new file mode 100644 index 0000000000..7783b38f72 --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/HyposprayComponent.cs @@ -0,0 +1,143 @@ +using System.Threading.Tasks; +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.GameObjects.Components.Mobs.State; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Chemistry; +using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.ComponentDependencies; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +#nullable enable + +namespace Content.Server.GameObjects.Components.Chemistry +{ + [RegisterComponent] + public sealed class HyposprayComponent : SharedHyposprayComponent, IAttack, ISolutionChange, IAfterInteract + { + [ViewVariables(VVAccess.ReadWrite)] public float ClumsyFailChance { get; set; } + [ViewVariables(VVAccess.ReadWrite)] public ReagentUnit TransferAmount { get; set; } + + [ComponentDependency] private readonly SolutionContainerComponent? _solution = default!; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(this, x => x.ClumsyFailChance, "ClumsyFailChance", 0.5f); + serializer.DataField(this, x => x.TransferAmount, "TransferAmount", ReagentUnit.New(5)); + } + + public override void Initialize() + { + base.Initialize(); + + Dirty(); + } + + bool IAttack.ClickAttack(AttackEventArgs eventArgs) + { + var target = eventArgs.TargetEntity; + var user = eventArgs.User; + + return TryDoInject(target, user); + } + + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + { + if (!eventArgs.CanReach) + return false; + + return TryDoInject(eventArgs.Target, eventArgs.User); + } + + private bool TryDoInject(IEntity? target, IEntity user) + { + if (target == null || !EligibleEntity(target)) + return false; + + var msgFormat = "You inject {0:TheName}."; + + if (target == user) + { + msgFormat = "You inject yourself."; + } + else if (EligibleEntity(user) && ClumsyComponent.TryRollClumsy(user, ClumsyFailChance)) + { + msgFormat = "Oops! You injected yourself!"; + target = user; + } + + if (_solution == null || _solution.CurrentVolume == 0) + { + user.PopupMessageCursor(Loc.GetString("It's empty!")); + return true; + } + + user.PopupMessage(Loc.GetString(msgFormat, target)); + if (target != user) + { + target.PopupMessage(Loc.GetString("You feel a tiny prick!")); + var meleeSys = EntitySystem.Get(); + var angle = new Angle(target.Transform.WorldPosition - user.Transform.WorldPosition); + meleeSys.SendLunge(angle, user); + } + + EntitySystem.Get().PlayFromEntity("/Audio/Items/hypospray.ogg", user); + + var targetSolution = target.GetComponent(); + + // Get transfer amount. May be smaller than _transferAmount if not enough room + var realTransferAmount = ReagentUnit.Min(TransferAmount, targetSolution.EmptyVolume); + + if (realTransferAmount <= 0) + { + user.PopupMessage(user, Loc.GetString("{0:TheName} is already full!", targetSolution.Owner)); + return true; + } + + // Move units from attackSolution to targetSolution + var removedSolution = _solution.SplitSolution(realTransferAmount); + + if (!targetSolution.CanAddSolution(removedSolution)) + { + return true; + } + + removedSolution.DoEntityReaction(target, ReactionMethod.Injection); + + targetSolution.TryAddSolution(removedSolution); + + static bool EligibleEntity(IEntity entity) + { + // TODO: Does checking for BodyComponent make sense as a "can be hypospray'd" tag? + // In SS13 the hypospray ONLY works on mobs, NOT beakers or anything else. + return entity.HasComponent() && entity.HasComponent(); + } + + return true; + } + + void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) + { + Dirty(); + } + + public override ComponentState GetComponentState() + { + if (_solution == null) + return new HyposprayComponentState(ReagentUnit.Zero, ReagentUnit.Zero); + + return new HyposprayComponentState(_solution.CurrentVolume, _solution.MaxVolume); + } + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs b/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs index 76fc2f8b29..fa23f8c0de 100644 --- a/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/InjectorComponent.cs @@ -10,9 +10,7 @@ using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Utility; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Localization; -using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -26,27 +24,24 @@ namespace Content.Server.GameObjects.Components.Chemistry [RegisterComponent] public class InjectorComponent : SharedInjectorComponent, IAfterInteract, IUse, ISolutionChange { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - /// /// Whether or not the injector is able to draw from containers or if it's a single use /// device that can only inject. /// - [ViewVariables] - private bool _injectOnly; + [ViewVariables] private bool _injectOnly; /// /// Amount to inject or draw on each usage. If the injector is inject only, it will /// attempt to inject it's entire contents upon use. /// - [ViewVariables] - private ReagentUnit _transferAmount; + [ViewVariables] private ReagentUnit _transferAmount; /// /// Initial storage volume of the injector /// - [ViewVariables] - private ReagentUnit _initialMaxVolume; + [ViewVariables] private ReagentUnit _initialMaxVolume; + + private InjectorToggleMode _toggleState; /// /// The state of the injector. Determines it's attack behavior. Containers must have the @@ -54,7 +49,15 @@ namespace Content.Server.GameObjects.Components.Chemistry /// only ever be set to Inject /// [ViewVariables(VVAccess.ReadWrite)] - private InjectorToggleMode _toggleState; + public InjectorToggleMode ToggleState + { + get => _toggleState; + set + { + _toggleState = value; + Dirty(); + } + } public override void ExposeData(ObjectSerializer serializer) { @@ -62,17 +65,14 @@ namespace Content.Server.GameObjects.Components.Chemistry serializer.DataField(ref _injectOnly, "injectOnly", false); serializer.DataField(ref _initialMaxVolume, "initialMaxVolume", ReagentUnit.New(15)); serializer.DataField(ref _transferAmount, "transferAmount", ReagentUnit.New(5)); + serializer.DataField(ref _toggleState, "toggleState", + _injectOnly ? InjectorToggleMode.Inject : InjectorToggleMode.Draw); } + protected override void Startup() { base.Startup(); - var solution = Owner.EnsureComponent(); - solution.Capabilities = SolutionContainerCaps.AddTo | SolutionContainerCaps.RemoveFrom; - - // Set _toggleState based on prototype - _toggleState = _injectOnly ? InjectorToggleMode.Inject : InjectorToggleMode.Draw; - Dirty(); } @@ -87,14 +87,14 @@ namespace Content.Server.GameObjects.Components.Chemistry } string msg; - switch (_toggleState) + switch (ToggleState) { case InjectorToggleMode.Inject: - _toggleState = InjectorToggleMode.Draw; + ToggleState = InjectorToggleMode.Draw; msg = "Now drawing"; break; case InjectorToggleMode.Draw: - _toggleState = InjectorToggleMode.Inject; + ToggleState = InjectorToggleMode.Inject; msg = "Now injecting"; break; default: @@ -102,66 +102,61 @@ namespace Content.Server.GameObjects.Components.Chemistry } Owner.PopupMessage(user, Loc.GetString(msg)); - - Dirty(); } /// /// Called when clicking on entities while holding in active hand /// /// - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { - if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) return; + if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) + return false; //Make sure we have the attacking entity - if (eventArgs.Target == null || !Owner.TryGetComponent(out SolutionContainerComponent? solution)) + if (eventArgs.Target == null || !Owner.HasComponent()) { - return; + return false; } var targetEntity = eventArgs.Target; // Handle injecting/drawing for solutions - if (targetEntity.TryGetComponent(out var targetSolution)) + if (targetEntity.TryGetComponent(out var targetSolution)) { - if (_toggleState == InjectorToggleMode.Inject) + if (ToggleState == InjectorToggleMode.Inject) { - if (solution.CanRemoveSolutions && targetSolution.CanAddSolutions) + if (targetSolution.CanInject) { TryInject(targetSolution, eventArgs.User); } else { - eventArgs.User.PopupMessage(eventArgs.User, Loc.GetString("You aren't able to transfer to {0:theName}!", targetSolution.Owner)); + eventArgs.User.PopupMessage(eventArgs.User, + Loc.GetString("You aren't able to transfer to {0:theName}!", targetSolution.Owner)); } } - else if (_toggleState == InjectorToggleMode.Draw) + else if (ToggleState == InjectorToggleMode.Draw) { - if (targetSolution.CanRemoveSolutions && solution.CanAddSolutions) + if (targetSolution.CanDraw) { TryDraw(targetSolution, eventArgs.User); } else { - eventArgs.User.PopupMessage(eventArgs.User, Loc.GetString("You aren't able to draw from {0:theName}!", targetSolution.Owner)); + eventArgs.User.PopupMessage(eventArgs.User, + Loc.GetString("You aren't able to draw from {0:theName}!", targetSolution.Owner)); } } } - else // Handle injecting into bloodstream + // Handle injecting into bloodstream + else if (targetEntity.TryGetComponent(out BloodstreamComponent? bloodstream) && + ToggleState == InjectorToggleMode.Inject) { - if (targetEntity.TryGetComponent(out BloodstreamComponent? bloodstream) && _toggleState == InjectorToggleMode.Inject) - { - if (solution.CanRemoveSolutions) - { - TryInjectIntoBloodstream(bloodstream, eventArgs.User); - } - else - { - eventArgs.User.PopupMessage(eventArgs.User, Loc.GetString("You aren't able to inject {0:theName}!", targetEntity)); - } - } + TryInjectIntoBloodstream(bloodstream, eventArgs.User); } + + return true; } /// @@ -187,7 +182,8 @@ namespace Content.Server.GameObjects.Components.Chemistry if (realTransferAmount <= 0) { - Owner.PopupMessage(user, Loc.GetString("You aren't able to inject {0:theName}!", targetBloodstream.Owner)); + Owner.PopupMessage(user, + Loc.GetString("You aren't able to inject {0:theName}!", targetBloodstream.Owner)); return; } @@ -201,25 +197,20 @@ namespace Content.Server.GameObjects.Components.Chemistry // TODO: Account for partial transfer. - foreach (var (reagentId, quantity) in removedSolution.Contents) - { - if(!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent)) continue; - removedSolution.RemoveReagent(reagentId, reagent.ReactionEntity(solution.Owner, ReactionMethod.Injection, quantity)); - } + removedSolution.DoEntityReaction(solution.Owner, ReactionMethod.Injection); solution.TryAddSolution(removedSolution); - foreach (var (reagentId, quantity) in removedSolution.Contents) - { - if(!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent)) continue; - reagent.ReactionEntity(targetBloodstream.Owner, ReactionMethod.Injection, quantity); - } + removedSolution.DoEntityReaction(targetBloodstream.Owner, ReactionMethod.Injection); - Owner.PopupMessage(user, Loc.GetString("You inject {0}u into {1:theName}!", removedSolution.TotalVolume, targetBloodstream.Owner)); + Owner.PopupMessage(user, + Loc.GetString("You inject {0}u into {1:theName}!", removedSolution.TotalVolume, + targetBloodstream.Owner)); Dirty(); + AfterInject(); } - private void TryInject(SolutionContainerComponent targetSolution, IEntity user) + private void TryInject(ISolutionInteractionsComponent targetSolution, IEntity user) { if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.CurrentVolume == 0) { @@ -227,7 +218,7 @@ namespace Content.Server.GameObjects.Components.Chemistry } // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = ReagentUnit.Min(_transferAmount, targetSolution.EmptyVolume); + var realTransferAmount = ReagentUnit.Min(_transferAmount, targetSolution.InjectSpaceAvailable); if (realTransferAmount <= 0) { @@ -238,24 +229,26 @@ namespace Content.Server.GameObjects.Components.Chemistry // Move units from attackSolution to targetSolution var removedSolution = solution.SplitSolution(realTransferAmount); - if (!targetSolution.CanAddSolution(removedSolution)) - { - return; - } + removedSolution.DoEntityReaction(targetSolution.Owner, ReactionMethod.Injection); - foreach (var (reagentId, quantity) in removedSolution.Contents) - { - if(!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent)) continue; - removedSolution.RemoveReagent(reagentId, reagent.ReactionEntity(targetSolution.Owner, ReactionMethod.Injection, quantity)); - } + targetSolution.Inject(removedSolution); - targetSolution.TryAddSolution(removedSolution); - - Owner.PopupMessage(user, Loc.GetString("You transfter {0}u to {1:theName}", removedSolution.TotalVolume, targetSolution.Owner)); + Owner.PopupMessage(user, + Loc.GetString("You transfer {0}u to {1:theName}", removedSolution.TotalVolume, targetSolution.Owner)); Dirty(); + AfterInject(); } - private void TryDraw(SolutionContainerComponent targetSolution, IEntity user) + private void AfterInject() + { + // Automatically set syringe to draw after completely draining it. + if (Owner.GetComponent().CurrentVolume == 0) + { + ToggleState = InjectorToggleMode.Draw; + } + } + + private void TryDraw(ISolutionInteractionsComponent targetSolution, IEntity user) { if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.EmptyVolume == 0) { @@ -263,7 +256,7 @@ namespace Content.Server.GameObjects.Components.Chemistry } // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = ReagentUnit.Min(_transferAmount, targetSolution.CurrentVolume); + var realTransferAmount = ReagentUnit.Min(_transferAmount, targetSolution.DrawAvailable); if (realTransferAmount <= 0) { @@ -272,18 +265,29 @@ namespace Content.Server.GameObjects.Components.Chemistry } // Move units from attackSolution to targetSolution - var removedSolution = targetSolution.SplitSolution(realTransferAmount); + var removedSolution = targetSolution.Draw(realTransferAmount); if (!solution.TryAddSolution(removedSolution)) { return; } - Owner.PopupMessage(user, Loc.GetString("Drew {0}u from {1:theName}", removedSolution.TotalVolume, targetSolution.Owner)); + Owner.PopupMessage(user, + Loc.GetString("Drew {0}u from {1:theName}", removedSolution.TotalVolume, targetSolution.Owner)); Dirty(); + AfterDraw(); } - public void SolutionChanged(SolutionChangeEventArgs eventArgs) + private void AfterDraw() + { + // Automatically set syringe to inject after completely filling it. + if (Owner.GetComponent().EmptyVolume == 0) + { + ToggleState = InjectorToggleMode.Inject; + } + } + + void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) { Dirty(); } @@ -295,7 +299,7 @@ namespace Content.Server.GameObjects.Components.Chemistry var currentVolume = solution?.CurrentVolume ?? ReagentUnit.Zero; var maxVolume = solution?.MaxVolume ?? ReagentUnit.Zero; - return new InjectorComponentState(currentVolume, maxVolume, _toggleState); + return new InjectorComponentState(currentVolume, maxVolume, ToggleState); } } } diff --git a/Content.Server/GameObjects/Components/Chemistry/PillComponent.cs b/Content.Server/GameObjects/Components/Chemistry/PillComponent.cs index d899c00abb..a5f2551dae 100644 --- a/Content.Server/GameObjects/Components/Chemistry/PillComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/PillComponent.cs @@ -59,14 +59,15 @@ namespace Content.Server.GameObjects.Components.Chemistry } // Feeding someone else - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (eventArgs.Target == null) { - return; + return false; } TryUseFood(eventArgs.User, eventArgs.Target); + return true; } public override bool TryUseFood(IEntity user, IEntity target, UtensilComponent utensilUsed = null) @@ -103,11 +104,7 @@ namespace Content.Server.GameObjects.Components.Chemistry // TODO: Account for partial transfer. - foreach (var (reagentId, quantity) in split.Contents) - { - if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent)) continue; - split.RemoveReagent(reagentId, reagent.ReactionEntity(trueTarget, ReactionMethod.Ingestion, quantity)); - } + split.DoEntityReaction(trueTarget, ReactionMethod.Ingestion); firstStomach.TryTransferSolution(split); diff --git a/Content.Server/GameObjects/Components/Chemistry/PourableComponent.cs b/Content.Server/GameObjects/Components/Chemistry/PourableComponent.cs deleted file mode 100644 index ac747c962a..0000000000 --- a/Content.Server/GameObjects/Components/Chemistry/PourableComponent.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System.Threading.Tasks; -using Content.Shared.Chemistry; -using Content.Shared.Interfaces; -using Content.Shared.Interfaces.GameObjects.Components; -using Robust.Shared.GameObjects; -using Robust.Shared.Localization; -using Robust.Shared.Serialization; -using Robust.Shared.ViewVariables; - -namespace Content.Server.GameObjects.Components.Chemistry -{ - /// - /// Gives an entity click behavior for pouring reagents into - /// other entities and being poured into. The entity must have - /// a SolutionComponent or DrinkComponent for this to work. - /// (DrinkComponent adds a SolutionComponent if one isn't present). - /// - [RegisterComponent] - class PourableComponent : Component, IInteractUsing - { - public override string Name => "Pourable"; - - private ReagentUnit _transferAmount; - - /// - /// The amount of solution to be transferred from this solution when clicking on other solutions with it. - /// - [ViewVariables(VVAccess.ReadWrite)] - public ReagentUnit TransferAmount - { - get => _transferAmount; - set => _transferAmount = value; - } - - public override void ExposeData(ObjectSerializer serializer) - { - base.ExposeData(serializer); - serializer.DataField(ref _transferAmount, "transferAmount", ReagentUnit.New(5.0)); - } - - /// - /// Called when the owner of this component is clicked on with another entity. - /// The owner of this component is the target. - /// The entity used to click on this one is the attacker. - /// - /// Attack event args - /// - async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) - { - //Get target solution component - if (!Owner.TryGetComponent(out var targetSolution)) - return false; - - //Get attack solution component - var attackEntity = eventArgs.Using; - if (!attackEntity.TryGetComponent(out var attackSolution)) - return false; - - // Calculate possibe solution transfer - if (targetSolution.CanAddSolutions && attackSolution.CanRemoveSolutions) - { - // default logic (beakers and glasses) - // transfer solution from object in hand to attacked - return TryTransfer(eventArgs, attackSolution, targetSolution); - } - else if (targetSolution.CanRemoveSolutions && attackSolution.CanAddSolutions) - { - // storage tanks and sinks logic - // drain solution from attacked object to object in hand - return TryTransfer(eventArgs, targetSolution, attackSolution); - } - - // No transfer possible - return false; - } - - bool TryTransfer(InteractUsingEventArgs eventArgs, SolutionContainerComponent fromSolution, SolutionContainerComponent toSolution) - { - var fromEntity = fromSolution.Owner; - - if (!fromEntity.TryGetComponent(out var fromPourable)) - { - return false; - } - - //Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = ReagentUnit.Min(fromPourable.TransferAmount, toSolution.EmptyVolume); - - if (realTransferAmount <= 0) // Special message if container is full - { - Owner.PopupMessage(eventArgs.User, Loc.GetString("{0:theName} is full!", toSolution.Owner)); - return false; - } - - //Move units from attackSolution to targetSolution - var removedSolution = fromSolution.SplitSolution(realTransferAmount); - - if (removedSolution.TotalVolume <= ReagentUnit.Zero) - { - return false; - } - - if (!toSolution.TryAddSolution(removedSolution)) - { - return false; - } - - Owner.PopupMessage(eventArgs.User, Loc.GetString("You transfer {0}u to {1:theName}.", removedSolution.TotalVolume, toSolution.Owner)); - - return true; - } - } -} diff --git a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs index 51f2bdb46d..eb62004809 100644 --- a/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/ReagentDispenserComponent.cs @@ -161,9 +161,18 @@ namespace Content.Server.GameObjects.Components.Chemistry case UiButton.SetDispenseAmount10: _dispenseAmount = ReagentUnit.New(10); break; + case UiButton.SetDispenseAmount15: + _dispenseAmount = ReagentUnit.New(15); + break; + case UiButton.SetDispenseAmount20: + _dispenseAmount = ReagentUnit.New(20); + break; case UiButton.SetDispenseAmount25: _dispenseAmount = ReagentUnit.New(25); break; + case UiButton.SetDispenseAmount30: + _dispenseAmount = ReagentUnit.New(30); + break; case UiButton.SetDispenseAmount50: _dispenseAmount = ReagentUnit.New(50); break; diff --git a/Content.Server/GameObjects/Components/Chemistry/ReagentTankComponent.cs b/Content.Server/GameObjects/Components/Chemistry/ReagentTankComponent.cs new file mode 100644 index 0000000000..0f654380fb --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/ReagentTankComponent.cs @@ -0,0 +1,35 @@ +using Content.Shared.Chemistry; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +#nullable enable + +namespace Content.Server.GameObjects.Components.Chemistry +{ + [RegisterComponent] + public class ReagentTankComponent : Component + { + public override string Name => "ReagentTank"; + + [ViewVariables(VVAccess.ReadWrite)] + public ReagentUnit TransferAmount { get; set; } + + [ViewVariables(VVAccess.ReadWrite)] + public ReagentTankType TankType { get; set; } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(this, c => c.TransferAmount, "transferAmount", ReagentUnit.New(10)); + serializer.DataField(this, c => c.TankType, "tankType", ReagentTankType.Unspecified); + } + } + + public enum ReagentTankType : byte + { + Unspecified, + Fuel + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/SmokeSolutionAreaEffectComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SmokeSolutionAreaEffectComponent.cs new file mode 100644 index 0000000000..f916725ad6 --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/SmokeSolutionAreaEffectComponent.cs @@ -0,0 +1,63 @@ +#nullable enable +using System.Linq; +using Content.Server.GameObjects.Components.Body.Circulatory; +using Content.Server.GameObjects.Components.Body.Respiratory; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Chemistry; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Server.GameObjects.Components.Chemistry +{ + [RegisterComponent] + [ComponentReference(typeof(SolutionAreaEffectComponent))] + public class SmokeSolutionAreaEffectComponent : SolutionAreaEffectComponent + { + public override string Name => "SmokeSolutionAreaEffect"; + + protected override void UpdateVisuals() + { + if (Owner.TryGetComponent(out AppearanceComponent? appearance) && + SolutionContainerComponent != null) + { + appearance.SetData(SmokeVisuals.Color, SolutionContainerComponent.Color); + } + } + + protected override void ReactWithEntity(IEntity entity, double solutionFraction) + { + if (SolutionContainerComponent == null) + return; + + if (!entity.TryGetComponent(out BloodstreamComponent? bloodstream)) + return; + + if (entity.TryGetComponent(out InternalsComponent? internals) && + internals.AreInternalsWorking()) + return; + + var cloneSolution = SolutionContainerComponent.Solution.Clone(); + var transferAmount = ReagentUnit.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.EmptyVolume); + var transferSolution = cloneSolution.SplitSolution(transferAmount); + + foreach (var reagentQuantity in transferSolution.Contents.ToArray()) + { + if (reagentQuantity.Quantity == ReagentUnit.Zero) continue; + var reagent = PrototypeManager.Index(reagentQuantity.ReagentId); + transferSolution.RemoveReagent(reagentQuantity.ReagentId,reagent.ReactionEntity(entity, ReactionMethod.Ingestion, reagentQuantity.Quantity)); + } + + bloodstream.TryTransferSolution(transferSolution); + } + + + protected override void OnKill() + { + if (Owner.Deleted) + return; + Owner.Delete(); + } + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionAreaEffectComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionAreaEffectComponent.cs new file mode 100644 index 0000000000..682cfac522 --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionAreaEffectComponent.cs @@ -0,0 +1,188 @@ +#nullable enable +using System; +using System.Linq; +using Content.Server.GameObjects.Components.Atmos; +using Content.Server.Utility; +using Content.Shared.Chemistry; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.ComponentDependencies; +using Robust.Shared.GameObjects.Components.Transform; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; + +namespace Content.Server.GameObjects.Components.Chemistry +{ + /// + /// Used to clone its owner repeatedly and group up them all so they behave like one unit, that way you can have + /// effects that cover an area. Inherited by and . + /// + public abstract class SolutionAreaEffectComponent : Component + { + [Dependency] protected readonly IMapManager MapManager = default!; + [Dependency] protected readonly IPrototypeManager PrototypeManager = default!; + + [ComponentDependency] protected readonly SnapGridComponent? SnapGridComponent = default!; + [ComponentDependency] protected readonly SolutionContainerComponent? SolutionContainerComponent = default!; + public int Amount { get; set; } + public SolutionAreaEffectInceptionComponent? Inception { get; set; } + + /// + /// Adds an to owner so the effect starts spreading and reacting. + /// + /// The range of the effect + /// + /// + /// + public void Start(int amount, float duration, float spreadDelay, float removeDelay) + { + if (Inception != null) + return; + + if (Owner.HasComponent()) + return; + + Amount = amount; + var inception = Owner.AddComponent(); + + inception.Add(this); + inception.Setup(amount, duration, spreadDelay, removeDelay); + } + + /// + /// Gets called by an AreaEffectInceptionComponent. "Clones" Owner into the four directions and copies the + /// solution into each of them. + /// + public void Spread() + { + if (Owner.Prototype == null) + { + Logger.Error("AreaEffectComponent needs its owner to be spawned by a prototype."); + return; + } + + if (SnapGridComponent == null) + { + Logger.Error("AreaEffectComponent attached to " + Owner.Prototype.ID + + " couldn't get SnapGridComponent from owner."); + return; + } + + void SpreadToDir(Direction dir) + { + foreach (var neighbor in SnapGridComponent.GetInDir(dir)) + { + if (neighbor.TryGetComponent(out SolutionAreaEffectComponent? comp) && comp.Inception == Inception) + return; + + if (neighbor.TryGetComponent(out AirtightComponent? airtight) && airtight.AirBlocked) + return; + } + + var newEffect = + Owner.EntityManager.SpawnEntity(Owner.Prototype.ID, SnapGridComponent.DirectionToGrid(dir)); + + if (!newEffect.TryGetComponent(out SolutionAreaEffectComponent? effectComponent)) + { + newEffect.Delete(); + return; + } + + if (SolutionContainerComponent != null) + { + effectComponent.TryAddSolution(SolutionContainerComponent.Solution.Clone()); + } + + effectComponent.Amount = Amount - 1; + Inception?.Add(effectComponent); + } + + SpreadToDir(Direction.North); + SpreadToDir(Direction.East); + SpreadToDir(Direction.South); + SpreadToDir(Direction.West); + + } + + /// + /// Gets called by an AreaEffectInceptionComponent. + /// Removes this component from its inception and calls OnKill(). The implementation of OnKill() should + /// eventually delete the entity. + /// + public void Kill() + { + Inception?.Remove(this); + OnKill(); + } + + protected abstract void OnKill(); + + /// + /// Gets called by an AreaEffectInceptionComponent. + /// Makes this effect's reagents react with the tile its on and with the entities it covers. Also calls + /// ReactWithEntity on the entities so inheritors can implement more specific behavior. + /// + /// How many times will this get called over this area effect's duration, averaged + /// with the other area effects from the inception. + public void React(float averageExposures) + { + if (SolutionContainerComponent == null) + return; + + var mapGrid = MapManager.GetGrid(Owner.Transform.GridID); + var tile = mapGrid.GetTileRef(Owner.Transform.Coordinates.ToVector2i(Owner.EntityManager, MapManager)); + + var solutionFraction = 1 / Math.Floor(averageExposures); + + foreach (var reagentQuantity in SolutionContainerComponent.ReagentList.ToArray()) + { + if (reagentQuantity.Quantity == ReagentUnit.Zero) continue; + var reagent = PrototypeManager.Index(reagentQuantity.ReagentId); + + // React with the tile the effect is on + reagent.ReactionTile(tile, reagentQuantity.Quantity * solutionFraction); + + // Touch every entity on the tile + foreach (var entity in tile.GetEntitiesInTileFast()) + { + reagent.ReactionEntity(entity, ReactionMethod.Touch, reagentQuantity.Quantity * solutionFraction); + } + } + + foreach (var entity in tile.GetEntitiesInTileFast()) + { + ReactWithEntity(entity, solutionFraction); + } + } + + protected abstract void ReactWithEntity(IEntity entity, double solutionFraction); + + public void TryAddSolution(Solution solution) + { + if (solution.TotalVolume == 0) + return; + + if (SolutionContainerComponent == null) + return; + + var addSolution = + solution.SplitSolution(ReagentUnit.Min(solution.TotalVolume, SolutionContainerComponent.EmptyVolume)); + + SolutionContainerComponent.TryAddSolution(addSolution); + + UpdateVisuals(); + } + + protected abstract void UpdateVisuals(); + + public override void OnRemove() + { + base.OnRemove(); + Inception?.Remove(this); + } + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionAreaEffectInceptionComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionAreaEffectInceptionComponent.cs new file mode 100644 index 0000000000..2eb1ccebdc --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionAreaEffectInceptionComponent.cs @@ -0,0 +1,142 @@ +#nullable enable +using System.Collections.Generic; +using System.Linq; +using Robust.Shared.GameObjects; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Chemistry +{ + /// + /// The "mastermind" of a SolutionAreaEffect group. It gets updated by the SolutionAreaEffectSystem and tells the + /// group when to spread, react and remove itself. This makes the group act like a single unit. + /// + /// It should only be manually added to an entity by the and not with a prototype. + [RegisterComponent] + public class SolutionAreaEffectInceptionComponent : Component + { + public override string Name => "AreaEffectInception"; + + private const float ReactionDelay = 0.5f; + + private readonly HashSet _group = new(); + + [ViewVariables] private float _lifeTimer; + [ViewVariables] private float _spreadTimer; + [ViewVariables] private float _reactionTimer; + + [ViewVariables] private int _amountCounterSpreading; + [ViewVariables] private int _amountCounterRemoving; + + /// + /// How much time to wait after fully spread before starting to remove itself. + /// + [ViewVariables] private float _duration; + + /// + /// Time between each spread step. Decreasing this makes spreading faster. + /// + [ViewVariables] private float _spreadDelay; + + /// + /// Time between each remove step. Decreasing this makes removing faster. + /// + [ViewVariables] private float _removeDelay; + + /// + /// How many times will the effect react. As some entities from the group last a different amount of time than + /// others, they will react a different amount of times, so we calculate the average to make the group behave + /// a bit more uniformly. + /// + [ViewVariables] private float _averageExposures; + + public void Setup(int amount, float duration, float spreadDelay, float removeDelay) + { + _amountCounterSpreading = amount; + _duration = duration; + _spreadDelay = spreadDelay; + _removeDelay = removeDelay; + + // So the first square reacts immediately after spawning + _reactionTimer = ReactionDelay; + /* + The group takes amount*spreadDelay seconds to fully spread, same with fully disappearing. + The outer squares will last duration seconds. + The first square will last duration + how many seconds the group takes to fully spread and fully disappear, so + it will last duration + amount*(spreadDelay+removeDelay). + Thus, the average lifetime of the smokes will be (outerSmokeLifetime + firstSmokeLifetime)/2 = duration + amount*(spreadDelay+removeDelay)/2 + */ + _averageExposures = (duration + amount * (spreadDelay+removeDelay) / 2)/ReactionDelay; + } + + public void InceptionUpdate(float frameTime) + { + _group.RemoveWhere(effect => effect.Deleted); + if (_group.Count == 0) + return; + + // Make every outer square from the group spread + if (_amountCounterSpreading > 0) + { + _spreadTimer += frameTime; + if (_spreadTimer > _spreadDelay) + { + _spreadTimer -= _spreadDelay; + + var outerEffects = new HashSet(_group.Where(effect => effect.Amount == _amountCounterSpreading)); + foreach (var effect in outerEffects) + { + effect.Spread(); + } + + _amountCounterSpreading -= 1; + } + } + // Start counting for _duration after fully spreading + else + { + _lifeTimer += frameTime; + } + + // Delete every outer square + if (_lifeTimer > _duration) + { + _spreadTimer += frameTime; + if (_spreadTimer > _removeDelay) + { + _spreadTimer -= _removeDelay; + + var outerEffects = new HashSet(_group.Where(effect => effect.Amount == _amountCounterRemoving)); + foreach (var effect in outerEffects) + { + effect.Kill(); + } + + _amountCounterRemoving += 1; + } + } + + // Make every square from the group react with the tile and entities + _reactionTimer += frameTime; + if (_reactionTimer > ReactionDelay) + { + _reactionTimer -= ReactionDelay; + foreach (var effect in _group) + { + effect.React(_averageExposures); + } + } + } + + public void Add(SolutionAreaEffectComponent effect) + { + _group.Add(effect); + effect.Inception = this; + } + + public void Remove(SolutionAreaEffectComponent effect) + { + _group.Remove(effect); + effect.Inception = null; + } + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionContainerComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionContainerComponent.cs index 79a003913e..36ff877874 100644 --- a/Content.Server/GameObjects/Components/Chemistry/SolutionContainerComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionContainerComponent.cs @@ -1,130 +1,27 @@ -#nullable enable +#nullable enable +using Content.Server.Administration; +using Content.Server.Eui; using Content.Server.GameObjects.Components.GUI; +using Content.Shared.Administration; using Content.Shared.Chemistry; +using Content.Shared.Eui; using Content.Shared.GameObjects.Components.Chemistry; +using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.GameObjects.Verbs; +using Robust.Server.Interfaces.GameObjects; +using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Localization; namespace Content.Server.GameObjects.Components.Chemistry { [RegisterComponent] [ComponentReference(typeof(SharedSolutionContainerComponent))] + [ComponentReference(typeof(ISolutionInteractionsComponent))] public class SolutionContainerComponent : SharedSolutionContainerComponent { - /// - /// Transfers solution from the held container to the target container. - /// - [Verb] - private sealed class FillTargetVerb : Verb - { - protected override void GetData(IEntity user, SolutionContainerComponent component, VerbData data) - { - if (!ActionBlockerSystem.CanInteract(user) || - !user.TryGetComponent(out var hands) || - hands.GetActiveHand == null || - hands.GetActiveHand.Owner == component.Owner || - !hands.GetActiveHand.Owner.TryGetComponent(out var solution) || - !solution.CanRemoveSolutions || - !component.CanAddSolutions) - { - data.Visibility = VerbVisibility.Invisible; - return; - } - - var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? ""; - var myName = component.Owner.Prototype?.Name ?? ""; - - var locHeldEntityName = Loc.GetString(heldEntityName); - var locMyName = Loc.GetString(myName); - - data.Visibility = VerbVisibility.Visible; - data.Text = Loc.GetString("Transfer liquid from [{0}] to [{1}].", locHeldEntityName, locMyName); - } - - protected override void Activate(IEntity user, SolutionContainerComponent component) - { - if (!user.TryGetComponent(out var hands) || hands.GetActiveHand == null) - { - return; - } - - if (!hands.GetActiveHand.Owner.TryGetComponent(out var handSolutionComp) || - !handSolutionComp.CanRemoveSolutions || - !component.CanAddSolutions) - { - return; - } - - var transferQuantity = ReagentUnit.Min(component.MaxVolume - component.CurrentVolume, handSolutionComp.CurrentVolume, ReagentUnit.New(10)); - - if (transferQuantity <= 0) - { - return; - } - - var transferSolution = handSolutionComp.SplitSolution(transferQuantity); - component.TryAddSolution(transferSolution); - } - } - - /// - /// Transfers solution from a target container to the held container. - /// - [Verb] - private sealed class EmptyTargetVerb : Verb - { - protected override void GetData(IEntity user, SolutionContainerComponent component, VerbData data) - { - if (!ActionBlockerSystem.CanInteract(user) || - !user.TryGetComponent(out var hands) || - hands.GetActiveHand == null || - hands.GetActiveHand.Owner == component.Owner || - !hands.GetActiveHand.Owner.TryGetComponent(out var solution) || - !solution.CanAddSolutions || - !component.CanRemoveSolutions) - { - data.Visibility = VerbVisibility.Invisible; - return; - } - - var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? ""; - var myName = component.Owner.Prototype?.Name ?? ""; - - var locHeldEntityName = Loc.GetString(heldEntityName); - var locMyName = Loc.GetString(myName); - - data.Visibility = VerbVisibility.Visible; - data.Text = Loc.GetString("Transfer liquid from [{0}] to [{1}].", locMyName, locHeldEntityName); - return; - } - - protected override void Activate(IEntity user, SolutionContainerComponent component) - { - if (!user.TryGetComponent(out var hands) || hands.GetActiveHand == null) - { - return; - } - - if(!hands.GetActiveHand.Owner.TryGetComponent(out var handSolutionComp) || - !handSolutionComp.CanAddSolutions || - !component.CanRemoveSolutions) - { - return; - } - - var transferQuantity = ReagentUnit.Min(handSolutionComp.MaxVolume - handSolutionComp.CurrentVolume, component.CurrentVolume, ReagentUnit.New(10)); - - if (transferQuantity <= 0) - { - return; - } - - var transferSolution = component.SplitSolution(transferQuantity); - handSolutionComp.TryAddSolution(transferSolution); - } - } } } diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionTransferComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionTransferComponent.cs new file mode 100644 index 0000000000..b0f43572eb --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionTransferComponent.cs @@ -0,0 +1,144 @@ +#nullable enable +using System.Threading.Tasks; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Chemistry; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Chemistry +{ + /// + /// Gives click behavior for transferring to/from other reagent containers. + /// + [RegisterComponent] + public sealed class SolutionTransferComponent : Component, IAfterInteract + { + // Behavior is as such: + // If it's a reagent tank, TAKE reagent. + // If it's anything else, GIVE reagent. + // Of course, only if possible. + + public override string Name => "SolutionTransfer"; + + private ReagentUnit _transferAmount; + private bool _canReceive; + private bool _canSend; + + /// + /// The amount of solution to be transferred from this solution when clicking on other solutions with it. + /// + [ViewVariables(VVAccess.ReadWrite)] + public ReagentUnit TransferAmount + { + get => _transferAmount; + set => _transferAmount = value; + } + + /// + /// Can this entity take reagent from reagent tanks? + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool CanReceive + { + get => _canReceive; + set => _canReceive = value; + } + + /// + /// Can this entity give reagent to other reagent containers? + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool CanSend + { + get => _canSend; + set => _canSend = value; + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _transferAmount, "transferAmount", ReagentUnit.New(5)); + serializer.DataField(ref _canReceive, "canReceive", true); + serializer.DataField(ref _canSend, "canSend", true); + } + + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + { + if (!eventArgs.CanReach || eventArgs.Target == null) + return false; + + if (!Owner.TryGetComponent(out ISolutionInteractionsComponent? ownerSolution)) + return false; + + var target = eventArgs.Target; + if (!target.TryGetComponent(out ISolutionInteractionsComponent? targetSolution)) + { + return false; + } + + if (CanReceive && target.TryGetComponent(out ReagentTankComponent? tank) + && ownerSolution.CanRefill && targetSolution.CanDrain) + { + var transferred = DoTransfer(targetSolution, ownerSolution, tank.TransferAmount, eventArgs.User); + if (transferred > 0) + { + var toTheBrim = ownerSolution.RefillSpaceAvailable == 0; + var msg = toTheBrim + ? "You fill {0:TheName} to the brim with {1}u from {2:theName}" + : "You fill {0:TheName} with {1}u from {2:theName}"; + + target.PopupMessage(eventArgs.User, Loc.GetString(msg, Owner, transferred, target)); + return true; + } + } + + if (CanSend && targetSolution.CanRefill && ownerSolution.CanDrain) + { + var transferred = DoTransfer(ownerSolution, targetSolution, TransferAmount, eventArgs.User); + + if (transferred > 0) + { + Owner.PopupMessage(eventArgs.User, Loc.GetString("You transfer {0}u to {1:theName}.", + transferred, target)); + + return true; + } + } + + return true; + } + + /// The actual amount transferred. + private static ReagentUnit DoTransfer( + ISolutionInteractionsComponent source, + ISolutionInteractionsComponent target, + ReagentUnit amount, + IEntity user) + { + if (source.DrainAvailable == 0) + { + source.Owner.PopupMessage(user, Loc.GetString("{0:TheName} is empty!", source.Owner)); + return ReagentUnit.Zero; + } + + if (target.RefillSpaceAvailable == 0) + { + target.Owner.PopupMessage(user, Loc.GetString("{0:TheName} is full!", target.Owner)); + return ReagentUnit.Zero; + } + + var actualAmount = + ReagentUnit.Min(amount, ReagentUnit.Min(source.DrainAvailable, target.RefillSpaceAvailable)); + + var solution = source.Drain(actualAmount); + target.Refill(solution); + + return actualAmount; + } + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionTransferVerbs.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionTransferVerbs.cs new file mode 100644 index 0000000000..8715ed027a --- /dev/null +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionTransferVerbs.cs @@ -0,0 +1,282 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Server.Administration; +using Content.Server.Eui; +using Content.Server.GameObjects.Components.GUI; +using Content.Shared.Administration; +using Content.Shared.Chemistry; +using Content.Shared.Eui; +using Content.Shared.GameObjects.Components.Chemistry; +using Content.Shared.GameObjects.EntitySystems.ActionBlocker; +using Content.Shared.GameObjects.Verbs; +using Robust.Server.Interfaces.GameObjects; +using Robust.Server.Interfaces.Player; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; + +#nullable enable + +namespace Content.Server.GameObjects.Components.Chemistry +{ + internal abstract class SolutionTransferVerbBase : GlobalVerb + { + protected static bool GetHeldSolution( + IEntity holder, + [NotNullWhen(true)] + out IEntity? held, + [NotNullWhen(true)] + out ISolutionInteractionsComponent? heldSolution) + { + if (!holder.TryGetComponent(out HandsComponent? hands) + || hands.GetActiveHand == null + || !hands.GetActiveHand.Owner.TryGetComponent(out heldSolution)) + { + held = null; + heldSolution = null; + return false; + } + + held = heldSolution.Owner; + return true; + } + } + + /// + /// Transfers solution from the held container to the target container. + /// + [GlobalVerb] + internal sealed class SolutionFillTargetVerb : SolutionTransferVerbBase + { + public override void GetData(IEntity user, IEntity target, VerbData data) + { + if (!target.TryGetComponent(out ISolutionInteractionsComponent? targetSolution) || + !ActionBlockerSystem.CanInteract(user) || + !GetHeldSolution(user, out var source, out var sourceSolution) || + source != target || + !sourceSolution.CanDrain || + !targetSolution.CanRefill) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + + data.Visibility = VerbVisibility.Visible; + data.Text = Loc.GetString("Transfer liquid from [{0}] to [{1}].", source.Name, target.Name); + } + + public override void Activate(IEntity user, IEntity target) + { + if (!GetHeldSolution(user, out _, out var handSolutionComp)) + { + return; + } + + if (!handSolutionComp.CanDrain || + !target.TryGetComponent(out ISolutionInteractionsComponent? targetComp) || + !targetComp.CanRefill) + { + return; + } + + var transferQuantity = ReagentUnit.Min( + targetComp.RefillSpaceAvailable, + handSolutionComp.DrainAvailable, + ReagentUnit.New(10)); + + if (transferQuantity <= 0) + { + return; + } + + var transferSolution = handSolutionComp.Drain(transferQuantity); + targetComp.Refill(transferSolution); + } + } + + /// + /// Transfers solution from a target container to the held container. + /// + [GlobalVerb] + internal sealed class SolutionDrainTargetVerb : SolutionTransferVerbBase + { + public override void GetData(IEntity user, IEntity target, VerbData data) + { + if (!target.TryGetComponent(out ISolutionInteractionsComponent? sourceSolution) || + !ActionBlockerSystem.CanInteract(user) || + !GetHeldSolution(user, out var held, out var targetSolution) || + !sourceSolution.CanDrain || + !targetSolution.CanRefill) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + + data.Visibility = VerbVisibility.Visible; + data.Text = Loc.GetString("Transfer liquid from [{0}] to [{1}].", held.Name, target.Name); + } + + public override void Activate(IEntity user, IEntity target) + { + if (!GetHeldSolution(user, out _, out var targetComp)) + { + return; + } + + if (!targetComp.CanRefill || + !target.TryGetComponent(out ISolutionInteractionsComponent? sourceComp) || + !sourceComp.CanDrain) + { + return; + } + + var transferQuantity = ReagentUnit.Min( + targetComp.RefillSpaceAvailable, + sourceComp.DrainAvailable, + ReagentUnit.New(10)); + + if (transferQuantity <= 0) + { + return; + } + + var transferSolution = sourceComp.Drain(transferQuantity); + targetComp.Refill(transferSolution); + } + } + + [GlobalVerb] + internal sealed class AdminAddReagentVerb : GlobalVerb + { + public override bool RequireInteractionRange => false; + public override bool BlockedByContainers => false; + + private const AdminFlags ReqFlags = AdminFlags.Fun; + + private static void OpenAddReagentMenu(IPlayerSession player, IEntity target) + { + var euiMgr = IoCManager.Resolve(); + euiMgr.OpenEui(new AdminAddReagentEui(target), player); + } + + public override void GetData(IEntity user, IEntity target, VerbData data) + { + // ISolutionInteractionsComponent doesn't exactly have an interface for "admin tries to refill this", so... + // Still have a path for SolutionContainerComponent in case it doesn't allow direct refilling. + if (!target.HasComponent() + && !(target.TryGetComponent(out ISolutionInteractionsComponent? interactions) + && interactions.CanInject)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + + data.Text = Loc.GetString("Add Reagent..."); + data.CategoryData = VerbCategories.Debug; + data.Visibility = VerbVisibility.Invisible; + + var adminManager = IoCManager.Resolve(); + + if (user.TryGetComponent(out var player)) + { + if (adminManager.HasAdminFlag(player.playerSession, ReqFlags)) + { + data.Visibility = VerbVisibility.Visible; + } + } + } + + public override void Activate(IEntity user, IEntity target) + { + var groupController = IoCManager.Resolve(); + if (user.TryGetComponent(out var player)) + { + if (groupController.HasAdminFlag(player.playerSession, ReqFlags)) + OpenAddReagentMenu(player.playerSession, target); + } + } + + private sealed class AdminAddReagentEui : BaseEui + { + private readonly IEntity _target; + [Dependency] private readonly IAdminManager _adminManager = default!; + + public AdminAddReagentEui(IEntity target) + { + _target = target; + + IoCManager.InjectDependencies(this); + } + + public override void Opened() + { + StateDirty(); + } + + public override EuiStateBase GetNewState() + { + if (_target.TryGetComponent(out SolutionContainerComponent? container)) + { + return new AdminAddReagentEuiState + { + CurVolume = container.CurrentVolume, + MaxVolume = container.MaxVolume + }; + } + + if (_target.TryGetComponent(out ISolutionInteractionsComponent? interactions)) + { + return new AdminAddReagentEuiState + { + // We don't exactly have an absolute total volume so good enough. + CurVolume = ReagentUnit.Zero, + MaxVolume = interactions.InjectSpaceAvailable + }; + } + + return new AdminAddReagentEuiState + { + CurVolume = ReagentUnit.Zero, + MaxVolume = ReagentUnit.Zero + }; + } + + public override void HandleMessage(EuiMessageBase msg) + { + switch (msg) + { + case AdminAddReagentEuiMsg.Close: + Close(); + break; + case AdminAddReagentEuiMsg.DoAdd doAdd: + // Double check that user wasn't de-adminned in the mean time... + // Or the target was deleted. + if (!_adminManager.HasAdminFlag(Player, ReqFlags) || _target.Deleted) + { + Close(); + return; + } + + var id = doAdd.ReagentId; + var amount = doAdd.Amount; + + if (_target.TryGetComponent(out SolutionContainerComponent? container)) + { + container.TryAddReagent(id, amount, out _); + } + else if (_target.TryGetComponent(out ISolutionInteractionsComponent? interactions)) + { + var solution = new Solution(id, amount); + interactions.Inject(solution); + } + + StateDirty(); + + if (doAdd.CloseAfter) + Close(); + + break; + } + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Chemistry/VaporComponent.cs b/Content.Server/GameObjects/Components/Chemistry/VaporComponent.cs index 44461c3b94..208cfd658f 100644 --- a/Content.Server/GameObjects/Components/Chemistry/VaporComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/VaporComponent.cs @@ -135,12 +135,7 @@ namespace Content.Server.GameObjects.Components.Chemistry if (!Owner.TryGetComponent(out SolutionContainerComponent contents)) return; - foreach (var reagentQuantity in contents.ReagentList.ToArray()) - { - if (reagentQuantity.Quantity == ReagentUnit.Zero) continue; - var reagent = _prototypeManager.Index(reagentQuantity.ReagentId); - contents.TryRemoveReagent(reagentQuantity.ReagentId, reagent.ReactionEntity(collidedWith, ReactionMethod.Touch, reagentQuantity.Quantity * 0.125f)); - } + contents.Solution.DoEntityReaction(collidedWith, ReactionMethod.Touch); // Check for collision with a impassable object (e.g. wall) and stop if (collidedWith.TryGetComponent(out IPhysicsComponent physics)) diff --git a/Content.Server/GameObjects/Components/CrayonComponent.cs b/Content.Server/GameObjects/Components/CrayonComponent.cs index 5c0067a4f7..d44644999a 100644 --- a/Content.Server/GameObjects/Components/CrayonComponent.cs +++ b/Content.Server/GameObjects/Components/CrayonComponent.cs @@ -109,19 +109,22 @@ namespace Content.Server.GameObjects.Components return false; } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: false, popup: true, - collisionMask: Shared.Physics.CollisionGroup.MobImpassable)) return; + collisionMask: Shared.Physics.CollisionGroup.MobImpassable)) + { + return true; + } if (Charges <= 0) { eventArgs.User.PopupMessage(Loc.GetString("Not enough left.")); - return; + return true; } var entityManager = IoCManager.Resolve(); - + var entity = entityManager.SpawnEntity("CrayonDecal", eventArgs.ClickLocation); if (entity.TryGetComponent(out AppearanceComponent? appearance)) { @@ -138,6 +141,7 @@ namespace Content.Server.GameObjects.Components // Decrease "Ammo" Charges--; Dirty(); + return true; } void IDropped.Dropped(DroppedEventArgs eventArgs) diff --git a/Content.Server/GameObjects/Components/Culinary/UtensilComponent.cs b/Content.Server/GameObjects/Components/Culinary/UtensilComponent.cs index d6c8629c6b..01eaeb5068 100644 --- a/Content.Server/GameObjects/Components/Culinary/UtensilComponent.cs +++ b/Content.Server/GameObjects/Components/Culinary/UtensilComponent.cs @@ -107,9 +107,10 @@ namespace Content.Server.GameObjects.Components.Culinary serializer.DataField(ref _breakSound, "breakSound", "/Audio/Items/snap.ogg"); } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { TryUseUtensil(eventArgs.User, eventArgs.Target); + return true; } private void TryUseUtensil(IEntity user, IEntity? target) diff --git a/Content.Server/GameObjects/Components/Fluids/MopComponent.cs b/Content.Server/GameObjects/Components/Fluids/MopComponent.cs index ad6e85b951..11fda8a54a 100644 --- a/Content.Server/GameObjects/Components/Fluids/MopComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/MopComponent.cs @@ -62,14 +62,16 @@ namespace Content.Server.GameObjects.Components.Fluids Owner.EnsureComponentWarn(out SolutionContainerComponent _); } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { - if (!Owner.TryGetComponent(out SolutionContainerComponent? contents)) return; - if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) return; + if (!Owner.TryGetComponent(out SolutionContainerComponent? contents)) + return false; + if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) + return false; if (CurrentVolume <= 0) { - return; + return true; } if (eventArgs.Target == null) @@ -77,12 +79,12 @@ namespace Content.Server.GameObjects.Components.Fluids // Drop the liquid on the mop on to the ground contents.SplitSolution(CurrentVolume).SpillAt(eventArgs.ClickLocation, "PuddleSmear"); - return; + return true; } if (!eventArgs.Target.TryGetComponent(out PuddleComponent? puddleComponent)) { - return; + return true; } // Essentially pickup either: // - _pickupAmount, @@ -101,7 +103,7 @@ namespace Content.Server.GameObjects.Components.Fluids } else { - return; + return true; } } else @@ -121,12 +123,12 @@ namespace Content.Server.GameObjects.Components.Fluids // Give some visual feedback shit's happening (for anyone who can't hear sound) Owner.PopupMessage(eventArgs.User, Loc.GetString("Swish")); - if (string.IsNullOrWhiteSpace(_pickupSound)) + if (!string.IsNullOrWhiteSpace(_pickupSound)) { - return; + EntitySystem.Get().PlayFromEntity(_pickupSound, Owner); } - EntitySystem.Get().PlayFromEntity(_pickupSound, Owner); + return true; } } } diff --git a/Content.Server/GameObjects/Components/Fluids/SpillableComponent.cs b/Content.Server/GameObjects/Components/Fluids/SpillableComponent.cs index 62b2a5ec6c..5026ede0e4 100644 --- a/Content.Server/GameObjects/Components/Fluids/SpillableComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/SpillableComponent.cs @@ -1,6 +1,5 @@ -using Content.Server.GameObjects.Components.Chemistry; -using Content.Shared.Chemistry; -using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.GameObjects.Verbs; using Content.Shared.Interfaces; @@ -24,34 +23,37 @@ namespace Content.Server.GameObjects.Components.Fluids protected override void GetData(IEntity user, SpillableComponent component, VerbData data) { if (!ActionBlockerSystem.CanInteract(user) || - !component.Owner.TryGetComponent(out SolutionContainerComponent solutionComponent) || - !solutionComponent.CanRemoveSolutions) + !component.Owner.TryGetComponent(out ISolutionInteractionsComponent solutionComponent) || + !solutionComponent.CanDrain) { data.Visibility = VerbVisibility.Invisible; return; } data.Text = Loc.GetString("Spill liquid"); - data.Visibility = solutionComponent.CurrentVolume > ReagentUnit.Zero ? VerbVisibility.Visible : VerbVisibility.Disabled; + data.Visibility = solutionComponent.DrainAvailable > ReagentUnit.Zero + ? VerbVisibility.Visible + : VerbVisibility.Disabled; } protected override void Activate(IEntity user, SpillableComponent component) { - if (component.Owner.TryGetComponent(out var solutionComponent)) + if (component.Owner.TryGetComponent(out var solutionComponent)) { - if (!solutionComponent.CanRemoveSolutions) + if (!solutionComponent.CanDrain) { - user.PopupMessage(user, Loc.GetString("You can't pour anything from {0:theName}!", component.Owner)); + user.PopupMessage(user, + Loc.GetString("You can't pour anything from {0:theName}!", component.Owner)); } - if (solutionComponent.CurrentVolume.Float() <= 0) + if (solutionComponent.DrainAvailable <= 0) { user.PopupMessage(user, Loc.GetString("{0:theName} is empty!", component.Owner)); } // Need this as when we split the component's owner may be deleted var entityLocation = component.Owner.Transform.Coordinates; - var solution = solutionComponent.SplitSolution(solutionComponent.CurrentVolume); + var solution = solutionComponent.Drain(solutionComponent.DrainAvailable); solution.SpillAt(entityLocation, "PuddleSmear"); } } diff --git a/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs b/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs index 09900b8f58..0d82752b64 100644 --- a/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/SprayComponent.cs @@ -100,34 +100,34 @@ namespace Content.Server.GameObjects.Components.Fluids serializer.DataField(ref _safety, "safety", true); } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (!ActionBlockerSystem.CanInteract(eventArgs.User)) - return; + return false; if (_hasSafety && _safety) { Owner.PopupMessage(eventArgs.User, Loc.GetString("Its safety is on!")); - return; + return true; } if (CurrentVolume <= 0) { Owner.PopupMessage(eventArgs.User, Loc.GetString("It's empty!")); - return; + return true; } var curTime = _gameTiming.CurTime; if(curTime < _cooldownEnd) - return; + return true; var playerPos = eventArgs.User.Transform.Coordinates; if (eventArgs.ClickLocation.GetGridId(_serverEntityManager) != playerPos.GetGridId(_serverEntityManager)) - return; + return true; if (!Owner.TryGetComponent(out SolutionContainerComponent contents)) - return; + return true; var direction = (eventArgs.ClickLocation.Position - playerPos.Position).Normalized; var threeQuarters = direction * 0.75f; @@ -183,6 +183,8 @@ namespace Content.Server.GameObjects.Components.Fluids cooldown.CooldownStart = _lastUseTime; cooldown.CooldownEnd = _cooldownEnd; } + + return true; } bool IUse.UseEntity(UseEntityEventArgs eventArgs) diff --git a/Content.Server/GameObjects/Components/GUI/HandsComponent.cs b/Content.Server/GameObjects/Components/GUI/HandsComponent.cs index 0182636f77..2c7aad758e 100644 --- a/Content.Server/GameObjects/Components/GUI/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/HandsComponent.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -176,9 +176,16 @@ namespace Content.Server.GameObjects.Components.GUI Dirty(); + var position = item.Owner.Transform.Coordinates; + var contained = item.Owner.IsInContainer(); var success = hand.Container.Insert(item.Owner); if (success) { + //If the entity isn't in a container, and it isn't located exactly at our position (i.e. in our own storage), then we can safely play the animation + if (position != Owner.Transform.Coordinates && !contained) + { + SendNetworkMessage(new AnimatePickupEntityMessage(item.Owner.Uid, position)); + } item.Owner.Transform.LocalPosition = Vector2.Zero; OnItemChanged?.Invoke(); } @@ -191,14 +198,33 @@ namespace Content.Server.GameObjects.Components.GUI return success; } + /// + /// Drops the item if doesn't have hands. + /// + public static void PutInHandOrDropStatic(IEntity mob, ItemComponent item, bool mobCheck = true) + { + if (!mob.TryGetComponent(out HandsComponent? hands)) + { + DropAtFeet(mob, item); + return; + } + + hands.PutInHandOrDrop(item, mobCheck); + } + public void PutInHandOrDrop(ItemComponent item, bool mobCheck = true) { if (!PutInHand(item, mobCheck)) { - item.Owner.Transform.Coordinates = Owner.Transform.Coordinates; + DropAtFeet(Owner, item); } } + private static void DropAtFeet(IEntity mob, ItemComponent item) + { + item.Owner.Transform.Coordinates = mob.Transform.Coordinates; + } + public bool CanPutInHand(ItemComponent item, bool mobCheck = true) { if (mobCheck && !ActionBlockerSystem.CanPickup(Owner)) diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs index 3527e9fcfb..b402e587ae 100644 --- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using Content.Server.Administration.Commands; @@ -15,9 +15,9 @@ using Content.Shared.GameObjects.Verbs; using Content.Shared.Interfaces; using Robust.Server.Console; using Robust.Server.GameObjects.Components.Container; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.GameObjects; using Robust.Server.Player; +using Robust.Shared.Console; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; @@ -686,9 +686,10 @@ namespace Content.Server.GameObjects.Components.GUI var entityId = target.Uid.ToString(); var command = new SetOutfitCommand(); - var shell = IoCManager.Resolve(); + var host = IoCManager.Resolve(); var args = new string[] {entityId}; - command.Execute(shell, user.PlayerSession(), args); + var session = user.PlayerSession(); + command.Execute(new ConsoleShell(host, session), $"{command.Command} {entityId}", args); } private static bool CanCommand(IEntity user) diff --git a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs index c7c25f8d1e..990e6da091 100644 --- a/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs +++ b/Content.Server/GameObjects/Components/Instruments/InstrumentComponent.cs @@ -4,9 +4,7 @@ using System.Linq; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.EntitySystems; using Content.Server.Utility; -using Content.Shared; using Content.Shared.GameObjects.Components.Instruments; -using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; @@ -18,10 +16,7 @@ using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; -using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.Network; -using Robust.Shared.Interfaces.Timing; -using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Players; using Robust.Shared.Serialization; @@ -41,9 +36,6 @@ namespace Content.Server.GameObjects.Components.Instruments IUse, IThrown { - [Dependency] private readonly IGameTiming _gameTiming = default!; - - private static readonly TimeSpan OneSecAgo = TimeSpan.FromSeconds(-1); private InstrumentSystem _instrumentSystem = default!; /// @@ -60,9 +52,6 @@ namespace Content.Server.GameObjects.Components.Instruments [ViewVariables] private float _timer = 0f; - [ViewVariables(VVAccess.ReadOnly)] - private TimeSpan _lastMeasured = TimeSpan.MinValue; - [ViewVariables] private int _batchesDropped = 0; @@ -213,15 +202,6 @@ namespace Content.Server.GameObjects.Components.Instruments var minTick = midiEventMsg.MidiEvent.Min(x => x.Tick); if (_lastSequencerTick > minTick) { - var now = _gameTiming.RealTime; - var oneSecAGo = now.Add(OneSecAgo); - if (_lastMeasured < oneSecAGo) - { - _lastMeasured = now; - _laggedBatches = 0; - _batchesDropped = 0; - } - _laggedBatches++; if (_respectMidiLimits) @@ -246,15 +226,6 @@ namespace Content.Server.GameObjects.Components.Instruments if (++_midiEventCount > maxMidiEventsPerSecond || midiEventMsg.MidiEvent.Length > maxMidiEventsPerBatch) { - var now = _gameTiming.RealTime; - var oneSecAGo = now.Add(OneSecAgo); - if (_lastMeasured < oneSecAGo) - { - _lastMeasured = now; - _laggedBatches = 0; - _batchesDropped = 0; - } - _batchesDropped++; send = false; @@ -266,7 +237,7 @@ namespace Content.Server.GameObjects.Components.Instruments } var maxTick = midiEventMsg.MidiEvent.Max(x => x.Tick); - _lastSequencerTick = Math.Max(maxTick, minTick + 1); + _lastSequencerTick = Math.Max(maxTick, minTick); break; case InstrumentStartMidiMessage startMidi: if (session != _instrumentPlayer) @@ -386,15 +357,14 @@ namespace Content.Server.GameObjects.Components.Instruments UserInterface?.CloseAll(); + if(Handheld) + EntitySystem.Get().DropAllItemsInHands(mob, false); + if (mob != null && mob.TryGetComponent(out StunnableComponent? stun)) { stun.Stun(1); Clean(); } - else - { - EntitySystem.Get().DropAllItemsInHands(mob, false); - } InstrumentPlayer = null; @@ -406,6 +376,8 @@ namespace Content.Server.GameObjects.Components.Instruments _timer = 0f; _midiEventCount = 0; + _laggedBatches = 0; + _batchesDropped = 0; } } diff --git a/Content.Server/GameObjects/Components/Interactable/TilePryingComponent.cs b/Content.Server/GameObjects/Components/Interactable/TilePryingComponent.cs index f932a40f8d..18746fa094 100644 --- a/Content.Server/GameObjects/Components/Interactable/TilePryingComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/TilePryingComponent.cs @@ -21,9 +21,10 @@ namespace Content.Server.GameObjects.Components.Interactable public override string Name => "TilePrying"; private bool _toolComponentNeeded = true; - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { TryPryTile(eventArgs.User, eventArgs.ClickLocation); + return true; } public override void ExposeData(ObjectSerializer serializer) diff --git a/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs b/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs index 25b4aaf4c1..854f93a6ea 100644 --- a/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/WelderComponent.cs @@ -2,6 +2,7 @@ using System; using System.Threading.Tasks; using Content.Server.Atmos; +using Content.Server.Explosions; using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.EntitySystems; @@ -10,12 +11,15 @@ using Content.Server.Interfaces.GameObjects; using Content.Server.Utility; using Content.Shared.Chemistry; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Server.GameObjects; +using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; @@ -29,7 +33,7 @@ namespace Content.Server.GameObjects.Components.Interactable [ComponentReference(typeof(ToolComponent))] [ComponentReference(typeof(IToolComponent))] [ComponentReference(typeof(IHotItem))] - public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange, IHotItem + public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange, IHotItem, IAfterInteract { [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!; @@ -293,5 +297,38 @@ namespace Content.Server.GameObjects.Components.Interactable } + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + { + if (eventArgs.Target == null || !eventArgs.CanReach) + { + return false; + } + + if (eventArgs.Target.TryGetComponent(out ReagentTankComponent? tank) + && tank.TankType == ReagentTankType.Fuel + && eventArgs.Target.TryGetComponent(out ISolutionInteractionsComponent? targetSolution) + && targetSolution.CanDrain + && _solutionComponent != null) + { + if (WelderLit) + { + // Oh no no + eventArgs.Target.SpawnExplosion(); + return true; + } + + var trans = ReagentUnit.Min(_solutionComponent.EmptyVolume, targetSolution.DrainAvailable); + if (trans > 0) + { + var drained = targetSolution.Drain(trans); + _solutionComponent.TryAddSolution(drained); + + EntitySystem.Get().PlayFromEntity("/Audio/Effects/refill.ogg", Owner); + eventArgs.Target.PopupMessage(eventArgs.User, Loc.GetString("Welder refueled")); + } + } + + return true; + } } } diff --git a/Content.Server/GameObjects/Components/Items/FireExtinguisherComponent.cs b/Content.Server/GameObjects/Components/Items/FireExtinguisherComponent.cs index 6159aa7f52..3edcd5b392 100644 --- a/Content.Server/GameObjects/Components/Items/FireExtinguisherComponent.cs +++ b/Content.Server/GameObjects/Components/Items/FireExtinguisherComponent.cs @@ -1,10 +1,52 @@ -using Robust.Shared.GameObjects; +using System.Threading.Tasks; +using Content.Server.GameObjects.Components.Chemistry; +using Content.Shared.Chemistry; +using Content.Shared.GameObjects.Components.Chemistry; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Localization; + +#nullable enable namespace Content.Server.GameObjects.Components.Items { [RegisterComponent] - public class FireExtinguisherComponent : Component + public class FireExtinguisherComponent : Component, IAfterInteract { public override string Name => "FireExtinguisher"; + + // Higher priority than sprays. + int IAfterInteract.Priority => 1; + + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + { + if (eventArgs.Target == null || !eventArgs.CanReach) + { + return false; + } + + if (eventArgs.Target.TryGetComponent(out ReagentTankComponent? tank) + && eventArgs.Target.TryGetComponent(out ISolutionInteractionsComponent? targetSolution) + && targetSolution.CanDrain + && Owner.TryGetComponent(out SolutionContainerComponent? container)) + { + var trans = ReagentUnit.Min(container.EmptyVolume, targetSolution.DrainAvailable); + if (trans > 0) + { + var drained = targetSolution.Drain(trans); + container.TryAddSolution(drained); + + EntitySystem.Get().PlayFromEntity("/Audio/Effects/refill.ogg", Owner); + eventArgs.Target.PopupMessage(eventArgs.User, Loc.GetString("{0:TheName} is now refilled", Owner)); + } + + return true; + } + + return false; + } } } diff --git a/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs b/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs index 7b715cd433..a65215e12b 100644 --- a/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/FloorTileItemComponent.cs @@ -56,10 +56,14 @@ namespace Content.Server.GameObjects.Components.Items EntitySystem.Get().PlayAtCoords("/Audio/Items/genhit.ogg", location, AudioHelpers.WithVariation(0.125f)); } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { - if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) return; - if (!Owner.TryGetComponent(out StackComponent stack)) return; + if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) + return true; + + if (!Owner.TryGetComponent(out StackComponent stack)) + return true; + var mapManager = IoCManager.Resolve(); var location = eventArgs.ClickLocation.AlignWithClosestGridTile(); @@ -88,10 +92,9 @@ namespace Content.Server.GameObjects.Components.Items PlaceAt(mapGrid, location, _tileDefinitionManager[_outputTiles[0]].TileId, mapGrid.TileSize / 2f); break; } - - } + return true; } } } diff --git a/Content.Server/GameObjects/Components/Items/RCD/RCDAmmoComponent.cs b/Content.Server/GameObjects/Components/Items/RCD/RCDAmmoComponent.cs index 5ab40c7413..7c874a59a1 100644 --- a/Content.Server/GameObjects/Components/Items/RCD/RCDAmmoComponent.cs +++ b/Content.Server/GameObjects/Components/Items/RCD/RCDAmmoComponent.cs @@ -32,17 +32,17 @@ namespace Content.Server.GameObjects.Components.Items.RCD message.AddMarkup(Loc.GetString("It holds {0} charges.", refillAmmo)); } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (eventArgs.Target == null || !eventArgs.Target.TryGetComponent(out RCDComponent rcdComponent) || !eventArgs.User.TryGetComponent(out IHandsComponent hands)) { - return; + return false; } if (rcdComponent.maxAmmo - rcdComponent._ammo < refillAmmo) { rcdComponent.Owner.PopupMessage(eventArgs.User, Loc.GetString("The RCD is full!")); - return; + return true; } rcdComponent._ammo = Math.Min(rcdComponent.maxAmmo, rcdComponent._ammo + refillAmmo); @@ -51,6 +51,7 @@ namespace Content.Server.GameObjects.Components.Items.RCD //Deleting a held item causes a lot of errors hands.Drop(Owner, false); Owner.Delete(); + return true; } } } diff --git a/Content.Server/GameObjects/Components/Items/RCD/RCDComponent.cs b/Content.Server/GameObjects/Components/Items/RCD/RCDComponent.cs index 23d96861ec..f344dbf98b 100644 --- a/Content.Server/GameObjects/Components/Items/RCD/RCDComponent.cs +++ b/Content.Server/GameObjects/Components/Items/RCD/RCDComponent.cs @@ -93,7 +93,7 @@ namespace Content.Server.GameObjects.Components.Items.RCD message.AddMarkup(Loc.GetString("It's currently on {0} mode, and holds {1} charges.",_mode.ToString(), _ammo)); } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { //No changing mode mid-RCD var startingMode = _mode; @@ -115,7 +115,7 @@ namespace Content.Server.GameObjects.Components.Items.RCD var result = await doAfterSystem.DoAfter(doAfterEventArgs); if (result == DoAfterStatus.Cancelled) { - return; + return true; } switch (_mode) @@ -145,12 +145,12 @@ namespace Content.Server.GameObjects.Components.Items.RCD airlock.Transform.LocalRotation = Owner.Transform.LocalRotation; //Now apply icon smoothing. break; default: - return; //I don't know why this would happen, but sure I guess. Get out of here invalid state! + return true; //I don't know why this would happen, but sure I guess. Get out of here invalid state! } _entitySystemManager.GetEntitySystem().PlayFromEntity("/Audio/Items/deconstruct.ogg", Owner); _ammo--; - + return true; } private bool IsRCDStillValid(AfterInteractEventArgs eventArgs, IMapGrid mapGrid, TileRef tile, Vector2i snapPos, RcdMode startingMode) diff --git a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs index fda487377c..b50a23bb4d 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Content.Server.GameObjects.Components.GUI; +using Content.Server.GameObjects.EntitySystems.DoAfter; using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Shared.Audio; using Content.Shared.GameObjects.Components.Storage; @@ -24,6 +26,7 @@ using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Network; using Robust.Shared.Log; +using Robust.Shared.Map; using Robust.Shared.Players; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -36,7 +39,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage [RegisterComponent] [ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IStorageComponent))] - public class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IUse, IActivate, IStorageComponent, IDestroyAct, IExAct + public class ServerStorageComponent : SharedStorageComponent, IInteractUsing, IUse, IActivate, IStorageComponent, IDestroyAct, IExAct, IAfterInteract { private const string LoggerName = "Storage"; @@ -44,6 +47,8 @@ namespace Content.Server.GameObjects.Components.Items.Storage private readonly Dictionary _sizeCache = new(); private bool _occludesLight; + private bool _quickInsert; //Can insert storables by "attacking" them with the storage entity + private bool _areaInsert; //"Attacking" with the storage entity causes it to insert all nearby storables after a delay private bool _storageInitialCalculated; private int _storageUsed; private int _storageCapacityMax; @@ -184,7 +189,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage /// /// The player to insert an entity from /// true if inserted, false otherwise - public bool PlayerInsertEntity(IEntity player) + public bool PlayerInsertHeldEntity(IEntity player) { EnsureInitialCalculated(); @@ -212,6 +217,24 @@ namespace Content.Server.GameObjects.Components.Items.Storage return true; } + /// + /// Inserts an Entity () in the world into storage, informing if it fails. + /// is *NOT* held, see . + /// + /// The player to insert an entity with + /// true if inserted, false otherwise + public bool PlayerInsertEntityInWorld(IEntity player, IEntity toInsert) + { + EnsureInitialCalculated(); + + if (!Insert(toInsert)) + { + Owner.PopupMessage(player, "Can't insert."); + return false; + } + return true; + } + /// /// Opens the storage UI for an entity /// @@ -343,6 +366,8 @@ namespace Content.Server.GameObjects.Components.Items.Storage serializer.DataField(ref _storageCapacityMax, "capacity", 10000); serializer.DataField(ref _occludesLight, "occludesLight", true); + serializer.DataField(ref _quickInsert, "quickInsert", false); + serializer.DataField(ref _areaInsert, "areaInsert", false); serializer.DataField(this, x => x.StorageSoundCollection, "storageSoundCollection", string.Empty); //serializer.DataField(ref StorageUsed, "used", 0); } @@ -418,7 +443,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage break; } - PlayerInsertEntity(player); + PlayerInsertHeldEntity(player); break; } @@ -449,7 +474,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage return false; } - return PlayerInsertEntity(eventArgs.User); + return PlayerInsertHeldEntity(eventArgs.User); } /// @@ -469,6 +494,97 @@ namespace Content.Server.GameObjects.Components.Items.Storage ((IUse) this).UseEntity(new UseEntityEventArgs { User = eventArgs.User }); } + /// + /// Allows a user to pick up entities by clicking them, or pick up all entities in a certain radius + /// arround a click. + /// + /// + /// + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + { + if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) return false; + + // Pick up all entities in a radius around the clicked location. + // The last half of the if is because carpets exist and this is terrible + if(_areaInsert && (eventArgs.Target == null || !eventArgs.Target.HasComponent())) + { + var validStorables = new List(); + foreach (var entity in Owner.EntityManager.GetEntitiesInRange(eventArgs.ClickLocation, 1)) + { + if (!entity.Transform.IsMapTransform + || entity == eventArgs.User + || !entity.HasComponent()) + continue; + validStorables.Add(entity); + } + + //If there's only one then let's be generous + if (validStorables.Count > 1) + { + var doAfterSystem = EntitySystem.Get(); + var doAfterArgs = new DoAfterEventArgs(eventArgs.User, 0.2f * validStorables.Count, CancellationToken.None, Owner) + { + BreakOnStun = true, + BreakOnDamage = true, + BreakOnUserMove = true, + NeedHand = true, + }; + var result = await doAfterSystem.DoAfter(doAfterArgs); + if (result != DoAfterStatus.Finished) return true; + } + + var successfullyInserted = new List(); + var successfullyInsertedPositions = new List(); + foreach (var entity in validStorables) + { + // Check again, situation may have changed for some entities, but we'll still pick up any that are valid + if (!entity.Transform.IsMapTransform + || entity == eventArgs.User + || !entity.HasComponent()) + continue; + var coords = entity.Transform.Coordinates; + if (PlayerInsertEntityInWorld(eventArgs.User, entity)) + { + successfullyInserted.Add(entity.Uid); + successfullyInsertedPositions.Add(coords); + } + } + + // If we picked up atleast one thing, play a sound and do a cool animation! + if (successfullyInserted.Count>0) + { + PlaySoundCollection(StorageSoundCollection); + SendNetworkMessage( + new AnimateInsertingEntitiesMessage( + successfullyInserted, + successfullyInsertedPositions + ) + ); + } + return true; + } + // Pick up the clicked entity + else if(_quickInsert) + { + if (eventArgs.Target == null + || !eventArgs.Target.Transform.IsMapTransform + || eventArgs.Target == eventArgs.User + || !eventArgs.Target.HasComponent()) + return false; + var position = eventArgs.Target.Transform.Coordinates; + if(PlayerInsertEntityInWorld(eventArgs.User, eventArgs.Target)) + { + SendNetworkMessage(new AnimateInsertingEntitiesMessage( + new List() { eventArgs.Target.Uid }, + new List() { position } + )); + return true; + } + return true; + } + return false; + } + void IDestroyAct.OnDestroy(DestructionEventArgs eventArgs) { var storedEntities = StoredEntities?.ToList(); diff --git a/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs b/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs index 9c42c520ac..83869ceef3 100644 --- a/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs +++ b/Content.Server/GameObjects/Components/Kitchen/MicrowaveComponent.cs @@ -13,6 +13,7 @@ using Content.Server.Utility; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Body; using Content.Shared.GameObjects.Components.Body.Part; +using Content.Shared.GameObjects.Components.Chemistry; using Content.Shared.GameObjects.Components.Power; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; @@ -213,10 +214,10 @@ namespace Content.Server.GameObjects.Components.Kitchen return false; } - if (itemEntity.TryGetComponent(out var attackPourable)) + if (itemEntity.TryGetComponent(out var attackPourable)) { - if (!itemEntity.TryGetComponent(out var attackSolution) - || !attackSolution.CanRemoveSolutions) + if (!itemEntity.TryGetComponent(out var attackSolution) + || !attackSolution.CanDrain) { return false; } @@ -235,7 +236,7 @@ namespace Content.Server.GameObjects.Components.Kitchen } //Move units from attackSolution to targetSolution - var removedSolution = attackSolution.SplitSolution(realTransferAmount); + var removedSolution = attackSolution.Drain(realTransferAmount); if (!solution.TryAddSolution(removedSolution)) { return false; diff --git a/Content.Server/GameObjects/Components/Medical/HealingComponent.cs b/Content.Server/GameObjects/Components/Medical/HealingComponent.cs index afee00d754..bdacd030c8 100644 --- a/Content.Server/GameObjects/Components/Medical/HealingComponent.cs +++ b/Content.Server/GameObjects/Components/Medical/HealingComponent.cs @@ -26,39 +26,41 @@ namespace Content.Server.GameObjects.Components.Medical serializer.DataField(this, h => h.Heal, "heal", new Dictionary()); } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (eventArgs.Target == null) { - return; + return false; } if (!eventArgs.Target.TryGetComponent(out IDamageableComponent damageable)) { - return; + return true; } if (!ActionBlockerSystem.CanInteract(eventArgs.User)) { - return; + return true; } if (eventArgs.User != eventArgs.Target && !eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) { - return; + return true; } if (Owner.TryGetComponent(out StackComponent stack) && !stack.Use(1)) { - return; + return true; } foreach (var (type, amount) in Heal) { damageable.ChangeDamage(type, -amount, true); } + + return true; } } } diff --git a/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs b/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs index 180e73897b..b9f98a6ec4 100644 --- a/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs +++ b/Content.Server/GameObjects/Components/Metabolism/MetabolismComponent.cs @@ -206,10 +206,13 @@ namespace Content.Server.GameObjects.Components.Metabolism if (bloodstreamAmount < amountNeeded) { - // Panic inhale - foreach (var lung in lungs) + if (!Owner.GetComponent().IsCritical()) { - lung.Gasp(); + // Panic inhale + foreach (var lung in lungs) + { + lung.Gasp(); + } } bloodstreamAmount = bloodstream.Air.GetMoles(gas); diff --git a/Content.Server/GameObjects/Components/Mobs/ClumsyComponent.cs b/Content.Server/GameObjects/Components/Mobs/ClumsyComponent.cs index 5e55a21a3e..02a278a29b 100644 --- a/Content.Server/GameObjects/Components/Mobs/ClumsyComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/ClumsyComponent.cs @@ -1,4 +1,10 @@ using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Random; +using Robust.Shared.IoC; +using Robust.Shared.Random; + +#nullable enable namespace Content.Server.GameObjects.Components.Mobs { @@ -8,6 +14,27 @@ namespace Content.Server.GameObjects.Components.Mobs [RegisterComponent] public class ClumsyComponent : Component { + [Dependency] private readonly IRobustRandom _random = default!; + public override string Name => "Clumsy"; + + public bool RollClumsy(float chance) + { + return Running && _random.Prob(chance); + } + + /// + /// Rolls a probability chance for a "bad action" if the target entity is clumsy. + /// + /// The entity that the clumsy check is happening for. + /// + /// The chance that a "bad action" happens if the user is clumsy, between 0 and 1 inclusive. + /// + /// True if a "bad action" happened, false if the normal action should happen. + public static bool TryRollClumsy(IEntity entity, float chance) + { + return entity.TryGetComponent(out ClumsyComponent? clumsy) + && clumsy.RollClumsy(chance); + } } } diff --git a/Content.Server/GameObjects/Components/Mobs/ServerOverlayEffectsComponent.cs b/Content.Server/GameObjects/Components/Mobs/ServerOverlayEffectsComponent.cs deleted file mode 100644 index 6b0c7214f4..0000000000 --- a/Content.Server/GameObjects/Components/Mobs/ServerOverlayEffectsComponent.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.Collections.Generic; -using Content.Shared.GameObjects.Components.Mobs; -using Robust.Server.Interfaces.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.Network; -using Robust.Shared.Players; -using Robust.Shared.ViewVariables; - -namespace Content.Server.GameObjects.Components.Mobs -{ - [RegisterComponent] - [ComponentReference(typeof(SharedOverlayEffectsComponent))] - public sealed class ServerOverlayEffectsComponent : SharedOverlayEffectsComponent - { - public ServerOverlayEffectsComponent() - { - NetSyncEnabled = false; - } - - [ViewVariables(VVAccess.ReadWrite)] - public List ActiveOverlays { get; } = new(); - - public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession session = null) - { - if (Owner.TryGetComponent(out IActorComponent actor) && message is ResendOverlaysMessage) - { - if (actor.playerSession.ConnectedClient == netChannel) - { - SyncClient(); - } - } - } - - public void AddOverlay(string id) => AddOverlay(new OverlayContainer(id)); - - public void AddOverlay(SharedOverlayID id) => AddOverlay(new OverlayContainer(id)); - - public void AddOverlay(OverlayContainer container) - { - if (!ActiveOverlays.Contains(container)) - { - ActiveOverlays.Add(container); - SyncClient(); - } - } - - public void RemoveOverlay(SharedOverlayID id) => RemoveOverlay(id.ToString()); - - public void RemoveOverlay(string id) => RemoveOverlay(new OverlayContainer(id)); - - public void RemoveOverlay(OverlayContainer container) - { - if (ActiveOverlays.Remove(container)) - { - SyncClient(); - } - } - - public bool TryModifyOverlay(string id, Action modifications) - { - var overlay = ActiveOverlays.Find(c => c.ID == id); - if (overlay == null) - { - return false; - } - - modifications(overlay); - SyncClient(); - return true; - } - - public void ClearOverlays() - { - if (ActiveOverlays.Count == 0) - { - return; - } - - ActiveOverlays.Clear(); - SyncClient(); - } - - private void SyncClient() - { - if (Owner.TryGetComponent(out IActorComponent actor)) - { - if (actor.playerSession.ConnectedClient.IsConnected) - { - SendNetworkMessage(new OverlayEffectComponentMessage(ActiveOverlays), actor.playerSession.ConnectedClient); - } - } - } - } -} diff --git a/Content.Server/GameObjects/Components/Mobs/State/CriticalMobState.cs b/Content.Server/GameObjects/Components/Mobs/State/CriticalMobState.cs index a7d5c7c8e0..cae7cd53e7 100644 --- a/Content.Server/GameObjects/Components/Mobs/State/CriticalMobState.cs +++ b/Content.Server/GameObjects/Components/Mobs/State/CriticalMobState.cs @@ -20,11 +20,6 @@ namespace Content.Server.GameObjects.Components.Mobs.State appearance.SetData(DamageStateVisuals.State, DamageState.Critical); } - if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlay)) - { - overlay.AddOverlay(SharedOverlayID.GradientCircleMaskOverlay); - } - if (entity.TryGetComponent(out StunnableComponent stun)) { stun.CancelAll(); @@ -36,11 +31,6 @@ namespace Content.Server.GameObjects.Components.Mobs.State public override void ExitState(IEntity entity) { base.ExitState(entity); - - if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlay)) - { - overlay.ClearOverlays(); - } } } } diff --git a/Content.Server/GameObjects/Components/Mobs/State/DeadMobState.cs b/Content.Server/GameObjects/Components/Mobs/State/DeadMobState.cs index 819ade09ac..26ca90cd14 100644 --- a/Content.Server/GameObjects/Components/Mobs/State/DeadMobState.cs +++ b/Content.Server/GameObjects/Components/Mobs/State/DeadMobState.cs @@ -26,11 +26,6 @@ namespace Content.Server.GameObjects.Components.Mobs.State status.ShowAlert(AlertType.HumanDead); } - if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlayComponent)) - { - overlayComponent.AddOverlay(SharedOverlayID.CircleMaskOverlay); - } - if (entity.TryGetComponent(out StunnableComponent stun)) { stun.CancelAll(); @@ -52,11 +47,6 @@ namespace Content.Server.GameObjects.Components.Mobs.State { physics.CanCollide = true; } - - if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlay)) - { - overlay.ClearOverlays(); - } } } } diff --git a/Content.Server/GameObjects/Components/Mobs/State/MobStateManager.cs b/Content.Server/GameObjects/Components/Mobs/State/MobStateManager.cs index 9e45c1395b..298d43bae1 100644 --- a/Content.Server/GameObjects/Components/Mobs/State/MobStateManager.cs +++ b/Content.Server/GameObjects/Components/Mobs/State/MobStateManager.cs @@ -8,15 +8,5 @@ namespace Content.Server.GameObjects.Components.Mobs.State [ComponentReference(typeof(IMobStateComponent))] public class MobStateComponent : SharedMobStateComponent { - public override void OnRemove() - { - // TODO: Might want to add an OnRemove() to IMobState since those are where these components are being used - if (Owner.TryGetComponent(out ServerOverlayEffectsComponent overlay)) - { - overlay.ClearOverlays(); - } - - base.OnRemove(); - } } } diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeContainerComponent.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeContainerComponent.cs index adf31160cf..4915b51958 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeContainerComponent.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeContainerComponent.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Collections.Generic; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Content.Server.GameObjects.Components.NodeContainer.Nodes; @@ -50,7 +51,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer } } - public override void HandleMessage(ComponentMessage message, IComponent component) + public override void HandleMessage(ComponentMessage message, IComponent? component) { base.HandleMessage(message, component); switch (message) diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/AMENodeGroup.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/AMENodeGroup.cs index 7e7edea5e6..113463ca47 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/AMENodeGroup.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/AMENodeGroup.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.Linq; using Content.Server.Explosions; @@ -24,12 +25,12 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups /// since any part connected to the node group can easily find the master. /// [ViewVariables] - private AMEControllerComponent _masterController; + private AMEControllerComponent? _masterController; [Dependency] private readonly IRobustRandom _random = default!; - public AMEControllerComponent MasterController => _masterController; + public AMEControllerComponent? MasterController => _masterController; private readonly List _cores = new(); @@ -52,20 +53,18 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups if (_masterController != null && _masterController?.Owner == node.Owner) { _masterController = null; } } - public void RefreshAMENodes(AMEControllerComponent controller) + public void RefreshAMENodes(AMEControllerComponent? controller) { if(_masterController == null && controller != null) { _masterController = controller; } - if (_cores != null) { - foreach (AMEShieldComponent core in _cores) - { - core.UnsetCore(); - } - _cores.Clear(); + foreach (AMEShieldComponent core in _cores) + { + core.UnsetCore(); } + _cores.Clear(); //Check each shield node to see if it meets core criteria foreach (Node node in Nodes) @@ -79,11 +78,12 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups .Select(entity => entity.TryGetComponent(out var adjshield) ? adjshield : null) .Where(adjshield => adjshield != null); - if (nodeNeighbors.Count() >= 8) { _cores.Add(shield); } + if (nodeNeighbors.Count() >= 8) + { + _cores.Add(shield); + } } - if (_cores == null) { return; } - foreach (AMEShieldComponent core in _cores) { core.SetCore(); diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/ApcNetNodeGroup.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/ApcNetNodeGroup.cs index 703f159162..d8ef14d799 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/ApcNetNodeGroup.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/ApcNetNodeGroup.cs @@ -1,6 +1,5 @@ -using System; +#nullable enable using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using Content.Server.GameObjects.Components.Power; using Content.Server.GameObjects.Components.Power.ApcNetComponents; @@ -58,7 +57,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups public void AddApc(ApcComponent apc) { - if (!apc.Owner.TryGetComponent(out BatteryComponent battery)) + if (!apc.Owner.TryGetComponent(out var battery)) { return; } diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/BaseNetConnectorNodeGroup.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/BaseNetConnectorNodeGroup.cs index c4b2bea708..5c0dacbb04 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/BaseNetConnectorNodeGroup.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/BaseNetConnectorNodeGroup.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Server.GameObjects.Components.Power; diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroup.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroup.cs index 6f6f18b381..a7b4e87099 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroup.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroup.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Robust.Shared.IoC; using Robust.Shared.Map; diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroupManager.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroupManager.cs index 203d65e98f..186c2d5cc9 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroupManager.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/INodeGroupManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups { diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/IPipeNet.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/IPipeNet.cs index e5e4a97066..a44f1ae476 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/IPipeNet.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/IPipeNet.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using Content.Server.Atmos; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Server.GameObjects.EntitySystems; @@ -27,9 +28,9 @@ namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups [ViewVariables] private readonly List _pipes = new(); - [ViewVariables] private AtmosphereSystem _atmosphereSystem; + [ViewVariables] private AtmosphereSystem? _atmosphereSystem; - [ViewVariables] private IGridAtmosphereComponent GridAtmos => _atmosphereSystem.GetGridAtmosphere(GridId); + [ViewVariables] private IGridAtmosphereComponent? GridAtmos => _atmosphereSystem?.GetGridAtmosphere(GridId); public override void Initialize(Node sourceNode) { diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/NodeGroupAttribute.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/NodeGroupAttribute.cs index 5f47956656..6fd7ae37c6 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/NodeGroupAttribute.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/NodeGroupAttribute.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; namespace Content.Server.GameObjects.Components.NodeContainer.NodeGroups { diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/NodeGroupFactory.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/NodeGroupFactory.cs index 8f1aba5b74..f39d08a1cf 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/NodeGroupFactory.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/NodeGroupFactory.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable + using System; using System.Collections.Generic; using System.Reflection; using Content.Server.GameObjects.Components.NodeContainer.Nodes; diff --git a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/PowerNetNodeGroup.cs b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/PowerNetNodeGroup.cs index 59ff48ef1b..933eeb34af 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/PowerNetNodeGroup.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/NodeGroups/PowerNetNodeGroup.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.Diagnostics; using Content.Server.GameObjects.Components.Power.PowerNetComponents; diff --git a/Content.Server/GameObjects/Components/NodeContainer/Nodes/AdjacentNode.cs b/Content.Server/GameObjects/Components/NodeContainer/Nodes/AdjacentNode.cs index 3badc4fe7f..4e1735ac2e 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/Nodes/AdjacentNode.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/Nodes/AdjacentNode.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Collections.Generic; using Robust.Shared.GameObjects.Components.Transform; diff --git a/Content.Server/GameObjects/Components/NodeContainer/Nodes/Node.cs b/Content.Server/GameObjects/Components/NodeContainer/Nodes/Node.cs index 09c45000df..8e784963cb 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/Nodes/Node.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/Nodes/Node.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -29,7 +30,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes private INodeGroup _nodeGroup = BaseNodeGroup.NullGroup; [ViewVariables] - public IEntity Owner { get; private set; } + public IEntity Owner { get; private set; } = default!; [ViewVariables] private bool _needsGroup = true; @@ -46,8 +47,6 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes /// private bool _deleting = false; - private INodeGroupFactory _nodeGroupFactory; - public virtual void ExposeData(ObjectSerializer serializer) { serializer.DataField(this, x => x.NodeGroupID, "nodeGroupID", NodeGroupID.Default); @@ -56,7 +55,6 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes public virtual void Initialize(IEntity owner) { Owner = owner; - _nodeGroupFactory = IoCManager.Resolve(); } public void OnContainerStartup() @@ -163,7 +161,7 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes private INodeGroup MakeNewGroup() { - return _nodeGroupFactory.MakeNodeGroup(this); + return IoCManager.Resolve().MakeNodeGroup(this); } } } diff --git a/Content.Server/GameObjects/Components/Nutrition/DrinkComponent.cs b/Content.Server/GameObjects/Components/Nutrition/DrinkComponent.cs index 6ea6074a46..cd41d3f2c5 100644 --- a/Content.Server/GameObjects/Components/Nutrition/DrinkComponent.cs +++ b/Content.Server/GameObjects/Components/Nutrition/DrinkComponent.cs @@ -3,11 +3,9 @@ using System.Threading.Tasks; using Content.Server.GameObjects.Components.Body.Behavior; using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Fluids; -using Content.Server.GameObjects.EntitySystems; using Content.Shared.Audio; using Content.Shared.Chemistry; using Content.Shared.GameObjects.Components.Body; -using Content.Shared.GameObjects.Components.Body.Mechanism; using Content.Shared.GameObjects.Components.Nutrition; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; @@ -75,7 +73,7 @@ namespace Content.Server.GameObjects.Components.Nutrition _contents = Owner.AddComponent(); } - _contents.Capabilities = SolutionContainerCaps.AddTo | SolutionContainerCaps.RemoveFrom; + _contents.Capabilities = SolutionContainerCaps.Refillable | SolutionContainerCaps.Drainable; Opened = _defaultToOpened; UpdateAppearance(); } @@ -113,9 +111,10 @@ namespace Content.Server.GameObjects.Components.Nutrition } //Force feeding a drink to someone. - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { TryUseDrink(eventArgs.Target, forced: true); + return true; } public void Examine(FormattedMessage message, bool inDetailsRange) @@ -131,7 +130,7 @@ namespace Content.Server.GameObjects.Components.Nutrition private bool TryUseDrink(IEntity target, bool forced = false) { - if (target == null || !_contents.CanRemoveSolutions) + if (target == null || !_contents.CanDrain) { return false; } @@ -181,11 +180,7 @@ namespace Content.Server.GameObjects.Components.Nutrition // TODO: Account for partial transfer. - foreach (var (reagentId, quantity) in split.Contents) - { - if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent)) continue; - split.RemoveReagent(reagentId, reagent.ReactionEntity(target, ReactionMethod.Ingestion, quantity)); - } + split.DoEntityReaction(target, ReactionMethod.Ingestion); firstStomach.TryTransferSolution(split); diff --git a/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs b/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs index 94fef359b0..0cb8436e11 100644 --- a/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs +++ b/Content.Server/GameObjects/Components/Nutrition/FoodComponent.cs @@ -100,14 +100,15 @@ namespace Content.Server.GameObjects.Components.Nutrition } // Feeding someone else - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (eventArgs.Target == null) { - return; + return false; } TryUseFood(eventArgs.User, eventArgs.Target); + return true; } public virtual bool TryUseFood(IEntity? user, IEntity? target, UtensilComponent? utensilUsed = null) @@ -183,11 +184,7 @@ namespace Content.Server.GameObjects.Components.Nutrition // TODO: Account for partial transfer. - foreach (var (reagentId, quantity) in split.Contents) - { - if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype reagent)) continue; - split.RemoveReagent(reagentId, reagent.ReactionEntity(trueTarget, ReactionMethod.Ingestion, quantity)); - } + split.DoEntityReaction(trueTarget, ReactionMethod.Ingestion); firstStomach.TryTransferSolution(split); diff --git a/Content.Server/GameObjects/Components/Observer/GhostComponent.cs b/Content.Server/GameObjects/Components/Observer/GhostComponent.cs index 8fd45b1bdc..15b909435b 100644 --- a/Content.Server/GameObjects/Components/Observer/GhostComponent.cs +++ b/Content.Server/GameObjects/Components/Observer/GhostComponent.cs @@ -144,7 +144,7 @@ namespace Content.Server.GameObjects.Components.Observer private List FindWaypoints() { var comp = IoCManager.Resolve(); - return comp.EntityQuery().ToList(); + return comp.EntityQuery(true).ToList(); } public void Examine(FormattedMessage message, bool inDetailsRange) diff --git a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs index 5ee0518c51..5d0862189c 100644 --- a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs +++ b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs @@ -135,12 +135,20 @@ namespace Content.Server.GameObjects.Components.PDA case PDAUplinkBuyListingMessage buyMsg: { - if (!_uplinkManager.TryPurchaseItem(_syndicateUplinkAccount, buyMsg.ItemId)) + if (message.Session.AttachedEntity == null) + break; + + if (!_uplinkManager.TryPurchaseItem(_syndicateUplinkAccount, buyMsg.ItemId, + message.Session.AttachedEntity.Transform.Coordinates, out var entity)) { SendNetworkMessage(new PDAUplinkInsufficientFundsMessage(), message.Session.ConnectedClient); break; } + HandsComponent.PutInHandOrDropStatic( + message.Session.AttachedEntity, + entity.GetComponent()); + SendNetworkMessage(new PDAUplinkBuySuccessMessage(), message.Session.ConnectedClient); break; } diff --git a/Content.Server/GameObjects/Components/Portal/TeleporterComponent.cs b/Content.Server/GameObjects/Components/Portal/TeleporterComponent.cs index f53d4b8f1d..b92632aa3b 100644 --- a/Content.Server/GameObjects/Components/Portal/TeleporterComponent.cs +++ b/Content.Server/GameObjects/Components/Portal/TeleporterComponent.cs @@ -23,7 +23,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Portal { [RegisterComponent] - public class TeleporterComponent : Component, IAfterInteract + public class TeleporterComponent : Component, IAfterInteract { [Dependency] private readonly IServerEntityManager _serverEntityManager = default!; [Dependency] private readonly IRobustRandom _spreadRandom = default!; @@ -78,7 +78,7 @@ namespace Content.Server.GameObjects.Components.Portal _state = newState; } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (_teleporterType == TeleporterType.Directed) { @@ -89,6 +89,8 @@ namespace Content.Server.GameObjects.Components.Portal { TryRandomTeleport(eventArgs.User); } + + return true; } public void TryDirectedTeleport(IEntity user, MapCoordinates mapCoords) diff --git a/Content.Server/GameObjects/Components/Power/AME/AMEFuelContainerComponent.cs b/Content.Server/GameObjects/Components/Power/AME/AMEFuelContainerComponent.cs index 98e336608e..6367ac9002 100644 --- a/Content.Server/GameObjects/Components/Power/AME/AMEFuelContainerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/AME/AMEFuelContainerComponent.cs @@ -1,4 +1,5 @@ -using Robust.Shared.GameObjects; +#nullable enable +using Robust.Shared.GameObjects; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Power.AME diff --git a/Content.Server/GameObjects/Components/Power/AME/AMEPartComponent.cs b/Content.Server/GameObjects/Components/Power/AME/AMEPartComponent.cs index 776dfb6309..5817fe5882 100644 --- a/Content.Server/GameObjects/Components/Power/AME/AMEPartComponent.cs +++ b/Content.Server/GameObjects/Components/Power/AME/AMEPartComponent.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Threading.Tasks; using System.Linq; using Content.Server.GameObjects.Components.Interactable; @@ -28,14 +29,13 @@ namespace Content.Server.GameObjects.Components.Power.AME async Task IInteractUsing.InteractUsing(InteractUsingEventArgs args) { - if (!args.User.TryGetComponent(out IHandsComponent hands)) + if (!args.User.TryGetComponent(out var hands)) { Owner.PopupMessage(args.User, Loc.GetString("You have no hands.")); return true; } - var activeHandEntity = hands.GetActiveHand.Owner; - if (activeHandEntity.TryGetComponent(out var multitool) && multitool.Qualities == ToolQuality.Multitool) + if (args.Using.TryGetComponent(out var multitool) && multitool.Qualities == ToolQuality.Multitool) { var mapGrid = _mapManager.GetGrid(args.ClickLocation.GetGridId(_serverEntityManager)); diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs index 4edd7f3df8..c2a2b6b431 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/ApcComponent.cs @@ -179,6 +179,10 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents return ApcExternalPowerState.None; } var consumer = batteryStorage.Consumer; + + if (consumer == null) + return ApcExternalPowerState.None; + if (consumer.ReceivedPower == 0 && consumer.DrawRate != 0) { return ApcExternalPowerState.None; diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/BaseApcNetComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/BaseApcNetComponent.cs index b8f6c13d15..d13f3fecfe 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/BaseApcNetComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/BaseApcNetComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; +#nullable enable +using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; namespace Content.Server.GameObjects.Components.Power.ApcNetComponents { diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerProviderComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerProviderComponent.cs index f1c14043dd..96c2b5e9e9 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerProviderComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerProviderComponent.cs @@ -1,6 +1,6 @@ +#nullable enable using System; using System.Collections.Generic; -using System.Diagnostics; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; @@ -20,7 +20,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents void UpdateReceiverLoad(int oldLoad, int newLoad); - public IEntity ProviderOwner { get; } + public IEntity? ProviderOwner { get; } public bool HasApcPower { get; } } @@ -172,7 +172,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents public void AddReceiver(PowerReceiverComponent receiver) { } public void RemoveReceiver(PowerReceiverComponent receiver) { } public void UpdateReceiverLoad(int oldLoad, int newLoad) { } - public IEntity ProviderOwner => default; + public IEntity? ProviderOwner => default; } } } diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/EmergencyLightComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/EmergencyLightComponent.cs index bf3044366b..55684c95a7 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/EmergencyLightComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/EmergencyLightComponent.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Collections.Generic; using Content.Shared.GameObjects.EntitySystems; @@ -63,7 +64,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece /// public void UpdateState() { - if (!Owner.TryGetComponent(out PowerReceiverComponent receiver)) + if (!Owner.TryGetComponent(out PowerReceiverComponent? receiver)) { return; } @@ -83,7 +84,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece public void OnUpdate(float frameTime) { - if (Owner.Deleted || !Owner.TryGetComponent(out BatteryComponent battery)) + if (Owner.Deleted || !Owner.TryGetComponent(out BatteryComponent? battery)) { return; } @@ -101,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece battery.CurrentCharge += _chargingWattage * frameTime * _chargingEfficiency; if (battery.BatteryState == BatteryState.Full) { - if (Owner.TryGetComponent(out PowerReceiverComponent receiver)) + if (Owner.TryGetComponent(out PowerReceiverComponent? receiver)) { receiver.Load = 1; } @@ -113,12 +114,12 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece private void TurnOff() { - if (Owner.TryGetComponent(out SpriteComponent sprite)) + if (Owner.TryGetComponent(out SpriteComponent? sprite)) { sprite.LayerSetState(0, "emergency_light_off"); } - if (Owner.TryGetComponent(out PointLightComponent light)) + if (Owner.TryGetComponent(out PointLightComponent? light)) { light.Enabled = false; } @@ -126,18 +127,18 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece private void TurnOn() { - if (Owner.TryGetComponent(out SpriteComponent sprite)) + if (Owner.TryGetComponent(out SpriteComponent? sprite)) { sprite.LayerSetState(0, "emergency_light_on"); } - if (Owner.TryGetComponent(out PointLightComponent light)) + if (Owner.TryGetComponent(out PointLightComponent? light)) { light.Enabled = true; } } - public override void HandleMessage(ComponentMessage message, IComponent component) + public override void HandleMessage(ComponentMessage message, IComponent? component) { base.HandleMessage(message, component); switch (message) diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs index 4bcc5e4b21..a485289f99 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/LightBulbComponent.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using Content.Shared.Audio; using Content.Shared.GameObjects.EntitySystems; @@ -41,8 +42,8 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece /// /// Invoked whenever the state of the light bulb changes. /// - public event EventHandler OnLightBulbStateChange; - public event EventHandler OnLightColorChange; + public event EventHandler? OnLightBulbStateChange; + public event EventHandler? OnLightColorChange; private Color _color = Color.White; @@ -106,7 +107,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece public void UpdateColor() { - if (!Owner.TryGetComponent(out SpriteComponent sprite)) + if (!Owner.TryGetComponent(out SpriteComponent? sprite)) { return; } diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PowerCellChargerComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PowerCellChargerComponent.cs index 8c71ff18c0..ad205fac64 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PowerCellChargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PowerCellChargerComponent.cs @@ -1,4 +1,5 @@ -using Content.Shared.Interfaces.GameObjects.Components; +#nullable enable +using Content.Shared.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs index 9e99e35cb3..c299af1b1f 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/PoweredLightComponent.cs @@ -1,3 +1,4 @@ +#nullable enable using System; using System.Threading.Tasks; using Content.Server.GameObjects.Components.GUI; @@ -41,16 +42,16 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece [ViewVariables] private bool _on; private LightBulbType BulbType = LightBulbType.Tube; - [ViewVariables] private ContainerSlot _lightBulbContainer; + [ViewVariables] private ContainerSlot _lightBulbContainer = default!; [ViewVariables] - private LightBulbComponent LightBulb + private LightBulbComponent? LightBulb { get { if (_lightBulbContainer.ContainedEntity == null) return null; - _lightBulbContainer.ContainedEntity.TryGetComponent(out LightBulbComponent bulb); + _lightBulbContainer.ContainedEntity.TryGetComponent(out LightBulbComponent? bulb); return bulb; } @@ -65,12 +66,12 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) { - if (!eventArgs.User.TryGetComponent(out IDamageableComponent damageableComponent)) + if (!eventArgs.User.TryGetComponent(out IDamageableComponent? damageableComponent)) { Eject(); return false; } - if(eventArgs.User.TryGetComponent(out HeatResistanceComponent heatResistanceComponent)) + if(eventArgs.User.TryGetComponent(out HeatResistanceComponent? heatResistanceComponent)) { if(CanBurn(heatResistanceComponent.GetHeatResistance())) { @@ -83,6 +84,9 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece bool CanBurn(int heatResistance) { + if (LightBulb == null) + return false; + return _lightState && heatResistance < LightBulb.BurningTemperature; } @@ -108,7 +112,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece private bool InsertBulb(IEntity bulb) { if (LightBulb != null) return false; - if (!bulb.TryGetComponent(out LightBulbComponent lightBulb)) return false; + if (!bulb.TryGetComponent(out LightBulbComponent? lightBulb)) return false; if (lightBulb.Type != BulbType) return false; var inserted = _lightBulbContainer.Insert(bulb); @@ -135,7 +139,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece if (!_lightBulbContainer.Remove(bulb.Owner)) return; - if (!user.TryGetComponent(out HandsComponent hands) + if (!user.TryGetComponent(out HandsComponent? hands) || !hands.PutInHand(bulb.Owner.GetComponent())) bulb.Owner.Transform.Coordinates = user.Transform.Coordinates; } @@ -149,7 +153,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece /// /// For attaching UpdateLight() to events. /// - public void UpdateLight(object sender, EventArgs e) + public void UpdateLight(object? sender, EventArgs? e) { UpdateLight(); } @@ -212,7 +216,7 @@ namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerRece _lightBulbContainer = ContainerManagerComponent.Ensure("light_bulb", Owner); } - public override void HandleMessage(ComponentMessage message, IComponent component) + public override void HandleMessage(ComponentMessage message, IComponent? component) { base.HandleMessage(message, component); switch (message) diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/WeaponCapacitorChargerComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/WeaponCapacitorChargerComponent.cs index e54cf3578f..5d03d47973 100644 --- a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/WeaponCapacitorChargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/WeaponCapacitorChargerComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; +#nullable enable +using Content.Server.GameObjects.Components.Weapon.Ranged.Barrels; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; diff --git a/Content.Server/GameObjects/Components/Power/BaseNetConnectorComponent.cs b/Content.Server/GameObjects/Components/Power/BaseNetConnectorComponent.cs index fc2148f85f..44a5310c98 100644 --- a/Content.Server/GameObjects/Components/Power/BaseNetConnectorComponent.cs +++ b/Content.Server/GameObjects/Components/Power/BaseNetConnectorComponent.cs @@ -1,4 +1,6 @@ -using System.Linq; +#nullable enable +using System.Diagnostics.CodeAnalysis; +using System.Linq; using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Robust.Shared.GameObjects; @@ -15,7 +17,7 @@ namespace Content.Server.GameObjects.Components.Power [ViewVariables] public TNetType Net { get => _net; set => SetNet(value); } - private TNetType _net; + private TNetType _net = default!; //set in OnAdd() protected abstract TNetType NullNet { get; } @@ -68,7 +70,7 @@ namespace Content.Server.GameObjects.Components.Power protected abstract void RemoveSelfFromNet(TNetType net); - private bool TryFindNet(out TNetType foundNet) + private bool TryFindNet([NotNullWhen(true)] out TNetType? foundNet) { if (Owner.TryGetComponent(out var container)) { diff --git a/Content.Server/GameObjects/Components/Power/BatteryComponent.cs b/Content.Server/GameObjects/Components/Power/BatteryComponent.cs index 887f9420f0..c7dce26485 100644 --- a/Content.Server/GameObjects/Components/Power/BatteryComponent.cs +++ b/Content.Server/GameObjects/Components/Power/BatteryComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using Robust.Shared.GameObjects; using Robust.Shared.Maths; using Robust.Shared.Serialization; @@ -53,7 +54,7 @@ namespace Content.Server.GameObjects.Components.Power /// /// If sufficient charge is avaiable on the battery, use it. Otherwise, don't. /// - public bool TryUseCharge(float chargeToUse) + public virtual bool TryUseCharge(float chargeToUse) { if (chargeToUse >= CurrentCharge) { @@ -66,7 +67,7 @@ namespace Content.Server.GameObjects.Components.Power } } - public float UseCharge(float toDeduct) + public virtual float UseCharge(float toDeduct) { var chargeChangedBy = Math.Min(CurrentCharge, toDeduct); CurrentCharge -= chargeChangedBy; diff --git a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs index 8a16a7c7da..8806e69272 100644 --- a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs @@ -1,4 +1,8 @@ -using Content.Shared.GameObjects.Components.Power; +#nullable enable +using System; +using Content.Server.Explosions; +using Content.Server.GameObjects.Components.Chemistry; +using Content.Shared.GameObjects.Components.Power; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Utility; using Robust.Server.GameObjects; @@ -16,13 +20,15 @@ namespace Content.Server.GameObjects.Components.Power /// [RegisterComponent] [ComponentReference(typeof(BatteryComponent))] - public class PowerCellComponent : BatteryComponent, IExamine + public class PowerCellComponent : BatteryComponent, IExamine, ISolutionChange { public override string Name => "PowerCell"; [ViewVariables] public PowerCellSize CellSize => _cellSize; private PowerCellSize _cellSize = PowerCellSize.Small; + [ViewVariables] public bool IsRigged { get; private set; } + public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); @@ -42,9 +48,41 @@ namespace Content.Server.GameObjects.Components.Power UpdateVisuals(); } + public override bool TryUseCharge(float chargeToUse) + { + if (IsRigged) + { + Explode(); + return false; + } + + return base.TryUseCharge(chargeToUse); + } + + public override float UseCharge(float toDeduct) + { + if (IsRigged) + { + Explode(); + return 0; + } + + return base.UseCharge(toDeduct); + } + + private void Explode() + { + var heavy = (int) Math.Ceiling(Math.Sqrt(CurrentCharge) / 60); + var light = (int) Math.Ceiling(Math.Sqrt(CurrentCharge) / 30); + + CurrentCharge = 0; + Owner.SpawnExplosion(0, heavy, light, light*2); + Owner.Delete(); + } + private void UpdateVisuals() { - if (Owner.TryGetComponent(out AppearanceComponent appearance)) + if (Owner.TryGetComponent(out AppearanceComponent? appearance)) { appearance.SetData(PowerCellVisuals.ChargeLevel, GetLevel(CurrentCharge / MaxCharge)); } @@ -57,11 +95,18 @@ namespace Content.Server.GameObjects.Components.Power void IExamine.Examine(FormattedMessage message, bool inDetailsRange) { - if(inDetailsRange) + if (inDetailsRange) { message.AddMarkup(Loc.GetString($"The charge indicator reads {CurrentCharge / MaxCharge * 100:F0} %.")); } } + + void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) + { + IsRigged = Owner.TryGetComponent(out SolutionContainerComponent? solution) + && solution.Solution.ContainsReagent("chem.Phoron", out var phoron) + && phoron >= 5; + } } public enum PowerCellSize diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BasePowerNetComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BasePowerNetComponent.cs index 3482d225a0..a80fc4ed9d 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BasePowerNetComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BasePowerNetComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; +#nullable enable +using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; namespace Content.Server.GameObjects.Components.Power.PowerNetComponents { diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryDischargerComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryDischargerComponent.cs index 65eaafb285..332b2abcbb 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryDischargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryDischargerComponent.cs @@ -1,6 +1,9 @@ -using Robust.Shared.GameObjects; +#nullable enable +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.ComponentDependencies; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; +using System; namespace Content.Server.GameObjects.Components.Power.PowerNetComponents { @@ -13,10 +16,10 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents public override string Name => "BatteryDischarger"; [ViewVariables] - private BatteryComponent _battery; + [ComponentDependency] private BatteryComponent? _battery = default!; [ViewVariables] - private PowerSupplierComponent _supplier; + [ComponentDependency] private PowerSupplierComponent? _supplier = default!; [ViewVariables(VVAccess.ReadWrite)] public int ActiveSupplyRate { get => _activeSupplyRate; set => SetActiveSupplyRate(value); } @@ -31,14 +34,16 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents public override void Initialize() { base.Initialize(); - - _battery = Owner.EnsureComponent(); - _supplier = Owner.EnsureComponent(); + Owner.EnsureComponentWarn(); + Owner.EnsureComponentWarn(); UpdateSupplyRate(); } public void Update(float frameTime) { + if (_battery == null) + return; + //Simplified implementation - if the battery is empty, and charge is being added to the battery //at a lower rate that this is using it, the charge is used without creating power supply. _battery.CurrentCharge -= ActiveSupplyRate * frameTime; @@ -47,6 +52,9 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents private void UpdateSupplyRate() { + if (_battery == null) + return; + if (_battery.BatteryState == BatteryState.Empty) { SetSupplierSupplyRate(0); @@ -59,6 +67,9 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents private void SetSupplierSupplyRate(int newSupplierSupplyRate) { + if (_supplier == null) + return; + if (_supplier.SupplyRate != newSupplierSupplyRate) { _supplier.SupplyRate = newSupplierSupplyRate; diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryStorageComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryStorageComponent.cs index 416ac17a5c..e87ccb96f8 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/BatteryStorageComponent.cs @@ -1,4 +1,6 @@ -using Robust.Shared.GameObjects; +#nullable enable +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.ComponentDependencies; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -17,10 +19,12 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents private int _activeDrawRate; [ViewVariables] - private BatteryComponent _battery; + [ComponentDependency] private BatteryComponent? _battery = default!; [ViewVariables] - public PowerConsumerComponent Consumer { get; private set; } + public PowerConsumerComponent? Consumer => _consumer; + + [ComponentDependency] private PowerConsumerComponent? _consumer = default!; public override void ExposeData(ObjectSerializer serializer) { @@ -31,21 +35,26 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents public override void Initialize() { base.Initialize(); - - _battery = Owner.EnsureComponent(); - Consumer = Owner.EnsureComponent(); + Owner.EnsureComponentWarn(); + Owner.EnsureComponentWarn(); UpdateDrawRate(); } public void Update(float frameTime) { + if (_consumer == null || _battery == null) + return; + //Simplified implementation - If a frame adds more power to a partially full battery than it can hold, the power is lost. - _battery.CurrentCharge += Consumer.ReceivedPower * frameTime; + _battery.CurrentCharge += _consumer.ReceivedPower * frameTime; UpdateDrawRate(); } private void UpdateDrawRate() { + if (_battery == null) + return; + if (_battery.BatteryState == BatteryState.Full) { SetConsumerDraw(0); @@ -58,9 +67,12 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents private void SetConsumerDraw(int newConsumerDrawRate) { - if (Consumer.DrawRate != newConsumerDrawRate) + if (_consumer == null) + return; + + if (_consumer.DrawRate != newConsumerDrawRate) { - Consumer.DrawRate = newConsumerDrawRate; + _consumer.DrawRate = newConsumerDrawRate; } } diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/IPowerNetManager.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/IPowerNetManager.cs index 808f3f564b..2f8b8230b2 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/IPowerNetManager.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/IPowerNetManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; namespace Content.Server.GameObjects.Components.Power.PowerNetComponents diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/PowerConsumerComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/PowerConsumerComponent.cs index 54dd3437d2..c6118c87f3 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/PowerConsumerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/PowerConsumerComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Diagnostics; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Robust.Shared.GameObjects; @@ -34,7 +35,7 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents public int ReceivedPower { get => _receivedPower; set => SetReceivedPower(value); } private int _receivedPower; - public event EventHandler OnReceivedPowerChanged; + public event EventHandler? OnReceivedPowerChanged; public override void ExposeData(ObjectSerializer serializer) { diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/PowerSupplierComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/PowerSupplierComponent.cs index b843c1bee7..02047fe80c 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/PowerSupplierComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/PowerSupplierComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; +#nullable enable +using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/RadiationCollectorComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/RadiationCollectorComponent.cs index 066b9b97b9..e93c3ffe10 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/RadiationCollectorComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/RadiationCollectorComponent.cs @@ -1,20 +1,18 @@ +#nullable enable using System; -using System.Threading; using Content.Server.Utility; using Content.Shared.GameObjects.Components; -using Content.Shared.GameObjects.Components.Doors; using Content.Shared.GameObjects.Components.Singularity; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.ComponentDependencies; using Robust.Shared.GameObjects.Components; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Localization; -using Robust.Shared.Log; -using Timer = Robust.Shared.Timers.Timer; namespace Content.Server.GameObjects.Components.Power.PowerNetComponents { @@ -27,19 +25,9 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents private bool _enabled; private TimeSpan _coolDownEnd; - private PhysicsComponent _collidableComponent; + [ComponentDependency] private readonly PhysicsComponent? _collidableComponent = default!; - public override void Initialize() - { - base.Initialize(); - if (!Owner.TryGetComponent(out _collidableComponent)) - { - Logger.Error("RadiationCollectorComponent created with no CollidableComponent"); - return; - } - } - - public override void HandleMessage(ComponentMessage message, IComponent component) + public override void HandleMessage(ComponentMessage message, IComponent? component) { base.HandleMessage(message, component); switch (message) @@ -52,7 +40,8 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents private void OnAnchoredChanged() { - if(_collidableComponent.Anchored) Owner.SnapToGrid(); + if(_collidableComponent != null && _collidableComponent.Anchored) + Owner.SnapToGrid(); } bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs) @@ -99,7 +88,7 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents protected void SetAppearance(RadiationCollectorVisualState state) { - if (Owner.TryGetComponent(out AppearanceComponent appearance)) + if (Owner.TryGetComponent(out var appearance)) { appearance.SetData(RadiationCollectorVisuals.VisualState, state); } diff --git a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarPanelComponent.cs b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarPanelComponent.cs index 6a3f46efcc..89fca08196 100644 --- a/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarPanelComponent.cs +++ b/Content.Server/GameObjects/Components/Power/PowerNetComponents/SolarPanelComponent.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems; using Robust.Server.GameObjects; @@ -62,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents private void UpdateSupply() { - if (Owner.TryGetComponent(out PowerSupplierComponent supplier)) + if (Owner.TryGetComponent(out var supplier)) { supplier.SupplyRate = (int) (_maxSupply * _coverage); } @@ -72,7 +73,7 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents { base.Initialize(); - Owner.EnsureComponentWarn(out PowerSupplierComponent _); + Owner.EnsureComponentWarn(); UpdateSupply(); } @@ -86,7 +87,9 @@ namespace Content.Server.GameObjects.Components.Power.PowerNetComponents public void OnBreak(BreakageEventArgs args) { - var sprite = Owner.GetComponent(); + if (!Owner.TryGetComponent(out var sprite)) + return; + sprite.LayerSetState(0, "broken"); MaxSupply = 0; } diff --git a/Content.Server/GameObjects/Components/Power/WireComponent.cs b/Content.Server/GameObjects/Components/Power/WireComponent.cs index 05f66be2b4..40352a73f8 100644 --- a/Content.Server/GameObjects/Components/Power/WireComponent.cs +++ b/Content.Server/GameObjects/Components/Power/WireComponent.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +#nullable enable +using System.Threading.Tasks; using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Stack; using Content.Shared.GameObjects.Components.Interactable; @@ -18,7 +19,7 @@ namespace Content.Server.GameObjects.Components.Power public override string Name => "Wire"; [ViewVariables] - private string _wireDroppedOnCutPrototype; + private string? _wireDroppedOnCutPrototype; /// /// Checked by to determine if there is @@ -37,7 +38,10 @@ namespace Content.Server.GameObjects.Components.Power async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) { - if (!eventArgs.Using.TryGetComponent(out ToolComponent tool)) return false; + if (_wireDroppedOnCutPrototype == null) + return false; + + if (!eventArgs.Using.TryGetComponent(out var tool)) return false; if (!await tool.UseTool(eventArgs.User, Owner, 0.25f, ToolQuality.Cutting)) return false; Owner.Delete(); diff --git a/Content.Server/GameObjects/Components/Power/WirePlacerComponent.cs b/Content.Server/GameObjects/Components/Power/WirePlacerComponent.cs index 46348bea6a..e653160b5f 100644 --- a/Content.Server/GameObjects/Components/Power/WirePlacerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/WirePlacerComponent.cs @@ -1,7 +1,7 @@ -using Content.Server.GameObjects.Components.Stack; +#nullable enable +using Content.Server.GameObjects.Components.Stack; using Content.Shared.Interfaces.GameObjects.Components; using Content.Shared.Utility; -using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.Interfaces.Map; @@ -21,7 +21,7 @@ namespace Content.Server.GameObjects.Components.Power public override string Name => "WirePlacer"; [ViewVariables] - private string _wirePrototypeID; + private string? _wirePrototypeID; [ViewVariables] private WireType _blockingWireType; @@ -34,25 +34,29 @@ namespace Content.Server.GameObjects.Components.Power } /// - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { - if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) return; + if (_wirePrototypeID == null) + return true; + if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true)) + return true; if(!_mapManager.TryGetGrid(eventArgs.ClickLocation.GetGridId(Owner.EntityManager), out var grid)) - return; + return true; var snapPos = grid.SnapGridCellFor(eventArgs.ClickLocation, SnapGridOffset.Center); var snapCell = grid.GetSnapGridCell(snapPos, SnapGridOffset.Center); if(grid.GetTileRef(snapPos).Tile.IsEmpty) - return; + return true; foreach (var snapComp in snapCell) { if (snapComp.Owner.TryGetComponent(out var wire) && wire.WireType == _blockingWireType) { - return; + return true; } } - if (Owner.TryGetComponent(out StackComponent stack) && !stack.Use(1)) - return; + if (Owner.TryGetComponent(out var stack) && !stack.Use(1)) + return true; Owner.EntityManager.SpawnEntity(_wirePrototypeID, grid.GridTileToLocal(snapPos)); + return true; } } } diff --git a/Content.Server/GameObjects/Components/Suspicion/SuspicionRoleComponent.cs b/Content.Server/GameObjects/Components/Suspicion/SuspicionRoleComponent.cs index 641080e643..c436c06b12 100644 --- a/Content.Server/GameObjects/Components/Suspicion/SuspicionRoleComponent.cs +++ b/Content.Server/GameObjects/Components/Suspicion/SuspicionRoleComponent.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; using Content.Server.GameObjects.Components.Mobs; -using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.GameMode; using Content.Server.Mobs; using Content.Server.Mobs.Roles; using Content.Server.Mobs.Roles.Suspicion; diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs index f5b2f156bb..5749eeb1f3 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/FlashComponent.cs @@ -4,13 +4,17 @@ using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces; using Content.Shared.Interfaces.GameObjects.Components; +using Content.Shared.Network.NetMessages; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; +using Robust.Server.Interfaces.Player; +using Robust.Server.Interfaces.GameObjects; using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Timers; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Serialization; @@ -128,22 +132,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee } // TODO: Check if target can be flashed (e.g. things like sunglasses would block a flash) + // TODO: Merge with the code in FlashableComponent private void Flash(IEntity entity, IEntity user, int flashDuration) { - if (entity.TryGetComponent(out ServerOverlayEffectsComponent overlayEffectsComponent)) + if (entity.TryGetComponent(out FlashableComponent flashable)) { - if (!overlayEffectsComponent.TryModifyOverlay(nameof(SharedOverlayID.FlashOverlay), - overlay => - { - if (overlay.TryGetOverlayParameter(out var timed)) - { - timed.Length += flashDuration; - } - })) - { - var container = new OverlayContainer(SharedOverlayID.FlashOverlay, new TimedOverlayParameter(flashDuration)); - overlayEffectsComponent.AddOverlay(container); - } + flashable.Flash(flashDuration / 1000d); } if (entity.TryGetComponent(out StunnableComponent stunnableComponent)) diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs index 6fd87d0236..ccc1f99b0c 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/MeleeWeaponComponent.cs @@ -6,6 +6,7 @@ using Content.Shared.Damage; using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Items; using Content.Shared.Interfaces.GameObjects.Components; +using Content.Shared.Physics; using Robust.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; @@ -203,7 +204,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee for (var i = 0; i < increments; i++) { var castAngle = new Angle(baseAngle + increment * i); - var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), 23), Range, ignore).FirstOrDefault(); + var res = _physicsManager.IntersectRay(mapId, new CollisionRay(position, castAngle.ToVec(), (int) (CollisionGroup.Impassable|CollisionGroup.MobImpassable)), Range, ignore).FirstOrDefault(); if (res.HitEntity != null) { resSet.Add(res.HitEntity); diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/SpeedLoaderComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/SpeedLoaderComponent.cs index f674459c2a..5ddf430552 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/SpeedLoaderComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/SpeedLoaderComponent.cs @@ -146,11 +146,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition return entity; } - async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) + async Task IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs) { if (eventArgs.Target == null) { - return; + return false; } // This area is dirty but not sure of an easier way to do it besides add an interface or somethin @@ -203,6 +203,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition { UpdateAppearance(); } + + return true; } async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs index c6a7d7a178..eecee54097 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs @@ -169,7 +169,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels // Multiply the entity's damage / whatever by the percentage of charge the shot has. IEntity entity; var chargeChange = Math.Min(capacitor.CurrentCharge, _baseFireCost); - capacitor.UseCharge(chargeChange); + if (capacitor.UseCharge(chargeChange) < _lowerChargeLimit) + { + // Handling of funny exploding cells. + return null; + } var energyRatio = chargeChange / _baseFireCost; if (_ammoContainer.ContainedEntity != null) diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs index f1331d4e7e..7f554a5eed 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/ServerRangedWeaponComponent.cs @@ -161,9 +161,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged _lastFireTime = curTime; - if (ClumsyCheck && - user.HasComponent() && - _random.Prob(ClumsyExplodeChance)) + if (ClumsyCheck && ClumsyComponent.TryRollClumsy(user, ClumsyExplodeChance)) { var soundSystem = EntitySystem.Get(); soundSystem.PlayAtCoords("/Audio/Items/bikehorn.ogg", diff --git a/Content.Server/GameObjects/Components/WindowComponent.cs b/Content.Server/GameObjects/Components/WindowComponent.cs index 266f25e85d..669971fb6d 100644 --- a/Content.Server/GameObjects/Components/WindowComponent.cs +++ b/Content.Server/GameObjects/Components/WindowComponent.cs @@ -1,4 +1,4 @@ -#nullable enable +#nullable enable using System; using Content.Server.Utility; using Content.Shared.Audio; @@ -6,6 +6,7 @@ using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces.GameObjects.Components; +using Content.Server.GameObjects.Components.Destructible; using Content.Shared.Utility; using Robust.Server.GameObjects; using Robust.Server.GameObjects.EntitySystems; @@ -13,7 +14,6 @@ using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Localization; -using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Server.GameObjects.Components @@ -22,14 +22,6 @@ namespace Content.Server.GameObjects.Components [ComponentReference(typeof(SharedWindowComponent))] public class WindowComponent : SharedWindowComponent, IExamine, IInteractHand { - private int _maxDamage; - - public override void ExposeData(ObjectSerializer serializer) - { - base.ExposeData(serializer); - - serializer.DataField(ref _maxDamage, "maxDamage", 100); - } public override void HandleMessage(ComponentMessage message, IComponent? component) { @@ -50,18 +42,24 @@ namespace Content.Server.GameObjects.Components { if (Owner.TryGetComponent(out AppearanceComponent? appearance)) { - appearance.SetData(WindowVisuals.Damage, (float) currentDamage / _maxDamage); + if (Owner.TryGetComponent(out DestructibleComponent? destructible)) + { + var damageThreshold = destructible.LowestToHighestThresholds.FirstOrNull()?.Key; + if (damageThreshold == null) return; + appearance.SetData(WindowVisuals.Damage, (float) currentDamage / damageThreshold); + } } } void IExamine.Examine(FormattedMessage message, bool inDetailsRange) { var damage = Owner.GetComponentOrNull()?.TotalDamage; - if (damage == null) return; - var fraction = ((damage == 0 || _maxDamage == 0) + var damageThreshold = Owner.GetComponentOrNull()?.LowestToHighestThresholds.FirstOrNull()?.Key; + if (damage == null || damageThreshold == null) return; + var fraction = ((damage == 0 || damageThreshold == 0) ? 0f - : (float) damage / _maxDamage); - var level = Math.Min(ContentHelpers.RoundToLevels(fraction, 1, 7), 5); + : (float) damage / damageThreshold); + var level = Math.Min(ContentHelpers.RoundToLevels((double) fraction, 1, 7), 5); switch (level) { case 0: diff --git a/Content.Server/GameObjects/EntitySystems/AI/AiFactionTagSystem.cs b/Content.Server/GameObjects/EntitySystems/AI/AiFactionTagSystem.cs index dc83c30d67..acfb7c0277 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/AiFactionTagSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/AiFactionTagSystem.cs @@ -48,7 +48,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI yield break; } - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { if ((component.Factions & hostile) == 0) continue; diff --git a/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs b/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs index 36b56d93f3..d069a9a0f5 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/AiSystem.cs @@ -10,7 +10,6 @@ using Content.Shared.Administration; using Content.Shared.GameObjects.Components.Movement; using JetBrains.Annotations; using Robust.Server.AI; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; diff --git a/Content.Server/GameObjects/EntitySystems/AntimatterEngineSystem.cs b/Content.Server/GameObjects/EntitySystems/AntimatterEngineSystem.cs index 3f4576fb84..0c73f45322 100644 --- a/Content.Server/GameObjects/EntitySystems/AntimatterEngineSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AntimatterEngineSystem.cs @@ -15,7 +15,7 @@ namespace Content.Server.GameObjects.EntitySystems _accumulatedFrameTime += frameTime; if (_accumulatedFrameTime >= 10) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.OnUpdate(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs b/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs index 94b0c3adb6..8dad965d5e 100644 --- a/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs @@ -21,7 +21,7 @@ namespace Content.Server.GameObjects.EntitySystems if (_lastUpdate < UpdateDelay) return; // creadth: everything exposable by atmos should be updated as well - foreach (var atmosExposedComponent in EntityManager.ComponentManager.EntityQuery()) + foreach (var atmosExposedComponent in EntityManager.ComponentManager.EntityQuery(true)) { var tile = atmosExposedComponent.Owner.Transform.Coordinates.GetTileAtmosphere(EntityManager); if (tile == null) continue; diff --git a/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs b/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs index 2864d813b0..71b0856e99 100644 --- a/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs @@ -143,7 +143,7 @@ namespace Content.Server.GameObjects.EntitySystems { base.Update(frameTime); - foreach (var (mapGridComponent, gridAtmosphereComponent) in EntityManager.ComponentManager.EntityQuery()) + foreach (var (mapGridComponent, gridAtmosphereComponent) in EntityManager.ComponentManager.EntityQuery(true)) { if (_pauseManager.IsGridPaused(mapGridComponent.GridIndex)) continue; diff --git a/Content.Server/GameObjects/EntitySystems/BlockGameSystem.cs b/Content.Server/GameObjects/EntitySystems/BlockGameSystem.cs index 37a881d1bf..5ebfe7dc5c 100644 --- a/Content.Server/GameObjects/EntitySystems/BlockGameSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/BlockGameSystem.cs @@ -63,7 +63,7 @@ namespace Content.Server.GameObjects.EntitySystems public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.DoGameTick(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/CargoConsoleSystem.cs b/Content.Server/GameObjects/EntitySystems/CargoConsoleSystem.cs index ad6ffad73c..c30bd6052f 100644 --- a/Content.Server/GameObjects/EntitySystems/CargoConsoleSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/CargoConsoleSystem.cs @@ -180,7 +180,7 @@ namespace Content.Server.GameObjects.EntitySystems private void SyncComponentsWithId(int id) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { if (!comp.ConnectedToDatabase || comp.Database.Id != id) continue; diff --git a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs index dde99dbddd..40ee427b78 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs @@ -315,14 +315,7 @@ namespace Content.Server.GameObjects.EntitySystems.Click var item = hands.GetActiveHand?.Owner; - if (ActionBlockerSystem.CanChangeDirection(player)) - { - var diff = coordinates.ToMapPos(EntityManager) - playerTransform.MapPosition.Position; - if (diff.LengthSquared > 0.01f) - { - playerTransform.LocalRotation = new Angle(diff); - } - } + ClickFace(player, coordinates); if (!ActionBlockerSystem.CanInteract(player)) { @@ -399,6 +392,18 @@ namespace Content.Server.GameObjects.EntitySystems.Click } } + private void ClickFace(IEntity player, EntityCoordinates coordinates) + { + if (ActionBlockerSystem.CanChangeDirection(player)) + { + var diff = coordinates.ToMapPos(EntityManager) - player.Transform.MapPosition.Position; + if (diff.LengthSquared > 0.01f) + { + player.Transform.LocalRotation = new Angle(diff); + } + } + } + /// /// We didn't click on any entity, try doing an AfterInteract on the click location /// @@ -411,13 +416,8 @@ namespace Content.Server.GameObjects.EntitySystems.Click return; } - var afterInteracts = weapon.GetAllComponents().ToList(); var afterInteractEventArgs = new AfterInteractEventArgs(user, clickLocation, null, canReach); - - foreach (var afterInteract in afterInteracts) - { - await afterInteract.AfterInteract(afterInteractEventArgs); - } + await DoAfterInteract(weapon, afterInteractEventArgs); } /// @@ -460,13 +460,9 @@ namespace Content.Server.GameObjects.EntitySystems.Click } // If we aren't directly attacking the nearby object, lets see if our item has an after attack we can do - var afterAttacks = weapon.GetAllComponents().ToList(); var afterAttackEventArgs = new AfterInteractEventArgs(user, clickLocation, attacked, canReach: true); - foreach (var afterAttack in afterAttacks) - { - await afterAttack.AfterInteract(afterAttackEventArgs); - } + await DoAfterInteract(weapon, afterAttackEventArgs); } /// @@ -830,13 +826,21 @@ namespace Content.Server.GameObjects.EntitySystems.Click if (afterAtkMsg.Handled) return; - var afterAttacks = weapon.GetAllComponents().ToList(); + // See if we have a ranged attack interaction var afterAttackEventArgs = new AfterInteractEventArgs(user, clickLocation, attacked, canReach: false); + await DoAfterInteract(weapon, afterAttackEventArgs); + } + + private static async Task DoAfterInteract(IEntity weapon, AfterInteractEventArgs afterAttackEventArgs) + { + var afterAttacks = weapon.GetAllComponents().OrderByDescending(x => x.Priority).ToList(); - //See if we have a ranged attack interaction foreach (var afterAttack in afterAttacks) { - await afterAttack.AfterInteract(afterAttackEventArgs); + if (await afterAttack.AfterInteract(afterAttackEventArgs)) + { + return; + } } } @@ -850,6 +854,8 @@ namespace Content.Server.GameObjects.EntitySystems.Click return; } + ClickFace(player, coordinates); + if (!ActionBlockerSystem.CanAttack(player) || (!wideAttack && !player.InRangeUnobstructed(coordinates, ignoreInsideBlocker: true))) { diff --git a/Content.Server/GameObjects/EntitySystems/ClimbSystem.cs b/Content.Server/GameObjects/EntitySystems/ClimbSystem.cs index f4d5b0f6cf..7f0a0a3857 100644 --- a/Content.Server/GameObjects/EntitySystems/ClimbSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ClimbSystem.cs @@ -9,7 +9,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.Update(); } diff --git a/Content.Server/GameObjects/EntitySystems/CloningSystem.cs b/Content.Server/GameObjects/EntitySystems/CloningSystem.cs index f759a5d139..438d26269d 100644 --- a/Content.Server/GameObjects/EntitySystems/CloningSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/CloningSystem.cs @@ -11,7 +11,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.Update(frameTime); } @@ -23,7 +23,7 @@ namespace Content.Server.GameObjects.EntitySystems { if (!Minds.ContainsValue(mind)) { - Minds.Add(Minds.Count(), mind); + Minds.Add(Minds.Count, mind); } } diff --git a/Content.Server/GameObjects/EntitySystems/ConveyorSystem.cs b/Content.Server/GameObjects/EntitySystems/ConveyorSystem.cs index b692bdd1bd..30a61761bf 100644 --- a/Content.Server/GameObjects/EntitySystems/ConveyorSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ConveyorSystem.cs @@ -11,7 +11,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/DisposableSystem.cs b/Content.Server/GameObjects/EntitySystems/DisposableSystem.cs index 536f0dfda4..eef8d319e8 100644 --- a/Content.Server/GameObjects/EntitySystems/DisposableSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/DisposableSystem.cs @@ -10,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/DoAfter/DoAfterSystem.cs b/Content.Server/GameObjects/EntitySystems/DoAfter/DoAfterSystem.cs index 93dc9478bd..226d942b00 100644 --- a/Content.Server/GameObjects/EntitySystems/DoAfter/DoAfterSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/DoAfter/DoAfterSystem.cs @@ -17,10 +17,8 @@ namespace Content.Server.GameObjects.EntitySystems.DoAfter { base.Update(frameTime); - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { - if (comp.Owner.Paused) continue; - var cancelled = new List(0); var finished = new List(0); diff --git a/Content.Server/GameObjects/EntitySystems/ExpendableLightSystem.cs b/Content.Server/GameObjects/EntitySystems/ExpendableLightSystem.cs index 4feba72bb0..36c9c3ab87 100644 --- a/Content.Server/GameObjects/EntitySystems/ExpendableLightSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ExpendableLightSystem.cs @@ -9,7 +9,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var light in ComponentManager.EntityQuery()) + foreach (var light in ComponentManager.EntityQuery(true)) { light.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/GameMode/SuspicionEndTimerSystem.cs b/Content.Server/GameObjects/EntitySystems/GameMode/SuspicionEndTimerSystem.cs new file mode 100644 index 0000000000..9e46b5c3a3 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/GameMode/SuspicionEndTimerSystem.cs @@ -0,0 +1,82 @@ +using System; +using System.Linq; +using Content.Server.Interfaces.GameTicking; +using Content.Shared.GameObjects.EntitySystemMessages; +using Content.Shared.GameTicking; +using JetBrains.Annotations; +using Robust.Server.Interfaces.Player; +using Robust.Server.Player; +using Robust.Shared.Enums; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.Timing; +using Robust.Shared.IoC; + +#nullable enable + +namespace Content.Server.GameObjects.EntitySystems.GameMode +{ + [UsedImplicitly] + public sealed class SuspicionEndTimerSystem : EntitySystem, IResettingEntitySystem + { + [Dependency] private readonly IPlayerManager _playerManager = null!; + [Dependency] private readonly IGameTiming _timing = null!; + [Dependency] private readonly IGameTicker _gameTicker = null!; + + private TimeSpan? _endTime; + + public TimeSpan? EndTime + { + get => _endTime; + set + { + _endTime = value; + SendUpdateToAll(); + } + } + + public override void Initialize() + { + base.Initialize(); + + _playerManager.PlayerStatusChanged += PlayerManagerOnPlayerStatusChanged; + } + + public override void Shutdown() + { + base.Shutdown(); + + _playerManager.PlayerStatusChanged -= PlayerManagerOnPlayerStatusChanged; + } + + private void PlayerManagerOnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) + { + if (e.NewStatus == SessionStatus.InGame) + { + SendUpdateTimerMessage(e.Session); + } + } + + private void SendUpdateToAll() + { + foreach (var player in _playerManager.GetAllPlayers().Where(p => p.Status == SessionStatus.InGame)) + { + SendUpdateTimerMessage(player); + } + } + + private void SendUpdateTimerMessage(IPlayerSession player) + { + var msg = new SuspicionMessages.SetSuspicionEndTimerMessage + { + EndTime = EndTime + }; + + EntityNetworkManager.SendSystemNetworkMessage(msg, player.ConnectedClient); + } + + void IResettingEntitySystem.Reset() + { + EndTime = null; + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/SuspicionRoleSystem.cs b/Content.Server/GameObjects/EntitySystems/GameMode/SuspicionRoleSystem.cs similarity index 92% rename from Content.Server/GameObjects/EntitySystems/SuspicionRoleSystem.cs rename to Content.Server/GameObjects/EntitySystems/GameMode/SuspicionRoleSystem.cs index 7bfb191404..e805bab473 100644 --- a/Content.Server/GameObjects/EntitySystems/SuspicionRoleSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/GameMode/SuspicionRoleSystem.cs @@ -1,10 +1,10 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Content.Server.GameObjects.Components.Suspicion; using Content.Shared.GameTicking; using JetBrains.Annotations; using Robust.Shared.GameObjects.Systems; -namespace Content.Server.GameObjects.EntitySystems +namespace Content.Server.GameObjects.EntitySystems.GameMode { [UsedImplicitly] public class SuspicionRoleSystem : EntitySystem, IResettingEntitySystem diff --git a/Content.Server/GameObjects/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/GameObjects/EntitySystems/GasAnalyzerSystem.cs index cf452f4111..d0a65cfa6e 100644 --- a/Content.Server/GameObjects/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/GasAnalyzerSystem.cs @@ -9,7 +9,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var analyzer in ComponentManager.EntityQuery()) + foreach (var analyzer in ComponentManager.EntityQuery(true)) { analyzer.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/GasCanisterSystem.cs b/Content.Server/GameObjects/EntitySystems/GasCanisterSystem.cs index a9c74af4f7..b94b2fed60 100644 --- a/Content.Server/GameObjects/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/GasCanisterSystem.cs @@ -10,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs b/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs index fe88bc52f3..657e618c1f 100644 --- a/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs @@ -23,7 +23,7 @@ namespace Content.Server.GameObjects.EntitySystems if (_timer < Interval) return; _timer = 0f; - foreach (var gasTank in EntityManager.ComponentManager.EntityQuery()) + foreach (var gasTank in EntityManager.ComponentManager.EntityQuery(true)) { gasTank.Update(); } diff --git a/Content.Server/GameObjects/EntitySystems/GravitySystem.cs b/Content.Server/GameObjects/EntitySystems/GravitySystem.cs index 24f6057ba9..ca0b8572a5 100644 --- a/Content.Server/GameObjects/EntitySystems/GravitySystem.cs +++ b/Content.Server/GameObjects/EntitySystems/GravitySystem.cs @@ -36,7 +36,7 @@ namespace Content.Server.GameObjects.EntitySystems { _internalTimer += frameTime; var gridsWithGravity = new List(); - foreach (var generator in ComponentManager.EntityQuery()) + foreach (var generator in ComponentManager.EntityQuery(true)) { if (generator.NeedsUpdate) { diff --git a/Content.Server/GameObjects/EntitySystems/HandsSystem.cs b/Content.Server/GameObjects/EntitySystems/HandsSystem.cs index 471f9d369c..0450d0e459 100644 --- a/Content.Server/GameObjects/EntitySystems/HandsSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/HandsSystem.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.Items.Storage; @@ -216,7 +216,7 @@ namespace Content.Server.GameObjects.EntitySystems if (heldItem != null) { - storageComponent.PlayerInsertEntity(plyEnt); + storageComponent.PlayerInsertHeldEntity(plyEnt); } else { diff --git a/Content.Server/GameObjects/EntitySystems/HungerSystem.cs b/Content.Server/GameObjects/EntitySystems/HungerSystem.cs index bd8cd6a866..18a34dbae3 100644 --- a/Content.Server/GameObjects/EntitySystems/HungerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/HungerSystem.cs @@ -15,7 +15,7 @@ namespace Content.Server.GameObjects.EntitySystems if (_accumulatedFrameTime > 1) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.OnUpdate(_accumulatedFrameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs b/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs index 80a50a93b8..a62c9b2962 100644 --- a/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/InstrumentSystem.cs @@ -51,7 +51,7 @@ namespace Content.Server.GameObjects.EntitySystems { base.Update(frameTime); - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/LatheSystem.cs b/Content.Server/GameObjects/EntitySystems/LatheSystem.cs index 777c22c82c..7fc92095be 100644 --- a/Content.Server/GameObjects/EntitySystems/LatheSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/LatheSystem.cs @@ -9,7 +9,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { if (comp.Producing == false && comp.Queue.Count > 0) { diff --git a/Content.Server/GameObjects/EntitySystems/ListeningSystem.cs b/Content.Server/GameObjects/EntitySystems/ListeningSystem.cs index eb92727745..6b6a42a357 100644 --- a/Content.Server/GameObjects/EntitySystems/ListeningSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ListeningSystem.cs @@ -10,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems { public void PingListeners(IEntity source, string message) { - foreach (var listener in ComponentManager.EntityQuery()) + foreach (var listener in ComponentManager.EntityQuery(true)) { // TODO: Map Position distance if (listener.CanListen(message, source)) diff --git a/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs b/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs index 01d1cd20ac..d7f00b8437 100644 --- a/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs @@ -10,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/MetabolismSystem.cs b/Content.Server/GameObjects/EntitySystems/MetabolismSystem.cs index 7c33138ee6..80c6d099cf 100644 --- a/Content.Server/GameObjects/EntitySystems/MetabolismSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MetabolismSystem.cs @@ -11,7 +11,7 @@ namespace Content.Server.GameObjects.EntitySystems { base.Update(frameTime); - foreach (var metabolism in ComponentManager.EntityQuery()) + foreach (var metabolism in ComponentManager.EntityQuery(true)) { metabolism.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/MicrowaveSystem.cs b/Content.Server/GameObjects/EntitySystems/MicrowaveSystem.cs index a1ccba35ed..5e789493e2 100644 --- a/Content.Server/GameObjects/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MicrowaveSystem.cs @@ -10,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems public override void Update(float frameTime) { base.Update(frameTime); - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.OnUpdate(); } diff --git a/Content.Server/GameObjects/EntitySystems/MorgueSystem.cs b/Content.Server/GameObjects/EntitySystems/MorgueSystem.cs index bbb18adca2..0692438de1 100644 --- a/Content.Server/GameObjects/EntitySystems/MorgueSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MorgueSystem.cs @@ -16,7 +16,7 @@ namespace Content.Server.GameObjects.EntitySystems if (_accumulatedFrameTime >= 10) { - foreach (var morgue in ComponentManager.EntityQuery()) + foreach (var morgue in ComponentManager.EntityQuery(true)) { morgue.Update(); } diff --git a/Content.Server/GameObjects/EntitySystems/PlantSystem.cs b/Content.Server/GameObjects/EntitySystems/PlantSystem.cs index d2e776d6f4..5b43f9d1a0 100644 --- a/Content.Server/GameObjects/EntitySystems/PlantSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/PlantSystem.cs @@ -70,7 +70,7 @@ namespace Content.Server.GameObjects.EntitySystems _timer = 0f; - foreach (var plantHolder in _componentManager.EntityQuery()) + foreach (var plantHolder in _componentManager.EntityQuery(true)) { plantHolder.Update(); } diff --git a/Content.Server/GameObjects/EntitySystems/PointingSystem.cs b/Content.Server/GameObjects/EntitySystems/PointingSystem.cs index 0569600e7b..797171d780 100644 --- a/Content.Server/GameObjects/EntitySystems/PointingSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/PointingSystem.cs @@ -86,7 +86,7 @@ namespace Content.Server.GameObjects.EntitySystems else { return pointer.InRangeUnOccluded(coordinates, 15, e => e == pointer); - } + } } public bool TryPoint(ICommonSession? session, EntityCoordinates coords, EntityUid uid) @@ -199,7 +199,7 @@ namespace Content.Server.GameObjects.EntitySystems public override void Update(float frameTime) { - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/BaseChargerSystem.cs b/Content.Server/GameObjects/EntitySystems/Power/BaseChargerSystem.cs similarity index 77% rename from Content.Server/GameObjects/EntitySystems/BaseChargerSystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/BaseChargerSystem.cs index d206e07461..9b5ec578a4 100644 --- a/Content.Server/GameObjects/EntitySystems/BaseChargerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/BaseChargerSystem.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerReceiverUsers; +#nullable enable +using Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerReceiverUsers; using JetBrains.Annotations; using Robust.Shared.GameObjects.Systems; @@ -9,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.OnUpdate(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/BatteryDischargerSystem.cs b/Content.Server/GameObjects/EntitySystems/Power/BatteryDischargerSystem.cs similarity index 77% rename from Content.Server/GameObjects/EntitySystems/BatteryDischargerSystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/BatteryDischargerSystem.cs index f6d9ab7cc5..8980ff8948 100644 --- a/Content.Server/GameObjects/EntitySystems/BatteryDischargerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/BatteryDischargerSystem.cs @@ -1,8 +1,7 @@ -using Content.Server.GameObjects.Components.Power.PowerNetComponents; +#nullable enable +using Content.Server.GameObjects.Components.Power.PowerNetComponents; using JetBrains.Annotations; -using Robust.Server.Interfaces.Timing; using Robust.Shared.GameObjects.Systems; -using Robust.Shared.IoC; namespace Content.Server.GameObjects.EntitySystems { diff --git a/Content.Server/GameObjects/EntitySystems/BatteryStorageSystem.cs b/Content.Server/GameObjects/EntitySystems/Power/BatteryStorageSystem.cs similarity index 76% rename from Content.Server/GameObjects/EntitySystems/BatteryStorageSystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/BatteryStorageSystem.cs index 8ace299025..725ac2ed9e 100644 --- a/Content.Server/GameObjects/EntitySystems/BatteryStorageSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/BatteryStorageSystem.cs @@ -1,8 +1,7 @@ -using Content.Server.GameObjects.Components.Power.PowerNetComponents; +#nullable enable +using Content.Server.GameObjects.Components.Power.PowerNetComponents; using JetBrains.Annotations; -using Robust.Server.Interfaces.Timing; using Robust.Shared.GameObjects.Systems; -using Robust.Shared.IoC; namespace Content.Server.GameObjects.EntitySystems { diff --git a/Content.Server/GameObjects/EntitySystems/BatterySystem.cs b/Content.Server/GameObjects/EntitySystems/Power/BatterySystem.cs similarity index 81% rename from Content.Server/GameObjects/EntitySystems/BatterySystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/BatterySystem.cs index 438a58430f..92eb658962 100644 --- a/Content.Server/GameObjects/EntitySystems/BatterySystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/BatterySystem.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.Power; +#nullable enable +using Content.Server.GameObjects.Components.Power; using JetBrains.Annotations; using Robust.Shared.GameObjects.Systems; @@ -9,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.OnUpdate(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/PowerApcSystem.cs b/Content.Server/GameObjects/EntitySystems/Power/PowerApcSystem.cs similarity index 89% rename from Content.Server/GameObjects/EntitySystems/PowerApcSystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/PowerApcSystem.cs index aef620e58f..da177056dd 100644 --- a/Content.Server/GameObjects/EntitySystems/PowerApcSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/PowerApcSystem.cs @@ -1,10 +1,9 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Content.Server.GameObjects.Components.Power.ApcNetComponents; using JetBrains.Annotations; -using Robust.Server.Interfaces.Timing; using Robust.Shared.GameObjects.Systems; -using Robust.Shared.IoC; namespace Content.Server.GameObjects.EntitySystems { diff --git a/Content.Server/GameObjects/EntitySystems/PowerNetSystem.cs b/Content.Server/GameObjects/EntitySystems/Power/PowerNetSystem.cs similarity index 84% rename from Content.Server/GameObjects/EntitySystems/PowerNetSystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/PowerNetSystem.cs index 86196dcc2e..944e801028 100644 --- a/Content.Server/GameObjects/EntitySystems/PowerNetSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/PowerNetSystem.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.Power.PowerNetComponents; +#nullable enable +using Content.Server.GameObjects.Components.Power.PowerNetComponents; using JetBrains.Annotations; using Robust.Shared.GameObjects.Systems; using Robust.Shared.IoC; diff --git a/Content.Server/GameObjects/EntitySystems/PowerSmesSystem.cs b/Content.Server/GameObjects/EntitySystems/Power/PowerSmesSystem.cs similarity index 79% rename from Content.Server/GameObjects/EntitySystems/PowerSmesSystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/PowerSmesSystem.cs index f6bc4cdeeb..a1922d2288 100644 --- a/Content.Server/GameObjects/EntitySystems/PowerSmesSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/PowerSmesSystem.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.Power.PowerNetComponents; +#nullable enable +using Content.Server.GameObjects.Components.Power.PowerNetComponents; using JetBrains.Annotations; using Robust.Shared.GameObjects.Systems; @@ -9,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.OnUpdate(); } diff --git a/Content.Server/GameObjects/EntitySystems/PowerSolarControlConsoleSystem.cs b/Content.Server/GameObjects/EntitySystems/Power/PowerSolarControlConsoleSystem.cs similarity index 86% rename from Content.Server/GameObjects/EntitySystems/PowerSolarControlConsoleSystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/PowerSolarControlConsoleSystem.cs index 68820fbd1b..226b40c788 100644 --- a/Content.Server/GameObjects/EntitySystems/PowerSolarControlConsoleSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/PowerSolarControlConsoleSystem.cs @@ -1,4 +1,5 @@ -using Content.Server.GameObjects.Components.Power.PowerNetComponents; +#nullable enable +using Content.Server.GameObjects.Components.Power.PowerNetComponents; using JetBrains.Annotations; using Robust.Shared.GameObjects.Systems; @@ -21,7 +22,7 @@ namespace Content.Server.GameObjects.EntitySystems if (_updateTimer >= 1) { _updateTimer -= 1; - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.UpdateUIState(); } diff --git a/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs b/Content.Server/GameObjects/EntitySystems/Power/PowerSolarSystem.cs similarity index 99% rename from Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs rename to Content.Server/GameObjects/EntitySystems/Power/PowerSolarSystem.cs index d2a437b40a..b2a8dfa5c3 100644 --- a/Content.Server/GameObjects/EntitySystems/PowerSolarSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Power/PowerSolarSystem.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Linq; using Content.Server.GameObjects.Components.Power.PowerNetComponents; using Content.Shared.Physics; @@ -86,7 +87,7 @@ namespace Content.Server.GameObjects.EntitySystems TotalPanelPower = 0; - foreach (var panel in ComponentManager.EntityQuery()) + foreach (var panel in ComponentManager.EntityQuery(true)) { // There's supposed to be rotational logic here, but that implies putting it somewhere. panel.Owner.Transform.WorldRotation = TargetPanelRotation; diff --git a/Content.Server/GameObjects/EntitySystems/ProjectileSystem.cs b/Content.Server/GameObjects/EntitySystems/ProjectileSystem.cs index 7838ef62e0..5c8483866c 100644 --- a/Content.Server/GameObjects/EntitySystems/ProjectileSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ProjectileSystem.cs @@ -11,7 +11,7 @@ namespace Content.Server.GameObjects.EntitySystems { base.Update(frameTime); - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.TimeLeft -= frameTime; diff --git a/Content.Server/GameObjects/EntitySystems/PuddleSystem.cs b/Content.Server/GameObjects/EntitySystems/PuddleSystem.cs index f36783a983..6b8f6ab87e 100644 --- a/Content.Server/GameObjects/EntitySystems/PuddleSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/PuddleSystem.cs @@ -28,7 +28,7 @@ namespace Content.Server.GameObjects.EntitySystems private void HandleTileChanged(object sender, TileChangedEventArgs eventArgs) { // If this gets hammered you could probably queue up all the tile changes every tick but I doubt that would ever happen. - foreach (var (puddle, snapGrid) in ComponentManager.EntityQuery()) + foreach (var (puddle, snapGrid) in ComponentManager.EntityQuery(true)) { // If the tile becomes space then delete it (potentially change by design) if (eventArgs.NewTile.GridIndex == puddle.Owner.Transform.GridID && diff --git a/Content.Server/GameObjects/EntitySystems/RadioSystem.cs b/Content.Server/GameObjects/EntitySystems/RadioSystem.cs index f5696c14f8..7915ea6056 100644 --- a/Content.Server/GameObjects/EntitySystems/RadioSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/RadioSystem.cs @@ -25,7 +25,7 @@ namespace Content.Server.GameObjects.EntitySystems _messages.Add(message); - foreach (var radio in ComponentManager.EntityQuery()) + foreach (var radio in ComponentManager.EntityQuery(true)) { if (radio.Channels.Contains(channel)) { diff --git a/Content.Server/GameObjects/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/GameObjects/EntitySystems/ReagentGrinderSystem.cs index 85a4682d4b..0122a7e18f 100644 --- a/Content.Server/GameObjects/EntitySystems/ReagentGrinderSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ReagentGrinderSystem.cs @@ -10,7 +10,7 @@ namespace Content.Server.GameObjects.EntitySystems public override void Update(float frameTime) { base.Update(frameTime); - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.OnUpdate(); } diff --git a/Content.Server/GameObjects/EntitySystems/RecyclerSystem.cs b/Content.Server/GameObjects/EntitySystems/RecyclerSystem.cs index c0904a1271..bea76c6e49 100644 --- a/Content.Server/GameObjects/EntitySystems/RecyclerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/RecyclerSystem.cs @@ -9,7 +9,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/RoguePointingSystem.cs b/Content.Server/GameObjects/EntitySystems/RoguePointingSystem.cs index 7686fb1e3a..e4fa11b019 100644 --- a/Content.Server/GameObjects/EntitySystems/RoguePointingSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/RoguePointingSystem.cs @@ -9,7 +9,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/SingularitySystem.cs b/Content.Server/GameObjects/EntitySystems/SingularitySystem.cs index 18a4c524ca..55cad3de26 100644 --- a/Content.Server/GameObjects/EntitySystems/SingularitySystem.cs +++ b/Content.Server/GameObjects/EntitySystems/SingularitySystem.cs @@ -20,7 +20,7 @@ namespace Content.Server.GameObjects.EntitySystems var shouldUpdate = curTimeSingulo >= 1f; var shouldPull = curTimePull >= 0.2f; if (!shouldUpdate && !shouldPull) return; - var singulos = ComponentManager.EntityQuery(); + var singulos = ComponentManager.EntityQuery(true); if (curTimeSingulo >= 1f) { diff --git a/Content.Server/GameObjects/EntitySystems/SolutionAreaEffectSystem.cs b/Content.Server/GameObjects/EntitySystems/SolutionAreaEffectSystem.cs new file mode 100644 index 0000000000..79062a6d2a --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/SolutionAreaEffectSystem.cs @@ -0,0 +1,19 @@ +#nullable enable +using Content.Server.GameObjects.Components.Chemistry; +using JetBrains.Annotations; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Server.GameObjects.EntitySystems +{ + [UsedImplicitly] + public class SolutionAreaEffectSystem : EntitySystem + { + public override void Update(float frameTime) + { + foreach (var inception in ComponentManager.EntityQuery()) + { + inception.InceptionUpdate(frameTime); + } + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/StationEvents/RadiationPulseSystem.cs b/Content.Server/GameObjects/EntitySystems/StationEvents/RadiationPulseSystem.cs index 9dd45401be..db4e2db866 100644 --- a/Content.Server/GameObjects/EntitySystems/StationEvents/RadiationPulseSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StationEvents/RadiationPulseSystem.cs @@ -35,7 +35,7 @@ namespace Content.Server.GameObjects.EntitySystems.StationEvents { base.Update(frameTime); - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.Update(frameTime); var ent = comp.Owner; diff --git a/Content.Server/GameObjects/EntitySystems/StorageSystem.cs b/Content.Server/GameObjects/EntitySystems/StorageSystem.cs index 4753b332e6..d3dc608ce3 100644 --- a/Content.Server/GameObjects/EntitySystems/StorageSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StorageSystem.cs @@ -23,7 +23,7 @@ namespace Content.Server.GameObjects.EntitySystems /// public override void Update(float frameTime) { - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { CheckSubscribedEntities(component); } diff --git a/Content.Server/GameObjects/EntitySystems/StressTestMovementSystem.cs b/Content.Server/GameObjects/EntitySystems/StressTestMovementSystem.cs index abdda79a09..ed941c83c5 100644 --- a/Content.Server/GameObjects/EntitySystems/StressTestMovementSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StressTestMovementSystem.cs @@ -13,7 +13,7 @@ namespace Content.Server.GameObjects.EntitySystems { base.Update(frameTime); - foreach (var stressTest in ComponentManager.EntityQuery()) + foreach (var stressTest in ComponentManager.EntityQuery(true)) { var transform = stressTest.Owner.Transform; diff --git a/Content.Server/GameObjects/EntitySystems/StunSystem.cs b/Content.Server/GameObjects/EntitySystems/StunSystem.cs index 6e3a4459ba..05ce68c119 100644 --- a/Content.Server/GameObjects/EntitySystems/StunSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/StunSystem.cs @@ -11,7 +11,7 @@ namespace Content.Server.GameObjects.EntitySystems { base.Update(frameTime); - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.Update(frameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/ThirstSystem.cs b/Content.Server/GameObjects/EntitySystems/ThirstSystem.cs index dbb8816a49..64a057d791 100644 --- a/Content.Server/GameObjects/EntitySystems/ThirstSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/ThirstSystem.cs @@ -15,7 +15,7 @@ namespace Content.Server.GameObjects.EntitySystems if (_accumulatedFrameTime > 1) { - foreach (var component in ComponentManager.EntityQuery()) + foreach (var component in ComponentManager.EntityQuery(true)) { component.OnUpdate(_accumulatedFrameTime); } diff --git a/Content.Server/GameObjects/EntitySystems/TimedOverlayRemovalSystem.cs b/Content.Server/GameObjects/EntitySystems/TimedOverlayRemovalSystem.cs deleted file mode 100644 index 4994837d09..0000000000 --- a/Content.Server/GameObjects/EntitySystems/TimedOverlayRemovalSystem.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Content.Server.GameObjects.Components.Mobs; -using Content.Shared.GameObjects.Components.Mobs; -using JetBrains.Annotations; -using Robust.Shared.GameObjects.Systems; -using Robust.Shared.Interfaces.Timing; -using Robust.Shared.IoC; - -namespace Content.Server.GameObjects.EntitySystems -{ - [UsedImplicitly] - internal sealed class TimedOverlayRemovalSystem : EntitySystem - { - [Dependency] private readonly IGameTiming _gameTiming = default!; - - public override void Update(float frameTime) - { - base.Update(frameTime); - - foreach (var component in ComponentManager.EntityQuery()) - { - - foreach (var overlay in component.ActiveOverlays.ToArray()) - { - if (overlay.TryGetOverlayParameter(out var parameter)) - { - if (parameter.StartedAt + parameter.Length <= _gameTiming.CurTime.TotalMilliseconds) - { - component.RemoveOverlay(overlay); - } - } - } - } - } - } -} diff --git a/Content.Server/GameObjects/EntitySystems/VaporSystem.cs b/Content.Server/GameObjects/EntitySystems/VaporSystem.cs index e842db680f..7dc8155f5f 100644 --- a/Content.Server/GameObjects/EntitySystems/VaporSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/VaporSystem.cs @@ -9,7 +9,7 @@ namespace Content.Server.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var vaporComp in ComponentManager.EntityQuery()) + foreach (var vaporComp in ComponentManager.EntityQuery(true)) { vaporComp.Update(frameTime); } diff --git a/Content.Server/GameTicking/GamePreset.cs b/Content.Server/GameTicking/GamePreset.cs index 1d0d14cc42..478a3953b8 100644 --- a/Content.Server/GameTicking/GamePreset.cs +++ b/Content.Server/GameTicking/GamePreset.cs @@ -13,7 +13,6 @@ using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Mobs.State; using Robust.Shared.Network; using Robust.Shared.Interfaces.GameObjects; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Player; using Robust.Shared.IoC; @@ -85,12 +84,6 @@ namespace Content.Server.GameTicking var ghostComponent = ghost.GetComponent(); ghostComponent.CanReturnToBody = canReturn; - if (playerEntity != null && - playerEntity.TryGetComponent(out ServerOverlayEffectsComponent? overlayComponent)) - { - overlayComponent.RemoveOverlay(SharedOverlayID.CircleMaskOverlay); - } - if (canReturn) mind.Visit(ghost); else diff --git a/Content.Server/GameTicking/GameRules/RuleSuspicion.cs b/Content.Server/GameTicking/GameRules/RuleSuspicion.cs index 610748cd5e..f1d66028b7 100644 --- a/Content.Server/GameTicking/GameRules/RuleSuspicion.cs +++ b/Content.Server/GameTicking/GameRules/RuleSuspicion.cs @@ -2,6 +2,7 @@ using System.Threading; using Content.Server.GameObjects.Components.Suspicion; using Content.Server.GameObjects.EntitySystems; +using Content.Server.GameObjects.EntitySystems.GameMode; using Content.Server.Interfaces.Chat; using Content.Server.Interfaces.GameTicking; using Content.Server.Mobs.Roles.Suspicion; @@ -14,6 +15,7 @@ using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.Configuration; +using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Localization; using Timer = Robust.Shared.Timers.Timer; @@ -31,9 +33,10 @@ namespace Content.Server.GameTicking.GameRules [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IGameTicker _gameTicker = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IGameTiming _timing = default!; private readonly CancellationTokenSource _checkTimerCancel = new(); - private CancellationTokenSource _maxTimerCancel = new(); + private TimeSpan _endTime; public TimeSpan RoundMaxTime { get; set; } = TimeSpan.FromSeconds(CCVars.SuspicionMaxTimeSeconds.DefaultValue); public TimeSpan RoundEndDelay { get; set; } = TimeSpan.FromSeconds(10); @@ -42,63 +45,37 @@ namespace Content.Server.GameTicking.GameRules { RoundMaxTime = TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.SuspicionMaxTimeSeconds)); + _endTime = _timing.CurTime + RoundMaxTime; + _chatManager.DispatchServerAnnouncement(Loc.GetString("There are traitors on the station! Find them, and kill them!")); bool Predicate(IPlayerSession session) => session.ContentData()?.Mind?.HasRole() ?? false; EntitySystem.Get().PlayGlobal("/Audio/Misc/tatoralert.ogg", AudioParams.Default, Predicate); + EntitySystem.Get().EndTime = _endTime; EntitySystem.Get().AccessType = DoorSystem.AccessTypes.AllowAllNoExternal; Timer.SpawnRepeating(DeadCheckDelay, CheckWinConditions, _checkTimerCancel.Token); - - _gameTicker.OnRunLevelChanged += RunLevelChanged; } public override void Removed() { base.Removed(); - _gameTicker.OnRunLevelChanged -= RunLevelChanged; - EntitySystem.Get().AccessType = DoorSystem.AccessTypes.Id; + EntitySystem.Get().EndTime = null; _checkTimerCancel.Cancel(); } - public void RestartTimer() - { - _maxTimerCancel.Cancel(); - _maxTimerCancel = new CancellationTokenSource(); - Timer.Spawn(RoundMaxTime, TimerFired, _maxTimerCancel.Token); - } - - public void StopTimer() - { - _maxTimerCancel.Cancel(); - } - - private void TimerFired() + private void Timeout() { _chatManager.DispatchServerAnnouncement(Loc.GetString("Time has run out for the traitors!")); EndRound(Victory.Innocents); } - private void RunLevelChanged(GameRunLevelChangedEventArgs args) - { - switch (args.NewRunLevel) - { - case GameRunLevel.InRound: - RestartTimer(); - break; - case GameRunLevel.PreRoundLobby: - case GameRunLevel.PostRound: - StopTimer(); - break; - } - } - private void CheckWinConditions() { if (!_cfg.GetCVar(CCVars.GameLobbyEnableWin)) @@ -145,6 +122,11 @@ namespace Content.Server.GameTicking.GameRules _chatManager.DispatchServerAnnouncement(Loc.GetString("The innocents are dead! The traitors win.")); EndRound(Victory.Traitors); } + else if (_timing.CurTime > _endTime) + { + _chatManager.DispatchServerAnnouncement(Loc.GetString("Time has run out for the traitors!")); + EndRound(Victory.Innocents); + } } private enum Victory diff --git a/Content.Server/GlobalVerbs/MakeSentientVerb.cs b/Content.Server/GlobalVerbs/MakeSentientVerb.cs index 5206e89264..ff040dbb9b 100644 --- a/Content.Server/GlobalVerbs/MakeSentientVerb.cs +++ b/Content.Server/GlobalVerbs/MakeSentientVerb.cs @@ -2,8 +2,8 @@ using Content.Server.Commands; using Content.Server.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Verbs; using Robust.Server.Console; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; @@ -42,8 +42,11 @@ namespace Content.Server.GlobalVerbs if (!groupController.CanCommand(player, "makesentient")) return; - new MakeSentientCommand().Execute(IoCManager.Resolve(), player, - new[] {target.Uid.ToString()}); + var host = IoCManager.Resolve(); + var cmd = new MakeSentientCommand(); + var uidStr = target.Uid.ToString(); + cmd.Execute(new ConsoleShell(host, player), $"{cmd.Command} {uidStr}", + new[] {uidStr}); } } } diff --git a/Content.Server/Interfaces/Chat/IChatCommand.cs b/Content.Server/Interfaces/Chat/IChatCommand.cs deleted file mode 100644 index 09fff49d85..0000000000 --- a/Content.Server/Interfaces/Chat/IChatCommand.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Robust.Shared.Console; -using Robust.Shared.Interfaces.Network; - -namespace Content.Server.Interfaces.Chat -{ - public interface IChatCommand : ICommand - { - void Execute(IChatManager manager, INetChannel client, params string[] args); - } -} diff --git a/Content.Server/Interfaces/GameTicking/IGameTicker.cs b/Content.Server/Interfaces/GameTicking/IGameTicker.cs index 02073511f1..0e84bf73cd 100644 --- a/Content.Server/Interfaces/GameTicking/IGameTicker.cs +++ b/Content.Server/Interfaces/GameTicking/IGameTicker.cs @@ -5,7 +5,6 @@ using Content.Server.Mobs; using Content.Shared.Roles; using Content.Shared.Preferences; using Robust.Server.Interfaces.Player; -using Robust.Server.Interfaces.Console; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Map; using Robust.Shared.Timing; diff --git a/Content.Server/Interfaces/PDA/IPDAUplinkManager.cs b/Content.Server/Interfaces/PDA/IPDAUplinkManager.cs index f58fc5d755..0b9f78dba3 100644 --- a/Content.Server/Interfaces/PDA/IPDAUplinkManager.cs +++ b/Content.Server/Interfaces/PDA/IPDAUplinkManager.cs @@ -1,11 +1,15 @@ +#nullable enable using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Content.Shared.GameObjects.Components.PDA; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; namespace Content.Server.Interfaces.PDA { public interface IPDAUplinkManager { - public IReadOnlyDictionary FetchListings => null; + public IReadOnlyDictionary FetchListings { get; } void Initialize(); @@ -13,7 +17,11 @@ namespace Content.Server.Interfaces.PDA public bool ChangeBalance(UplinkAccount acc, int amt); - public bool TryPurchaseItem(UplinkAccount acc, string itemId); + public bool TryPurchaseItem( + UplinkAccount? acc, + string itemId, + EntityCoordinates spawnCoords, + [NotNullWhen(true)] out IEntity? purchasedItem); } } diff --git a/Content.Server/Objectives/Conditions/KillRandomPersonCondition.cs b/Content.Server/Objectives/Conditions/KillRandomPersonCondition.cs index fd3a583d38..62cff5cc11 100644 --- a/Content.Server/Objectives/Conditions/KillRandomPersonCondition.cs +++ b/Content.Server/Objectives/Conditions/KillRandomPersonCondition.cs @@ -17,7 +17,7 @@ namespace Content.Server.Objectives.Conditions public override IObjectiveCondition GetAssigned(Mind mind) { var entityMgr = IoCManager.Resolve(); - var allHumans = entityMgr.ComponentManager.EntityQuery().Where(mc => + var allHumans = entityMgr.ComponentManager.EntityQuery(true).Where(mc => { var entity = mc.Mind?.OwnedEntity; return (entity?.GetComponentOrNull()?.IsAlive() ?? false) && mc.Mind != mind; diff --git a/Content.Server/PDA/PDAUplinkManager.cs b/Content.Server/PDA/PDAUplinkManager.cs index 2cdae4e8ca..b4d96e6980 100644 --- a/Content.Server/PDA/PDAUplinkManager.cs +++ b/Content.Server/PDA/PDAUplinkManager.cs @@ -1,4 +1,6 @@ +#nullable enable using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.Items.Storage; @@ -8,6 +10,7 @@ using Content.Shared.GameObjects.Components.PDA; using Content.Shared.Prototypes.PDA; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; +using Robust.Shared.Map; using Robust.Shared.Prototypes; namespace Content.Server.PDA @@ -17,14 +20,13 @@ namespace Content.Server.PDA [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; - private List _accounts; - private Dictionary _listings; + private readonly List _accounts = new(); + private readonly Dictionary _listings = new(); public IReadOnlyDictionary FetchListings => _listings; public void Initialize() { - _listings = new Dictionary(); foreach (var item in _prototypeManager.EnumeratePrototypes()) { var newListing = new UplinkListingData(item.ListingName, item.ItemId, item.Price, item.Category, @@ -32,8 +34,6 @@ namespace Content.Server.PDA RegisterUplinkListing(newListing); } - - _accounts = new List(); } private void RegisterUplinkListing(UplinkListingData listing) @@ -53,7 +53,7 @@ namespace Content.Server.PDA { var entity = _entityManager.GetEntity(acc.AccountHolder); - if (entity.TryGetComponent(out MindComponent mindComponent) && !mindComponent.HasMind) + if (entity.TryGetComponent(out MindComponent? mindComponent) && !mindComponent.HasMind) { return false; } @@ -86,8 +86,9 @@ namespace Content.Server.PDA return true; } - public bool TryPurchaseItem(UplinkAccount acc, string itemId) + public bool TryPurchaseItem(UplinkAccount? acc, string itemId, EntityCoordinates spawnCoords, [NotNullWhen(true)] out IEntity? purchasedItem) { + purchasedItem = null; if (acc == null) { return false; @@ -108,10 +109,7 @@ namespace Content.Server.PDA return false; } - var player = _entityManager.GetEntity(acc.AccountHolder); - var hands = player.GetComponent(); - hands.PutInHandOrDrop(_entityManager.SpawnEntity(listing.ItemId, - player.Transform.Coordinates).GetComponent()); + purchasedItem = _entityManager.SpawnEntity(listing.ItemId, spawnCoords); return true; } } diff --git a/Content.Server/Sandbox/SandboxManager.cs b/Content.Server/Sandbox/SandboxManager.cs index 4516b17a00..4bdc3a366a 100644 --- a/Content.Server/Sandbox/SandboxManager.cs +++ b/Content.Server/Sandbox/SandboxManager.cs @@ -9,7 +9,6 @@ using Content.Shared.Access; using Content.Shared.Sandbox; using Robust.Server.Console; using Robust.Server.GameObjects; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Placement; using Robust.Server.Interfaces.Player; using Robust.Server.Player; @@ -31,7 +30,7 @@ namespace Content.Server.Sandbox [Dependency] private readonly IPlacementManager _placementManager = default!; [Dependency] private readonly IConGroupController _conGroupController = default!; [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly IConsoleShell _shell = default!; + [Dependency] private readonly IServerConsoleHost _host = default!; private bool _isSandboxEnabled; @@ -183,7 +182,7 @@ namespace Content.Server.Sandbox var player = _playerManager.GetSessionByChannel(message.MsgChannel); - _shell.ExecuteCommand(player, _conGroupController.CanCommand(player, "aghost") ? "aghost" : "ghost"); + _host.ExecuteCommand(player, _conGroupController.CanCommand(player, "aghost") ? "aghost" : "ghost"); } private void SandboxSuicideReceived(MsgSandboxSuicide message) @@ -194,7 +193,7 @@ namespace Content.Server.Sandbox } var player = _playerManager.GetSessionByChannel(message.MsgChannel); - _shell.ExecuteCommand(player, "suicide"); + _host.ExecuteCommand(player, "suicide"); } private void UpdateSandboxStatusForAll() diff --git a/Content.Server/ServerNotifyManager.cs b/Content.Server/ServerNotifyManager.cs index 6206e9838e..9c00fa92e1 100644 --- a/Content.Server/ServerNotifyManager.cs +++ b/Content.Server/ServerNotifyManager.cs @@ -1,9 +1,9 @@ using Content.Server.Administration; using Content.Server.Interfaces; using Content.Shared; +using Content.Shared.Network.NetMessages; using Content.Shared.Administration; using Content.Shared.Interfaces; -using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; diff --git a/Content.Server/StationEvents/PowerGridCheck.cs b/Content.Server/StationEvents/PowerGridCheck.cs index 31b000b2e7..90226c356e 100644 --- a/Content.Server/StationEvents/PowerGridCheck.cs +++ b/Content.Server/StationEvents/PowerGridCheck.cs @@ -43,7 +43,7 @@ namespace Content.Server.StationEvents { var componentManager = IoCManager.Resolve(); - foreach (var component in componentManager.EntityQuery()) + foreach (var component in componentManager.EntityQuery(true)) { component.PowerDisabled = true; _powered.Add(component.Owner); diff --git a/Content.Server/StationEvents/RadiationStorm.cs b/Content.Server/StationEvents/RadiationStorm.cs index ee88eb47cb..46c66e2423 100644 --- a/Content.Server/StationEvents/RadiationStorm.cs +++ b/Content.Server/StationEvents/RadiationStorm.cs @@ -51,25 +51,11 @@ namespace Content.Server.StationEvents public override void Startup() { ResetTimeUntilPulse(); - - var componentManager = IoCManager.Resolve(); - - foreach (var overlay in componentManager.EntityQuery()) - { - overlay.AddOverlay(SharedOverlayID.RadiationPulseOverlay); - } - base.Startup(); } public override void Shutdown() { - var componentManager = IoCManager.Resolve(); - - foreach (var overlay in componentManager.EntityQuery()) - { - overlay.RemoveOverlay(SharedOverlayID.RadiationPulseOverlay); - } base.Shutdown(); } diff --git a/Content.Shared/Administration/AdminAddReagentEuiState.cs b/Content.Shared/Administration/AdminAddReagentEuiState.cs new file mode 100644 index 0000000000..25bf03e17c --- /dev/null +++ b/Content.Shared/Administration/AdminAddReagentEuiState.cs @@ -0,0 +1,31 @@ +using System; +using Content.Shared.Chemistry; +using Content.Shared.Eui; +using Robust.Shared.Serialization; + +namespace Content.Shared.Administration +{ + [Serializable, NetSerializable] + public sealed class AdminAddReagentEuiState : EuiStateBase + { + public ReagentUnit MaxVolume; + public ReagentUnit CurVolume; + } + + public static class AdminAddReagentEuiMsg + { + [Serializable, NetSerializable] + public sealed class Close : EuiMessageBase + { + + } + + [Serializable, NetSerializable] + public sealed class DoAdd : EuiMessageBase + { + public bool CloseAfter; + public ReagentUnit Amount; + public string ReagentId; + } + } +} diff --git a/Content.Shared/Chemistry/ReactionPrototype.cs b/Content.Shared/Chemistry/ReactionPrototype.cs index 4aacbbf2e7..211627999e 100644 --- a/Content.Shared/Chemistry/ReactionPrototype.cs +++ b/Content.Shared/Chemistry/ReactionPrototype.cs @@ -1,4 +1,5 @@ #nullable enable +using System; using System.Collections.Generic; using Content.Server.Interfaces.Chemistry; using Content.Shared.Interfaces; @@ -20,7 +21,7 @@ namespace Content.Shared.Chemistry private string _name = default!; private Dictionary _reactants = default!; private Dictionary _products = default!; - private List _effects = default!; + private IReactionEffect[] _effects = default!; public string ID => _id; public string Name => _name; @@ -55,11 +56,11 @@ namespace Content.Shared.Chemistry { //TODO: Don't have a check for if this is the server //Some implementations of IReactionEffect can't currently be moved to shared, so this is here to prevent the client from breaking when reading server-only IReactionEffects. - serializer.DataField(ref _effects, "effects", new List()); + serializer.DataField(ref _effects, "effects", Array.Empty()); } else { - _effects = new(); //To ensure _effects isn't null since it is only serializable on the server right snow + _effects = Array.Empty(); //To ensure _effects isn't null since it is only serializable on the server right snow } } } diff --git a/Content.Shared/Chemistry/ReagentUnit.cs b/Content.Shared/Chemistry/ReagentUnit.cs index 67a900ec5f..f19553cd6b 100644 --- a/Content.Shared/Chemistry/ReagentUnit.cs +++ b/Content.Shared/Chemistry/ReagentUnit.cs @@ -19,7 +19,7 @@ namespace Content.Shared.Chemistry public static ReagentUnit Epsilon { get; } = new(1); public static ReagentUnit Zero { get; } = new(0); - private double ShiftDown() + private readonly double ShiftDown() { return _value / Math.Pow(10, Shift); } @@ -164,17 +164,17 @@ namespace Content.Shared.Chemistry return a._value > b._value; } - public float Float() + public readonly float Float() { return (float) ShiftDown(); } - public double Double() + public readonly double Double() { return ShiftDown(); } - public int Int() + public readonly int Int() { return (int) ShiftDown(); } @@ -204,14 +204,15 @@ namespace Content.Shared.Chemistry return reagent < min ? min : reagent > max ? max : reagent; } - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { return obj is ReagentUnit unit && _value == unit._value; } - public override int GetHashCode() + public override readonly int GetHashCode() { + // ReSharper disable once NonReadonlyMemberInGetHashCode return HashCode.Combine(_value); } @@ -220,19 +221,19 @@ namespace Content.Shared.Chemistry _value = FromFloat(FloatFromString(value)); } - public override string ToString() => $"{ShiftDown().ToString(CultureInfo.InvariantCulture)}"; + public override readonly string ToString() => $"{ShiftDown().ToString(CultureInfo.InvariantCulture)}"; - public string Serialize() + public readonly string Serialize() { return ToString(); } - public bool Equals(ReagentUnit other) + public readonly bool Equals(ReagentUnit other) { return _value == other._value; } - public int CompareTo(ReagentUnit other) + public readonly int CompareTo(ReagentUnit other) { if(other._value > _value) { diff --git a/Content.Shared/Chemistry/Solution.cs b/Content.Shared/Chemistry/Solution.cs index 17bda924ea..86449e552d 100644 --- a/Content.Shared/Chemistry/Solution.cs +++ b/Content.Shared/Chemistry/Solution.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using Robust.Shared.Analyzers; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Serialization; using Robust.Shared.IoC; using Robust.Shared.Maths; @@ -91,7 +93,7 @@ namespace Content.Shared.Chemistry return ""; } - var majorReagent = Contents.OrderByDescending(reagent => reagent.Quantity).First(); ; + var majorReagent = Contents.OrderByDescending(reagent => reagent.Quantity).First(); return majorReagent.ReagentId; } @@ -316,6 +318,20 @@ namespace Content.Shared.Chemistry return newSolution; } + public void DoEntityReaction(IEntity entity, ReactionMethod method) + { + var proto = IoCManager.Resolve(); + + foreach (var (reagentId, quantity) in _contents.ToArray()) + { + if (!proto.TryIndex(reagentId, out ReagentPrototype reagent)) + continue; + + var removedAmount = reagent.ReactionEntity(entity, method, quantity); + RemoveReagent(reagentId, removedAmount); + } + } + [Serializable, NetSerializable] public readonly struct ReagentQuantity: IComparable { diff --git a/Content.Shared/Chemistry/SolutionCaps.cs b/Content.Shared/Chemistry/SolutionCaps.cs deleted file mode 100644 index 3dada4d98e..0000000000 --- a/Content.Shared/Chemistry/SolutionCaps.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; -using Robust.Shared.Serialization; - -namespace Content.Shared.Chemistry -{ - /// - /// These are the defined capabilities of a container of a solution. - /// - [Flags] - [Serializable, NetSerializable] - public enum SolutionContainerCaps - { - None = 0, - - /// - /// Can solutions be added into the container? - /// - AddTo = 1, - - /// - /// Can solutions be removed from the container? - /// - RemoveFrom = 2, - - /// - /// Allows the container to be placed in a ReagentDispenserComponent. - /// Otherwise it's considered to be too large or the improper shape to fit. - /// Allows us to have obscenely large containers that are harder to abuse in chem dispensers - /// since they can't be placed directly in them. - /// - FitsInDispenser = 4, - - /// - /// Can people examine the solution in the container or is it impossible to see? - /// - CanExamine = 8, - } - - public static class SolutionContainerCapsHelpers - { - public static bool HasCap(this SolutionContainerCaps cap, SolutionContainerCaps other) - { - return (cap & other) == other; - } - } -} diff --git a/Content.Shared/Chemistry/SolutionContainerCaps.cs b/Content.Shared/Chemistry/SolutionContainerCaps.cs new file mode 100644 index 0000000000..47d8a76371 --- /dev/null +++ b/Content.Shared/Chemistry/SolutionContainerCaps.cs @@ -0,0 +1,62 @@ +using System; +using Content.Shared.GameObjects.Components.Chemistry; +using Robust.Shared.Serialization; + +namespace Content.Shared.Chemistry +{ + /// + /// Define common interaction behaviors for + /// + /// + [Flags] + [Serializable, NetSerializable] + public enum SolutionContainerCaps : ushort + { + None = 0, + + /// + /// Reagents can be added with syringes. + /// + Injectable = 1 << 0, + + /// + /// Reagents can be removed with syringes. + /// + Drawable = 1 << 1, + + /// + /// Reagents can be easily added via all reagent containers. + /// Think pouring something into another beaker or into the gas tank of a car. + /// + Refillable = 1 << 2, + + /// + /// Reagents can be easily removed through any reagent container. + /// Think pouring this or draining from a water tank. + /// + Drainable = 1 << 3, + + /// + /// The contents of the solution can be examined directly. + /// + CanExamine = 1 << 4, + + /// + /// Allows the container to be placed in a ReagentDispenserComponent. + /// Otherwise it's considered to be too large or the improper shape to fit. + /// Allows us to have obscenely large containers that are harder to abuse in chem dispensers + /// since they can't be placed directly in them. + /// + FitsInDispenser = 1 << 5, + + OpenContainer = Refillable | Drainable | CanExamine + } + + public static class SolutionContainerCapsHelpers + { + public static bool HasCap(this SolutionContainerCaps cap, SolutionContainerCaps other) + { + return (cap & other) == other; + } + } +} diff --git a/Content.Shared/EntryPoint.cs b/Content.Shared/EntryPoint.cs index 0f163e43c4..bbee9f5b2a 100644 --- a/Content.Shared/EntryPoint.cs +++ b/Content.Shared/EntryPoint.cs @@ -1,15 +1,17 @@ -using System; - using System.Collections.Generic; - using System.Globalization; - using Content.Shared.Maps; - using Robust.Shared.ContentPack; - using Robust.Shared.Interfaces.Map; - using Robust.Shared.IoC; - using Robust.Shared.Localization; - using Robust.Shared.Localization.Macros; - using Robust.Shared.Prototypes; +using System; +using System.Collections.Generic; +using System.Globalization; +using Content.Shared.Chemistry; +using Content.Shared.Maps; +using Robust.Shared.ContentPack; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Localization.Macros; +using Robust.Shared.Log; +using Robust.Shared.Prototypes; - namespace Content.Shared +namespace Content.Shared { public class EntryPoint : GameShared { @@ -39,6 +41,33 @@ base.PostInit(); _initTileDefinitions(); + CheckReactions(); + } + + private void CheckReactions() + { + foreach (var reaction in _prototypeManager.EnumeratePrototypes()) + { + foreach (var reactant in reaction.Reactants.Keys) + { + if (!_prototypeManager.HasIndex(reactant)) + { + Logger.ErrorS( + "chem", "Reaction {reaction} has unknown reactant {reagent}.", + reaction.ID, reactant); + } + } + + foreach (var product in reaction.Products.Keys) + { + if (!_prototypeManager.HasIndex(product)) + { + Logger.ErrorS( + "chem", "Reaction {reaction} has unknown product {product}.", + reaction.ID, product); + } + } + } } private void _initTileDefinitions() @@ -55,6 +84,7 @@ { continue; } + prototypeList.Add(tileDef); } diff --git a/Content.Shared/GameObjects/Components/Chemistry/FoamVisuals.cs b/Content.Shared/GameObjects/Components/Chemistry/FoamVisuals.cs new file mode 100644 index 0000000000..065ae3da7f --- /dev/null +++ b/Content.Shared/GameObjects/Components/Chemistry/FoamVisuals.cs @@ -0,0 +1,13 @@ +#nullable enable +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Chemistry +{ + [Serializable, NetSerializable] + public enum FoamVisuals : byte + { + State, + Color + } +} diff --git a/Content.Shared/GameObjects/Components/Chemistry/ISolutionInteractionsComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/ISolutionInteractionsComponent.cs new file mode 100644 index 0000000000..c88c46234d --- /dev/null +++ b/Content.Shared/GameObjects/Components/Chemistry/ISolutionInteractionsComponent.cs @@ -0,0 +1,84 @@ +using Content.Shared.Chemistry; +using Robust.Shared.Interfaces.GameObjects; + +namespace Content.Shared.GameObjects.Components.Chemistry +{ + /// + /// High-level solution transferring operations like "what happens when a syringe tries to inject this entity." + /// + /// + /// This interface is most often implemented by using + /// and setting the appropriate + /// + public interface ISolutionInteractionsComponent : IComponent + { + // + // INJECTING + // + + /// + /// Whether we CAN POTENTIALLY be injected with solutions by items like syringes. + /// + /// + /// + /// This should NOT change to communicate behavior like "the container is full". + /// Change to 0 for that. + /// + /// + /// If refilling is allowed () you should also always allow injecting. + /// + /// + bool CanInject => false; + + /// + /// The amount of solution space available for injecting. + /// + ReagentUnit InjectSpaceAvailable => ReagentUnit.Zero; + + /// + /// Actually inject reagents. + /// + void Inject(Solution solution) + { + + } + + // + // DRAWING + // + + bool CanDraw => false; + ReagentUnit DrawAvailable => ReagentUnit.Zero; + + Solution Draw(ReagentUnit amount) + { + return new(); + } + + + + // + // REFILLING + // + + bool CanRefill => false; + ReagentUnit RefillSpaceAvailable => ReagentUnit.Zero; + + void Refill(Solution solution) + { + + } + + // + // DRAINING + // + + bool CanDrain => false; + ReagentUnit DrainAvailable => ReagentUnit.Zero; + + Solution Drain(ReagentUnit amount) + { + return new(); + } + } +} diff --git a/Content.Shared/GameObjects/Components/Chemistry/ReagentDispenser/SharedReagentDispenserComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/ReagentDispenser/SharedReagentDispenserComponent.cs index b0d17284ec..c36e8498ff 100644 --- a/Content.Shared/GameObjects/Components/Chemistry/ReagentDispenser/SharedReagentDispenserComponent.cs +++ b/Content.Shared/GameObjects/Components/Chemistry/ReagentDispenser/SharedReagentDispenserComponent.cs @@ -88,7 +88,10 @@ namespace Content.Shared.GameObjects.Components.Chemistry.ReagentDispenser SetDispenseAmount1, SetDispenseAmount5, SetDispenseAmount10, + SetDispenseAmount15, + SetDispenseAmount20, SetDispenseAmount25, + SetDispenseAmount30, SetDispenseAmount50, SetDispenseAmount100, /// diff --git a/Content.Shared/GameObjects/Components/Chemistry/SharedHyposprayComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/SharedHyposprayComponent.cs new file mode 100644 index 0000000000..292e7ff36d --- /dev/null +++ b/Content.Shared/GameObjects/Components/Chemistry/SharedHyposprayComponent.cs @@ -0,0 +1,26 @@ +using System; +using Content.Shared.Chemistry; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Chemistry +{ + public abstract class SharedHyposprayComponent : Component + { + public sealed override string Name => "Hypospray"; + public sealed override uint? NetID => ContentNetIDs.HYPOSPRAY; + + [Serializable, NetSerializable] + protected sealed class HyposprayComponentState : ComponentState + { + public ReagentUnit CurVolume { get; } + public ReagentUnit MaxVolume { get; } + + public HyposprayComponentState(ReagentUnit curVolume, ReagentUnit maxVolume) : base(ContentNetIDs.HYPOSPRAY) + { + CurVolume = curVolume; + MaxVolume = maxVolume; + } + } + } +} diff --git a/Content.Shared/GameObjects/Components/Chemistry/SharedInjectorComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/SharedInjectorComponent.cs index 4fbef4ff26..d63ea77f6c 100644 --- a/Content.Shared/GameObjects/Components/Chemistry/SharedInjectorComponent.cs +++ b/Content.Shared/GameObjects/Components/Chemistry/SharedInjectorComponent.cs @@ -31,7 +31,7 @@ namespace Content.Shared.GameObjects.Components.Chemistry } } - protected enum InjectorToggleMode + public enum InjectorToggleMode { Inject, Draw diff --git a/Content.Shared/GameObjects/Components/Chemistry/SharedSolutionContainerComponent.cs b/Content.Shared/GameObjects/Components/Chemistry/SharedSolutionContainerComponent.cs index e453f4aeda..0a7d1fe7d2 100644 --- a/Content.Shared/GameObjects/Components/Chemistry/SharedSolutionContainerComponent.cs +++ b/Content.Shared/GameObjects/Components/Chemistry/SharedSolutionContainerComponent.cs @@ -20,7 +20,7 @@ namespace Content.Shared.GameObjects.Components.Chemistry /// /// Holds a with a limited volume. /// - public abstract class SharedSolutionContainerComponent : Component, IExamine + public abstract class SharedSolutionContainerComponent : Component, IExamine, ISolutionInteractionsComponent { public override string Name => "SolutionContainer"; @@ -60,9 +60,11 @@ namespace Content.Shared.GameObjects.Components.Chemistry public bool CanUseWithChemDispenser => Capabilities.HasCap(SolutionContainerCaps.FitsInDispenser); - public bool CanAddSolutions => Capabilities.HasCap(SolutionContainerCaps.AddTo); + public bool CanInject => Capabilities.HasCap(SolutionContainerCaps.Injectable) || CanRefill; + public bool CanDraw => Capabilities.HasCap(SolutionContainerCaps.Drawable) || CanDrain; - public bool CanRemoveSolutions => Capabilities.HasCap(SolutionContainerCaps.RemoveFrom); + public bool CanRefill => Capabilities.HasCap(SolutionContainerCaps.Refillable); + public bool CanDrain => Capabilities.HasCap(SolutionContainerCaps.Drainable); public override void ExposeData(ObjectSerializer serializer) { @@ -71,7 +73,7 @@ namespace Content.Shared.GameObjects.Components.Chemistry serializer.DataField(this, x => x.CanReact, "canReact", true); serializer.DataField(this, x => x.MaxVolume, "maxVol", ReagentUnit.New(0)); serializer.DataField(this, x => x.Solution, "contents", new Solution()); - serializer.DataField(this, x => x.Capabilities, "caps", SolutionContainerCaps.AddTo | SolutionContainerCaps.RemoveFrom | SolutionContainerCaps.CanExamine); + serializer.DataField(this, x => x.Capabilities, "caps", SolutionContainerCaps.None); } public void RemoveAllSolution() @@ -209,6 +211,43 @@ namespace Content.Shared.GameObjects.Components.Chemistry message.AddMarkup(Loc.GetString(messageString, colorHex, Loc.GetString(proto.PhysicalDescription))); } + ReagentUnit ISolutionInteractionsComponent.RefillSpaceAvailable => EmptyVolume; + ReagentUnit ISolutionInteractionsComponent.InjectSpaceAvailable => EmptyVolume; + ReagentUnit ISolutionInteractionsComponent.DrawAvailable => CurrentVolume; + ReagentUnit ISolutionInteractionsComponent.DrainAvailable => CurrentVolume; + + void ISolutionInteractionsComponent.Refill(Solution solution) + { + if (!CanRefill) + return; + + TryAddSolution(solution); + } + + void ISolutionInteractionsComponent.Inject(Solution solution) + { + if (!CanInject) + return; + + TryAddSolution(solution); + } + + Solution ISolutionInteractionsComponent.Draw(ReagentUnit amount) + { + if (!CanDraw) + return new Solution(); + + return SplitSolution(amount); + } + + Solution ISolutionInteractionsComponent.Drain(ReagentUnit amount) + { + if (!CanDrain) + return new Solution(); + + return SplitSolution(amount); + } + private void UpdateAppearance() { if (Owner.Deleted || !Owner.TryGetComponent(out var appearance)) diff --git a/Content.Shared/GameObjects/Components/Chemistry/SmokeVisuals.cs b/Content.Shared/GameObjects/Components/Chemistry/SmokeVisuals.cs new file mode 100644 index 0000000000..0ded6dd5c0 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Chemistry/SmokeVisuals.cs @@ -0,0 +1,12 @@ +#nullable enable +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Chemistry +{ + [Serializable, NetSerializable] + public enum SmokeVisuals : byte + { + Color + } +} diff --git a/Content.Shared/GameObjects/Components/GUI/SharedStrippingComponent.cs b/Content.Shared/GameObjects/Components/GUI/SharedStrippingComponent.cs new file mode 100644 index 0000000000..558a55b741 --- /dev/null +++ b/Content.Shared/GameObjects/Components/GUI/SharedStrippingComponent.cs @@ -0,0 +1,27 @@ +#nullable enable +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.GameObjects; + +namespace Content.Shared.GameObjects.Components.GUI +{ + /// + /// Give to an entity to say they can strip another entity. + /// + [RegisterComponent] + public class SharedStrippingComponent : Component, IDragDropOn + { + public override string Name => "Stripping"; + + public bool CanDragDropOn(DragDropEventArgs eventArgs) + { + if (!eventArgs.Dragged.TryGetComponent(out SharedStrippableComponent? strippable)) return false; + return strippable.CanBeStripped(Owner); + } + + public bool DragDropOn(DragDropEventArgs eventArgs) + { + // Handled by StrippableComponent + return true; + } + } +} diff --git a/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs index 83e24cdadb..e3fba91eb5 100644 --- a/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs +++ b/Content.Shared/GameObjects/Components/Items/SharedHandsComponent.cs @@ -1,7 +1,8 @@ -#nullable enable +#nullable enable using System; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; using Robust.Shared.Serialization; namespace Content.Shared.GameObjects.Components.Items @@ -127,4 +128,20 @@ namespace Content.Shared.GameObjects.Components.Items Middle, Right } + + /// + /// Component message for displaying an animation of an entity flying towards the owner of a HandsComponent + /// + [Serializable, NetSerializable] + public class AnimatePickupEntityMessage : ComponentMessage + { + public readonly EntityUid EntityId; + public readonly EntityCoordinates EntityPosition; + public AnimatePickupEntityMessage(EntityUid entity, EntityCoordinates entityPosition) + { + Directed = true; + EntityId = entity; + EntityPosition = entityPosition; + } + } } diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedOverlayEffectsComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedOverlayEffectsComponent.cs deleted file mode 100644 index 77c65c53c8..0000000000 --- a/Content.Shared/GameObjects/Components/Mobs/SharedOverlayEffectsComponent.cs +++ /dev/null @@ -1,120 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using JetBrains.Annotations; -using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.Timing; -using Robust.Shared.IoC; -using Robust.Shared.Serialization; -using Robust.Shared.ViewVariables; - -namespace Content.Shared.GameObjects.Components.Mobs -{ - /// - /// Full screen overlays; Blindness, death, flash, alcohol etc. - /// - public abstract class SharedOverlayEffectsComponent : Component - { - public override string Name => "OverlayEffectsUI"; - - public sealed override uint? NetID => ContentNetIDs.OVERLAYEFFECTS; - } - - [Serializable, NetSerializable] - public class OverlayContainer : IEquatable, IEquatable - { - [ViewVariables(VVAccess.ReadOnly)] - public string ID { get; } - - [ViewVariables(VVAccess.ReadWrite)] - public List Parameters { get; } = new(); - - public OverlayContainer([NotNull] string id) - { - ID = id; - } - - public OverlayContainer(SharedOverlayID id) : this(id.ToString()) - { - } - - public OverlayContainer(SharedOverlayID id, params OverlayParameter[] parameters) : this(id) - { - Parameters.AddRange(parameters); - } - - public bool TryGetOverlayParameter(out T parameter) where T : OverlayParameter - { - var found = Parameters.FirstOrDefault(p => p is T); - if (found != null) - { - parameter = found as T; - return true; - } - - parameter = default; - return false; - } - - public bool Equals(string other) - { - return ID == other; - } - - public bool Equals(OverlayContainer other) - { - return ID == other?.ID; - } - - public override int GetHashCode() - { - return ID != null ? ID.GetHashCode() : 0; - } - - } - - [Serializable, NetSerializable] - public class OverlayEffectComponentMessage : ComponentMessage - { - public List Overlays; - - public OverlayEffectComponentMessage(List overlays) - { - Directed = true; - Overlays = overlays; - } - } - - [Serializable, NetSerializable] - public class ResendOverlaysMessage : ComponentMessage - { - } - - [Serializable, NetSerializable] - public abstract class OverlayParameter - { - } - - [Serializable, NetSerializable] - public class TimedOverlayParameter : OverlayParameter - { - [ViewVariables(VVAccess.ReadOnly)] - public int Length { get; set; } - - public double StartedAt { get; private set; } - - public TimedOverlayParameter(int length) - { - Length = length; - StartedAt = IoCManager.Resolve().CurTime.TotalMilliseconds; - } - } - - public enum SharedOverlayID - { - GradientCircleMaskOverlay, - CircleMaskOverlay, - FlashOverlay, - RadiationPulseOverlay, - } -} diff --git a/Content.Shared/GameObjects/Components/Storage/SharedStorageComponent.cs b/Content.Shared/GameObjects/Components/Storage/SharedStorageComponent.cs index 81c81beb57..cd353412b4 100644 --- a/Content.Shared/GameObjects/Components/Storage/SharedStorageComponent.cs +++ b/Content.Shared/GameObjects/Components/Storage/SharedStorageComponent.cs @@ -1,12 +1,14 @@ -#nullable enable +#nullable enable using System; using System.Collections.Generic; using System.Linq; +using System.Numerics; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems.ActionBlocker; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Map; using Robust.Shared.Serialization; namespace Content.Shared.GameObjects.Components.Storage @@ -100,6 +102,22 @@ namespace Content.Shared.GameObjects.Components.Storage } } + /// + /// Component message for displaying an animation of entities flying into a storage entity + /// + [Serializable, NetSerializable] + public class AnimateInsertingEntitiesMessage : ComponentMessage + { + public readonly List StoredEntities; + public readonly List EntityPositions; + public AnimateInsertingEntitiesMessage(List storedEntities, List entityPositions) + { + Directed = true; + StoredEntities = storedEntities; + EntityPositions = entityPositions; + } + } + /// /// Component message for removing a contained entity from the storage entity /// diff --git a/Content.Shared/GameObjects/Components/Tag/TagComponent.cs b/Content.Shared/GameObjects/Components/Tag/TagComponent.cs new file mode 100644 index 0000000000..d01333b13d --- /dev/null +++ b/Content.Shared/GameObjects/Components/Tag/TagComponent.cs @@ -0,0 +1,300 @@ +#nullable enable +using System.Collections.Generic; +using System.Linq; +using Content.Shared.Prototypes.Tag; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; + +namespace Content.Shared.GameObjects.Components.Tag +{ + [RegisterComponent] + public class TagComponent : Component + { + public override string Name => "Tag"; + + [ViewVariables] + private readonly HashSet _tags = new(); + + public IReadOnlySet Tags => _tags; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataReadWriteFunction( + "tags", + null!, + (ids) => + { + _tags.Clear(); + + if (ids == null) + { + return; + } + + AddTags(ids); + }, + () => _tags); + } + + public override ComponentState GetComponentState() + { + var tags = new string[_tags.Count]; + var i = 0; + + foreach (var tag in _tags) + { + tags[i] = tag; + } + + return new TagComponentState(tags); + } + + public override void HandleComponentState(ComponentState? curState, ComponentState? nextState) + { + if (curState is not TagComponentState state) + { + return; + } + + _tags.Clear(); + + var prototypeManager = IoCManager.Resolve(); + + foreach (var tag in state.Tags) + { + GetTagOrThrow(tag, prototypeManager); + _tags.Add(tag); + } + } + + private TagPrototype GetTagOrThrow(string id, IPrototypeManager? manager = null) + { + manager ??= IoCManager.Resolve(); + return manager.Index(id); + } + + /// + /// Tries to add a tag if it doesn't already exist. + /// + /// The tag to add. + /// true if it was added, false if it already existed. + /// + /// Thrown if no exists with the given id. + /// + public bool AddTag(string id) + { + GetTagOrThrow(id); + var added = _tags.Add(id); + + if (added) + { + Dirty(); + return true; + } + + return false; + } + + /// + /// Tries to add the given tags if they don't already exist. + /// + /// The tags to add. + /// true if any tags were added, false if they all already existed. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool AddTags(params string[] ids) + { + return AddTags(ids.AsEnumerable()); + } + + /// + /// Tries to add the given tags if they don't already exist. + /// + /// The tags to add. + /// true if any tags were added, false if they all already existed. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool AddTags(IEnumerable ids) + { + var count = _tags.Count; + var prototypeManager = IoCManager.Resolve(); + + foreach (var id in ids) + { + GetTagOrThrow(id, prototypeManager); + _tags.Add(id); + } + + if (_tags.Count > count) + { + Dirty(); + return true; + } + + return false; + } + + /// + /// Checks if a tag has been added. + /// + /// The tag to check for. + /// true if it exists, false otherwise. + /// + /// Thrown if no exists with the given id. + /// + public bool HasTag(string id) + { + GetTagOrThrow(id); + return _tags.Contains(id); + } + + /// + /// Checks if all of the given tags have been added. + /// + /// The tags to check for. + /// true if they all exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(params string[] ids) + { + return HasAllTags(ids.AsEnumerable()); + } + + /// + /// Checks if all of the given tags have been added. + /// + /// The tags to check for. + /// true if they all exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(IEnumerable ids) + { + var prototypeManager = IoCManager.Resolve(); + + foreach (var id in ids) + { + GetTagOrThrow(id, prototypeManager); + + if (!_tags.Contains(id)) + { + return false; + } + } + + return true; + } + + /// + /// Checks if any of the given tags have been added. + /// + /// The tags to check for. + /// true if any of them exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(params string[] ids) + { + return HasAnyTag(ids.AsEnumerable()); + } + + /// + /// Checks if any of the given tags have been added. + /// + /// The tags to check for. + /// true if any of them exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(IEnumerable ids) + { + var prototypeManager = IoCManager.Resolve(); + + foreach (var id in ids) + { + GetTagOrThrow(id, prototypeManager); + + if (_tags.Contains(id)) + { + return true; + } + } + + return false; + } + + /// + /// Tries to remove a tag if it exists. + /// + /// The tag to remove. + /// + /// true if it was removed, false otherwise even if it didn't exist. + /// + /// + /// Thrown if no exists with the given id. + /// + public bool RemoveTag(string id) + { + GetTagOrThrow(id); + + if (_tags.Remove(id)) + { + Dirty(); + return true; + } + + return false; + } + + /// + /// Tries to remove all of the given tags if they exist. + /// + /// The tags to remove. + /// + /// true if it was removed, false otherwise even if they didn't exist. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool RemoveTags(params string[] ids) + { + return RemoveTags(ids.AsEnumerable()); + } + + /// + /// Tries to remove all of the given tags if they exist. + /// + /// The tags to remove. + /// true if any tag was removed, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool RemoveTags(IEnumerable ids) + { + var count = _tags.Count; + var prototypeManager = IoCManager.Resolve(); + + foreach (var id in ids) + { + GetTagOrThrow(id, prototypeManager); + _tags.Remove(id); + } + + if (_tags.Count < count) + { + Dirty(); + return true; + } + + return false; + } + } +} diff --git a/Content.Shared/GameObjects/Components/Tag/TagComponentExtensions.cs b/Content.Shared/GameObjects/Components/Tag/TagComponentExtensions.cs new file mode 100644 index 0000000000..9fbbb4fa45 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Tag/TagComponentExtensions.cs @@ -0,0 +1,243 @@ +#nullable enable +using System.Collections.Generic; +using Content.Shared.Prototypes.Tag; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Prototypes; + +namespace Content.Shared.GameObjects.Components.Tag +{ + public static class TagComponentExtensions + { + /// + /// Tries to add a tag to an entity if the tag doesn't already exist. + /// + /// The entity to add the tag to. + /// The tag to add. + /// + /// true if it was added, false otherwise even if it already existed. + /// + /// + /// Thrown if no exists with the given id. + /// + public static bool AddTag(this IEntity entity, string id) + { + return entity.EnsureComponent(out TagComponent tagComponent) && + tagComponent.AddTag(id); + } + + /// + /// Tries to add the given tags to an entity if the tags don't already exist. + /// + /// The entity to add the tag to. + /// The tags to add. + /// + /// true if any tags were added, false otherwise even if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool AddTags(this IEntity entity, params string[] ids) + { + return entity.EnsureComponent(out TagComponent tagComponent) && + tagComponent.AddTags(ids); + } + + /// + /// Tries to add the given tags to an entity if the tags don't already exist. + /// + /// The entity to add the tag to. + /// The tags to add. + /// + /// true if any tags were added, false otherwise even if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool AddTags(this IEntity entity, IEnumerable ids) + { + return entity.EnsureComponent(out TagComponent tagComponent) && + tagComponent.AddTags(ids); + } + + /// + /// Tries to add a tag to an entity if it has a + /// and the tag doesn't already exist. + /// + /// The entity to add the tag to. + /// The tag to add. + /// + /// true if it was added, false otherwise even if it already existed. + /// + /// + /// Thrown if no exists with the given id. + /// + public static bool TryAddTag(this IEntity entity, string id) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.AddTag(id); + } + + /// + /// Tries to add the given tags to an entity if it has a + /// and the tags don't already exist. + /// + /// The entity to add the tag to. + /// The tags to add. + /// + /// true if any tags were added, false otherwise even if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool TryAddTags(this IEntity entity, params string[] ids) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.AddTags(ids); + } + + /// + /// Tries to add the given tags to an entity if it has a + /// and the tags don't already exist. + /// + /// The entity to add the tag to. + /// The tags to add. + /// + /// true if any tags were added, false otherwise even if they all already existed. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool TryAddTags(this IEntity entity, IEnumerable ids) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.AddTags(ids); + } + + /// + /// Checks if a tag has been added to an entity. + /// + /// The entity to check. + /// The tag to check for. + /// true if it exists, false otherwise. + /// + /// Thrown if no exists with the given id. + /// + public static bool HasTag(this IEntity entity, string id) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.HasTag(id); + } + + /// + /// Checks if all of the given tags have been added to an entity. + /// + /// The entity to check. + /// The tags to check for. + /// true if they all exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool HasAllTags(this IEntity entity, params string[] ids) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.HasAllTags(ids); + } + + /// + /// Checks if all of the given tags have been added to an entity. + /// + /// The entity to check. + /// The tags to check for. + /// true if they all exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool HasAllTags(this IEntity entity, IEnumerable ids) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.HasAllTags(ids); + } + + /// + /// Checks if all of the given tags have been added to an entity. + /// + /// The entity to check. + /// The tags to check for. + /// true if any of them exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool HasAnyTag(this IEntity entity, params string[] ids) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.HasAnyTag(ids); + } + + /// + /// Checks if all of the given tags have been added to an entity. + /// + /// The entity to check. + /// The tags to check for. + /// true if any of them exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool HasAnyTag(this IEntity entity, IEnumerable ids) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.HasAnyTag(ids); + } + + /// + /// Tries to remove a tag from an entity if it exists. + /// + /// The entity to remove the tag from. + /// The tag to remove. + /// + /// true if it was removed, false otherwise even if it didn't exist. + /// + /// + /// Thrown if no exists with the given id. + /// + public static bool RemoveTag(this IEntity entity, string id) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.RemoveTag(id); + } + + /// + /// Tries to remove a tag from an entity if it exists. + /// + /// The entity to remove the tag from. + /// The tag to remove. + /// + /// true if it was removed, false otherwise even if it didn't exist. + /// + /// Thrown if one of the ids represents an unregistered . + /// + /// + public static bool RemoveTags(this IEntity entity, params string[] ids) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.RemoveTags(ids); + } + + /// + /// Tries to remove a tag from an entity if it exists. + /// + /// The entity to remove the tag from. + /// The tag to remove. + /// + /// true if it was removed, false otherwise even if it didn't exist. + /// + /// + /// Thrown if one of the ids represents an unregistered . + /// + public static bool RemoveTags(this IEntity entity, IEnumerable ids) + { + return entity.TryGetComponent(out TagComponent? tagComponent) && + tagComponent.RemoveTags(ids); + } + } +} diff --git a/Content.Shared/GameObjects/Components/Tag/TagComponentState.cs b/Content.Shared/GameObjects/Components/Tag/TagComponentState.cs new file mode 100644 index 0000000000..6c29189c72 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Tag/TagComponentState.cs @@ -0,0 +1,15 @@ +#nullable enable +using Robust.Shared.GameObjects; + +namespace Content.Shared.GameObjects.Components.Tag +{ + public class TagComponentState : ComponentState + { + public TagComponentState(string[] tags) : base(ContentNetIDs.TAG) + { + Tags = tags; + } + + public string[] Tags { get; } + } +} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index 0fe7b87c6c..3c3388662c 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -3,7 +3,8 @@ // Starting from 1000 to avoid crossover with engine. public static class ContentNetIDs { - // 1000 + // As a CMO main I hereby declare the hypospray worthy of ID #1000. + public const uint HYPOSPRAY = 1000; public const uint DESTRUCTIBLE = 1001; public const uint MAGAZINE_BARREL = 1002; public const uint HANDS = 1003; @@ -89,6 +90,7 @@ public const uint ACTIONS = 1083; public const uint DAMAGEABLE = 1084; public const uint MAGBOOTS = 1085; + public const uint TAG = 1086; // Net IDs for integration tests. public const uint PREDICTION_TEST = 10001; diff --git a/Content.Shared/GameObjects/DrawDepth.cs b/Content.Shared/GameObjects/DrawDepth.cs index 9f445d2e48..eea05d7d94 100644 --- a/Content.Shared/GameObjects/DrawDepth.cs +++ b/Content.Shared/GameObjects/DrawDepth.cs @@ -22,7 +22,8 @@ namespace Content.Shared.GameObjects Objects = DrawDepthTag.Default, Items = DrawDepthTag.Default + 1, Mobs = DrawDepthTag.Default + 2, - Ghosts = DrawDepthTag.Default + 3, - Overlays = DrawDepthTag.Default + 4, + Effects = DrawDepthTag.Default + 3, + Ghosts = DrawDepthTag.Default + 4, + Overlays = DrawDepthTag.Default + 5, } } diff --git a/Content.Shared/GameObjects/EntitySystemMessages/SuspicionMessages.cs b/Content.Shared/GameObjects/EntitySystemMessages/SuspicionMessages.cs new file mode 100644 index 0000000000..c540b0a4a5 --- /dev/null +++ b/Content.Shared/GameObjects/EntitySystemMessages/SuspicionMessages.cs @@ -0,0 +1,15 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.EntitySystemMessages +{ + public static class SuspicionMessages + { + [Serializable, NetSerializable] + public sealed class SetSuspicionEndTimerMessage : EntitySystemMessage + { + public TimeSpan? EndTime; + } + } +} diff --git a/Content.Shared/GameObjects/EntitySystems/MechanismSystem.cs b/Content.Shared/GameObjects/EntitySystems/MechanismSystem.cs index d3e9dd0daa..75861219e6 100644 --- a/Content.Shared/GameObjects/EntitySystems/MechanismSystem.cs +++ b/Content.Shared/GameObjects/EntitySystems/MechanismSystem.cs @@ -12,7 +12,7 @@ namespace Content.Shared.GameObjects.EntitySystems { base.Update(frameTime); - foreach (var mechanism in ComponentManager.EntityQuery()) + foreach (var mechanism in ComponentManager.EntityQuery(true)) { mechanism.Update(frameTime); } diff --git a/Content.Shared/GameObjects/EntitySystems/SharedDisposalUnitSystem.cs b/Content.Shared/GameObjects/EntitySystems/SharedDisposalUnitSystem.cs index d957a9f203..b8fd1ead39 100644 --- a/Content.Shared/GameObjects/EntitySystems/SharedDisposalUnitSystem.cs +++ b/Content.Shared/GameObjects/EntitySystems/SharedDisposalUnitSystem.cs @@ -9,12 +9,12 @@ namespace Content.Shared.GameObjects.EntitySystems { public override void Update(float frameTime) { - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.Update(frameTime); } - foreach (var comp in ComponentManager.EntityQuery()) + foreach (var comp in ComponentManager.EntityQuery(true)) { comp.Update(frameTime); } diff --git a/Content.Shared/GameObjects/EntitySystems/SlipperySystem.cs b/Content.Shared/GameObjects/EntitySystems/SlipperySystem.cs index e5ad22f7ec..6a44dd5634 100644 --- a/Content.Shared/GameObjects/EntitySystems/SlipperySystem.cs +++ b/Content.Shared/GameObjects/EntitySystems/SlipperySystem.cs @@ -10,7 +10,7 @@ namespace Content.Shared.GameObjects.EntitySystems /// public override void Update(float frameTime) { - foreach (var slipperyComp in ComponentManager.EntityQuery()) + foreach (var slipperyComp in ComponentManager.EntityQuery(true)) { slipperyComp.Update(); } diff --git a/Content.Shared/Interfaces/GameObjects/Components/Interaction/IAfterInteract.cs b/Content.Shared/Interfaces/GameObjects/Components/Interaction/IAfterInteract.cs index 5827fc31d5..d40b256de5 100644 --- a/Content.Shared/Interfaces/GameObjects/Components/Interaction/IAfterInteract.cs +++ b/Content.Shared/Interfaces/GameObjects/Components/Interaction/IAfterInteract.cs @@ -18,10 +18,16 @@ namespace Content.Shared.Interfaces.GameObjects.Components [RequiresExplicitImplementation] public interface IAfterInteract { + /// + /// The interaction priority. Higher numbers get called first. + /// + /// Priority defaults to 0 + int Priority => 0; + /// /// Called when we interact with nothing, or when we interact with an entity out of range that has no behavior /// - Task AfterInteract(AfterInteractEventArgs eventArgs); + Task AfterInteract(AfterInteractEventArgs eventArgs); } public class AfterInteractEventArgs : EventArgs diff --git a/Content.Shared/Interfaces/IConfigurableOverlay.cs b/Content.Shared/Interfaces/IConfigurableOverlay.cs deleted file mode 100644 index e1f0a6b974..0000000000 --- a/Content.Shared/Interfaces/IConfigurableOverlay.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Content.Shared.GameObjects.Components.Mobs; - -namespace Content.Shared.Interfaces -{ - public interface IConfigurableOverlay - { - void Configure(OverlayParameter parameter); - } -} diff --git a/Content.Shared/Prototypes/Tag/TagPrototype.cs b/Content.Shared/Prototypes/Tag/TagPrototype.cs new file mode 100644 index 0000000000..984faf1816 --- /dev/null +++ b/Content.Shared/Prototypes/Tag/TagPrototype.cs @@ -0,0 +1,31 @@ +#nullable enable +using JetBrains.Annotations; +using Robust.Shared.Interfaces.Serialization; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using YamlDotNet.RepresentationModel; + +namespace Content.Shared.Prototypes.Tag +{ + /// + /// Prototype representing a tag in YAML. + /// Meant to only have an ID property, as that is the only thing that + /// gets saved in TagComponent. + /// + [Prototype("Tag")] + public class TagPrototype : IPrototype, IIndexedPrototype, IExposeData + { + public string ID { get; [UsedImplicitly] private set; } = default!; + + public void ExposeData(ObjectSerializer serializer) + { + serializer.DataField(this, x => x.ID, "id", ""); + } + + public void LoadFrom(YamlMappingNode mapping) + { + var serializer = YamlObjectSerializer.NewReader(mapping); + ExposeData(serializer); + } + } +} diff --git a/Jenkinsfile b/Jenkinsfile index dfcd04b25e..fd90f90fa7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,6 +5,9 @@ pipeline { stage('Setup') { steps { sh 'git submodule update --init --recursive' + // Do a git fetch to make sure tags in the engine get pulled in if they've been added later. + // Can happen if somebody forgot to tag the engine then tried to fix it by tagging later. + sh 'cd RobustToolbox && git fetch && cd ..' } } stage('Build') { diff --git a/Resources/Audio/Effects/license.txt b/Resources/Audio/Effects/license.txt index 67629091c3..2587ffff73 100644 --- a/Resources/Audio/Effects/license.txt +++ b/Resources/Audio/Effects/license.txt @@ -1,2 +1,4 @@ hit_kick.ogg is made by Taira Komori (https://taira-komori.jpn.org/freesounden.html) + +smoke.ogg taken from https://github.com/tgstation/tgstation/blob/a5d362ce84e4f0c61026236d5ec84d3c81553664/sound/effects/smoke.ogg \ No newline at end of file diff --git a/Resources/Audio/Effects/refill.ogg b/Resources/Audio/Effects/refill.ogg new file mode 100644 index 0000000000..ec5c4dc344 Binary files /dev/null and b/Resources/Audio/Effects/refill.ogg differ diff --git a/Resources/Audio/Effects/smoke.ogg b/Resources/Audio/Effects/smoke.ogg new file mode 100644 index 0000000000..1a1aa3733e Binary files /dev/null and b/Resources/Audio/Effects/smoke.ogg differ diff --git a/Resources/Audio/Effects/trashbag1.ogg b/Resources/Audio/Effects/trashbag1.ogg new file mode 100644 index 0000000000..2324af18c6 Binary files /dev/null and b/Resources/Audio/Effects/trashbag1.ogg differ diff --git a/Resources/Audio/Effects/trashbag2.ogg b/Resources/Audio/Effects/trashbag2.ogg new file mode 100644 index 0000000000..31f3e13a69 Binary files /dev/null and b/Resources/Audio/Effects/trashbag2.ogg differ diff --git a/Resources/Audio/Effects/trashbag3.ogg b/Resources/Audio/Effects/trashbag3.ogg new file mode 100644 index 0000000000..08719273b5 Binary files /dev/null and b/Resources/Audio/Effects/trashbag3.ogg differ diff --git a/Resources/Audio/Items/hypospray.ogg b/Resources/Audio/Items/hypospray.ogg new file mode 100644 index 0000000000..92d73147a5 Binary files /dev/null and b/Resources/Audio/Items/hypospray.ogg differ diff --git a/Resources/Maps/saltern.yml b/Resources/Maps/saltern.yml index 6ec3a2cf13..6c744ecaf1 100644 --- a/Resources/Maps/saltern.yml +++ b/Resources/Maps/saltern.yml @@ -534,8 +534,6 @@ entities: pos: -15.694785,24.608267 rot: -1.5707963267948966 rad type: Transform - - caps: AddTo, RemoveFrom - type: SolutionContainer - uid: 60 type: DisgustingSweptSoup components: @@ -652,8 +650,6 @@ entities: pos: -3.470539,16.956116 rot: -1.5707963267948966 rad type: Transform - - caps: AddTo, RemoveFrom - type: SolutionContainer - uid: 74 type: Carpet components: @@ -703,8 +699,6 @@ entities: pos: 8.439846,26.712742 rot: 1.5707963267948966 rad type: Transform - - caps: AddTo, RemoveFrom - type: SolutionContainer - uid: 81 type: Table components: @@ -929,8 +923,6 @@ entities: - parent: 853 pos: 8.661116,25.513401 type: Transform - - caps: AddTo, RemoveFrom - type: SolutionContainer - uid: 114 type: BoxDonkpocket components: @@ -32236,8 +32228,6 @@ entities: pos: -8.476567,-17.420076 rot: -1.5707963267948966 rad type: Transform - - caps: AddTo, RemoveFrom - type: SolutionContainer - uid: 2443 type: TableWood components: @@ -48835,4 +48825,18 @@ entities: type: PowerConsumer - supplyRate: 6000 type: PowerSupplier +- uid: 4717 + type: Spade + components: + - parent: 853 + pos: -20.5,-1.5 + rot: -1.5707963267948966 rad + type: Transform +- uid: 4718 + type: Bucket + components: + - parent: 853 + pos: -20.5,-1.5 + rot: -1.5707963267948966 rad + type: Transform ... diff --git a/Resources/Maps/stationstation.yml b/Resources/Maps/stationstation.yml deleted file mode 100644 index 9a52655710..0000000000 --- a/Resources/Maps/stationstation.yml +++ /dev/null @@ -1,5941 +0,0 @@ -meta: - format: 2 - name: DemoStation - author: Space-Wizards - postmapinit: false -tilemap: - 0: space - 1: floor_asteroid_coarse_sand0 - 2: floor_asteroid_coarse_sand1 - 3: floor_asteroid_coarse_sand2 - 4: floor_asteroid_coarse_sand_dug - 5: floor_asteroid_sand - 6: floor_asteroid_tile - 7: floor_dark - 8: floor_elevator_shaft - 9: floor_freezer - 10: floor_gold - 11: floor_green_circuit - 12: floor_hydro - 13: floor_lino - 14: floor_mono - 15: floor_reinforced - 16: floor_rock_vault - 17: floor_showroom - 18: floor_snow - 19: floor_steel - 20: floor_steel_dirty - 21: floor_techmaint - 22: floor_white - 23: floor_wood - 24: plating - 25: underplating -grids: -- settings: - chunksize: 16 - tilesize: 1 - snapsize: 1 - chunks: - - ind: "-1,0" - tiles: EwAAABMAAAATAAAAEwAAABMAAAAZAAAAGQAAABkAAAAZAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAGQAAABUAAAAZAAAAGQAAABkAAAAZAAAAEwAAABMAAAATAAAAEwAAABkAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAAZAAAAGQAAABkAAAAZAAAAGQAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAAAAAAAEwAAABMAAAATAAAAAAAAAAAAAAAAAAAAAAAAABkAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAAAAAABMAAAATAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== - - ind: "-1,-1" - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAZAAAAGQAAABUAAAAVAAAAFQAAABUAAAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAGQAAABkAAAAVAAAAFQAAABkAAAAVAAAAFQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAZAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAGQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABMAAAATAAAAEwAAABMAAAATAAAAGQAAABkAAAAZAAAAGQAAABkAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABkAAAAVAAAAGQAAABkAAAAZAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABkAAAAZAAAAGQAAABkAAAAVAAAAGQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABMAAAATAAAAEwAAABMAAAATAAAAGQAAABUAAAAZAAAAGQAAABkAAAAVAAAAFQAAABUAAAAVAAAAFQAAABUAAAATAAAAEwAAABMAAAATAAAAEwAAABkAAAAVAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAEwAAABMAAAATAAAAEwAAABMAAAAZAAAAFQAAABkAAAAZAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAGQAAABUAAAAZAAAAGQAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABkAAAAVAAAAGQAAABkAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAAZAAAAFQAAABkAAAAZAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAAA== - - ind: "-1,1" - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== - - ind: "0,1" - tiles: AAAAABkAAAATAAAAEwAAABkAAAAZAAAAGQAAABkAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAEwAAAAAAAAAZAAAAEwAAABMAAAAZAAAAFQAAABkAAAAZAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAGQAAABYAAAAAAAAAGQAAABMAAAATAAAAGQAAABUAAAAZAAAAGQAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAZAAAAAAAAABkAAAATAAAAEwAAABkAAAAVAAAAGQAAABkAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAFgAAAAAAAAAZAAAAEwAAABMAAAAZAAAAFQAAABkAAAAVAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAAAAAAGQAAABMAAAATAAAAGQAAABUAAAAZAAAAGQAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAWAAAAAAAAABkAAAATAAAAEwAAABkAAAAVAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAFgAAAAAAAAAZAAAAEwAAABMAAAAZAAAAFQAAABkAAAAVAAAAFQAAABUAAAAZAAAAFQAAABUAAAAZAAAAGQAAABYAAAAAAAAAGQAAABMAAAATAAAAGQAAABUAAAAZAAAAFQAAABUAAAAVAAAAGQAAABUAAAAVAAAAGQAAABYAAAAWAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAVAAAAGQAAABUAAAAVAAAAFQAAABkAAAAVAAAAFQAAABkAAAAZAAAAFgAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAFQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABYAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABUAAAAZAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAWAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAVAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== - - ind: "0,0" - tiles: EwAAABkAAAATAAAAEwAAABkAAAAVAAAAFQAAABUAAAAZAAAAAAAAAAAAAAAAAAAAGQAAABYAAAAWAAAAFgAAABkAAAAZAAAAEwAAABMAAAAZAAAAFQAAABUAAAAVAAAAGQAAAAAAAAAAAAAAAAAAABkAAAAWAAAAFgAAABYAAAATAAAAEwAAABMAAAATAAAAGQAAABkAAAAZAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAZAAAAFgAAABYAAAAWAAAAEwAAABMAAAATAAAAEwAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABkAAAAZAAAAFgAAABMAAAATAAAAEwAAABMAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAFgAAABYAAAATAAAAEwAAABMAAAATAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABYAAAAWAAAAEwAAABMAAAATAAAAEwAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAWAAAAFgAAABMAAAATAAAAEwAAABMAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAFgAAABYAAAAZAAAAGQAAABMAAAATAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABYAAAAWAAAAGQAAABkAAAATAAAAEwAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAWAAAAFgAAABkAAAAVAAAAEwAAABMAAAAVAAAAGQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABkAAAAVAAAAFgAAABYAAAAZAAAAGQAAABMAAAATAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAATAAAAAAAAABkAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAAAAAAAAZAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAAAAAAAGQAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAAAAAABkAAAATAAAAEwAAABkAAAAVAAAAGQAAABkAAAAZAAAAFgAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAAA== - - ind: "0,-1" - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAFQAAABUAAAAVAAAAGQAAABkAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQAAABkAAAAVAAAAFQAAABkAAAAZAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAFQAAABUAAAAVAAAAGQAAABkAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQAAABUAAAAVAAAAFQAAABkAAAAZAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAAAAVAAAAFQAAABUAAAAZAAAAFQAAABUAAAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAFQAAABUAAAAVAAAAFQAAABkAAAAZAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFQAAABUAAAAVAAAAFQAAABUAAAAVAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAZAAAAGQAAABUAAAAVAAAAFQAAABUAAAAVAAAAFQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAFgAAABYAAAAZAAAAGQAAABUAAAAVAAAAGQAAABkAAAAZAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABYAAAAWAAAAEwAAABkAAAATAAAAEwAAABkAAAAVAAAAFQAAABUAAAAZAAAAAAAAAAAAAAAAAAAAAAAAABkAAAAWAAAAFgAAABMAAAATAAAAEwAAABMAAAAZAAAAFQAAABUAAAAVAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAZAAAAFgAAABYAAAATAAAAEwAAABMAAAATAAAAGQAAABUAAAAVAAAAFQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABYAAAAWAAAAEwAAABMAAAATAAAAEwAAABkAAAAVAAAAFQAAABUAAAAZAAAAAAAAAAAAAAAAAAAAGQAAABkAAAAZAAAAFgAAAA== - - ind: "1,-1" - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAGQAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAGQAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABYAAAAWAAAAGQAAABkAAAAZAAAAFgAAABkAAAAZAAAAGQAAAA== - - ind: "-2,0" - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== - - ind: "-2,-1" - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAAA== - - ind: "1,0" - tiles: FgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAAAAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAGQAAAAAAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAAAAAAFgAAABkAAAAZAAAAGQAAABYAAAAZAAAAGQAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAAAAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAZAAAAFgAAABkAAAAWAAAAGQAAABkAAAAZAAAAGQAAAAAAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAAAAAAAAAAAAAAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAGQAAABYAAAAWAAAAFgAAABYAAAAWAAAAGQAAAAAAAAAAAAAAAAAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAAAAAAAAAAAAAAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABYAAAAZAAAAAAAAAAAAAAAAAAAAFgAAABYAAAAWAAAAFgAAABYAAAAWAAAAGQAAABYAAAAWAAAAFgAAABYAAAAWAAAAGQAAAAAAAAAAAAAAAAAAABYAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAWAAAAFgAAABYAAAAWAAAAFgAAABkAAAAAAAAAAAAAAAAAAAATAAAAEwAAABMAAAATAAAAEwAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAAAAAAAAAAAAAAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAEwAAABMAAAATAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEwAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAABkAAAAZAAAAGQAAAAAAAAAAAAAAAAAAAA== - - ind: "2,-1" - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABkAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAWAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAAAFgAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAABYAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAWAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAAAFgAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAABkAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== - - ind: "1,1" - tiles: EwAAABMAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAWAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAAAGQAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAABYAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAWAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAAAFgAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAABYAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAWAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAAAFgAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAABYAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYAAAAWAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWAAAAFgAAABkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFgAAABYAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== -entities: -- uid: 0 - type: GlassStack - components: - - parent: 216 - pos: 8.560405,21.456738 - type: Transform - - anchored: False - type: Physics -- uid: 1 - type: solid_wall - components: - - parent: 216 - pos: 8.5,-2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 2 - type: LightTube - components: - - parent: 3 - type: Transform - - anchored: False - type: Physics -- uid: 3 - type: Poweredlight - components: - - parent: 216 - pos: 8,16.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 2 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 4 - type: ApcExtensionCableStack1 - components: - - parent: 216 - pos: 10.577456,21.424059 - type: Transform - - anchored: False - type: Physics -- uid: 5 - type: ChairOfficeLight - components: - - parent: 216 - pos: 9.5,18.5 - rot: 3.141592653589793 rad - type: Transform -- uid: 6 - type: ChairOfficeLight - components: - - parent: 216 - pos: 9.5,16.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 7 - type: Chair - components: - - parent: 216 - pos: 12.5,17.5 - type: Transform -- uid: 8 - type: solid_wall - components: - - parent: 216 - pos: 8.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 9 - type: solid_wall - components: - - parent: 216 - pos: 8.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 10 - type: solid_wall - components: - - parent: 216 - pos: 8.5,-3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 11 - type: Table - components: - - parent: 216 - pos: 13.5,17.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 12 - type: Table - components: - - parent: 216 - pos: 11.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 13 - type: Table - components: - - parent: 216 - pos: 10.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 14 - type: Table - components: - - parent: 216 - pos: 9.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 15 - type: Table - components: - - parent: 216 - pos: 8.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 16 - type: Autolathe - components: - - parent: 216 - pos: -4.5,-5.5 - type: Transform - - recipes: - - Brutepack - - Ointment - - LightTube - - LightBulb - - MetalStack - - GlassStack - - Wirecutter - - Screwdriver - - Welder - - Wrench - - Crowbar - - Multitool - type: LatheDatabase -- uid: 17 - type: Autolathe - components: - - parent: 216 - pos: 13.5,18.5 - type: Transform - - recipes: - - Brutepack - - Ointment - - LightTube - - LightBulb - - MetalStack - - GlassStack - - Wirecutter - - Screwdriver - - Welder - - Wrench - - Crowbar - - Multitool - type: LatheDatabase -- uid: 18 - type: Protolathe - components: - - parent: 216 - pos: 8.5,17.5 - type: Transform - - protolatherecipes: - - Brutepack - - Ointment - - LightTube - - LightBulb - - MetalStack - - GlassStack - - Wirecutter - - Screwdriver - - Welder - - Wrench - - Crowbar - - Multitool - type: ProtolatheDatabase -- uid: 19 - type: BaseResearchAndDevelopmentPointSource - components: - - parent: 216 - pos: 13.5,16.5 - type: Transform -- uid: 20 - type: ComputerResearchAndDevelopment - components: - - parent: 216 - pos: 8.5,18.5 - type: Transform - - deadThreshold: 100 - type: BreakableConstruction -- uid: 21 - type: ResearchAndDevelopmentServer - components: - - parent: 216 - pos: 11.5,24.5 - rot: 1.5707963267948966 rad - type: Transform - - points: 343000 - type: ResearchServer -- uid: 22 - type: LightBulb - components: - - parent: 23 - type: Transform - - anchored: False - type: Physics -- uid: 23 - type: PoweredSmallLight - components: - - parent: 216 - pos: 7.5,26 - rot: 1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 22 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 24 - type: Catwalk - components: - - parent: 216 - pos: 13.5,24.5 - rot: 3.141592653589793 rad - type: Transform -- uid: 25 - type: LightBulb - components: - - parent: 26 - type: Transform - - anchored: False - type: Physics -- uid: 26 - type: PoweredSmallLight - components: - - parent: 216 - pos: 11,24.5 - rot: 3.141592653589793 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 25 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 27 - type: Poweredlight - components: - - parent: 216 - pos: 2,23.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 28 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 28 - type: LightTube - components: - - parent: 27 - type: Transform - - anchored: False - type: Physics -- uid: 29 - type: LightTube - components: - - parent: 30 - type: Transform - - anchored: False - type: Physics -- uid: 30 - type: Poweredlight - components: - - parent: 216 - pos: 2,17.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 29 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 31 - type: LightBulb - components: - - parent: 32 - type: Transform - - anchored: False - type: Physics -- uid: 32 - type: PoweredSmallLight - components: - - parent: 216 - pos: 18,17.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 31 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 33 - type: LightTube - components: - - parent: 34 - type: Transform - - anchored: False - type: Physics -- uid: 34 - type: Poweredlight - components: - - parent: 216 - pos: 18,27.5 - rot: 3.141592653589793 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 33 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 35 - type: LightTube - components: - - parent: 36 - type: Transform - - anchored: False - type: Physics -- uid: 36 - type: Poweredlight - components: - - parent: 216 - pos: 18,22.5 - rot: 3.141592653589793 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 35 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 37 - type: Poweredlight - components: - - parent: 216 - pos: 14,18.5 - rot: 3.141592653589793 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 38 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 38 - type: LightTube - components: - - parent: 37 - type: Transform - - anchored: False - type: Physics -- uid: 39 - type: LightTube - components: - - parent: 40 - type: Transform - - anchored: False - type: Physics -- uid: 40 - type: Poweredlight - components: - - parent: 216 - pos: 12.5,12 - rot: 1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 39 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 41 - type: LightTube - components: - - parent: 42 - type: Transform - - anchored: False - type: Physics -- uid: 42 - type: Poweredlight - components: - - parent: 216 - pos: 6.5,12 - rot: 1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 41 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 43 - type: Table - components: - - parent: 216 - pos: 9.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 44 - type: Airlock - components: - - parent: 216 - pos: 7.5,20.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 45 - type: Airlock - components: - - parent: 216 - pos: 5.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 46 - type: AirlockScience - components: - - parent: 216 - pos: 16.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 47 - type: AirlockScience - components: - - parent: 216 - pos: 16.5,18.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 48 - type: AirlockScience - components: - - parent: 216 - pos: 14.5,24.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 49 - type: AirlockScienceGlass - components: - - parent: 216 - pos: 14.5,20.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 50 - type: solid_wall - components: - - parent: 216 - pos: 1.5,23.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 51 - type: solid_wall - components: - - parent: 216 - pos: 1.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 52 - type: solid_wall - components: - - parent: 216 - pos: 1.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 53 - type: solid_wall - components: - - parent: 216 - pos: 1.5,20.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 54 - type: solid_wall - components: - - parent: 216 - pos: 1.5,19.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 55 - type: solid_wall - components: - - parent: 216 - pos: 1.5,18.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 56 - type: solid_wall - components: - - parent: 216 - pos: 1.5,17.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 57 - type: solid_wall - components: - - parent: 216 - pos: 1.5,16.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 58 - type: solid_wall - components: - - parent: 216 - pos: 1.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 59 - type: Catwalk - components: - - parent: 216 - pos: 6.5,20.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 60 - type: Catwalk - components: - - parent: 216 - pos: 6.5,24.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 61 - type: Catwalk - components: - - parent: 216 - pos: 5.5,16.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 62 - type: solid_wall - components: - - parent: 216 - pos: 7.5,28.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 63 - type: solid_wall - components: - - parent: 216 - pos: 7.5,27.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 64 - type: solid_wall - components: - - parent: 216 - pos: 7.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 65 - type: solid_wall - components: - - parent: 216 - pos: 7.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 66 - type: solid_wall - components: - - parent: 216 - pos: 4.5,27.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 67 - type: solid_wall - components: - - parent: 216 - pos: 4.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 68 - type: solid_wall - components: - - parent: 216 - pos: 4.5,25.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 69 - type: solid_wall - components: - - parent: 216 - pos: 10.5,24.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 70 - type: solid_wall - components: - - parent: 216 - pos: 10.5,23.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 71 - type: solid_wall - components: - - parent: 216 - pos: 10.5,25.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 72 - type: solid_wall - components: - - parent: 216 - pos: 4.5,28.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 73 - type: solid_wall - components: - - parent: 216 - pos: 8.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 74 - type: solid_wall - components: - - parent: 216 - pos: 9.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 75 - type: solid_wall - components: - - parent: 216 - pos: 10.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 76 - type: solid_wall - components: - - parent: 216 - pos: 11.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 77 - type: solid_wall - components: - - parent: 216 - pos: 12.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 78 - type: solid_wall - components: - - parent: 216 - pos: 13.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 79 - type: solid_wall - components: - - parent: 216 - pos: 18.5,28.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 80 - type: solid_wall - components: - - parent: 216 - pos: 18.5,27.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 81 - type: solid_wall - components: - - parent: 216 - pos: 18.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 82 - type: solid_wall - components: - - parent: 216 - pos: 18.5,25.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 83 - type: solid_wall - components: - - parent: 216 - pos: 18.5,24.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 84 - type: solid_wall - components: - - parent: 216 - pos: 18.5,23.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 85 - type: solid_wall - components: - - parent: 216 - pos: 14.5,28.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 86 - type: solid_wall - components: - - parent: 216 - pos: 14.5,27.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 87 - type: solid_wall - components: - - parent: 216 - pos: 14.5,26.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 88 - type: solid_wall - components: - - parent: 216 - pos: 14.5,25.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 89 - type: solid_wall - components: - - parent: 216 - pos: 14.5,23.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 90 - type: solid_wall - components: - - parent: 216 - pos: 13.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 91 - type: solid_wall - components: - - parent: 216 - pos: 12.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 92 - type: solid_wall - components: - - parent: 216 - pos: 11.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 93 - type: solid_wall - components: - - parent: 216 - pos: 10.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 94 - type: solid_wall - components: - - parent: 216 - pos: 9.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 95 - type: solid_wall - components: - - parent: 216 - pos: 8.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 96 - type: solid_wall - components: - - parent: 216 - pos: 14.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 97 - type: solid_wall - components: - - parent: 216 - pos: 14.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 98 - type: solid_wall - components: - - parent: 216 - pos: 7.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 99 - type: solid_wall - components: - - parent: 216 - pos: 6.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 100 - type: solid_wall - components: - - parent: 216 - pos: 28.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 101 - type: solid_wall - components: - - parent: 216 - pos: 27.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 102 - type: solid_wall - components: - - parent: 216 - pos: 26.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 103 - type: solid_wall - components: - - parent: 216 - pos: 25.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 104 - type: solid_wall - components: - - parent: 216 - pos: 24.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 105 - type: solid_wall - components: - - parent: 216 - pos: 23.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 106 - type: solid_wall - components: - - parent: 216 - pos: 22.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 107 - type: solid_wall - components: - - parent: 216 - pos: 21.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 108 - type: solid_wall - components: - - parent: 216 - pos: 20.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 109 - type: solid_wall - components: - - parent: 216 - pos: 19.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 110 - type: solid_wall - components: - - parent: 216 - pos: 18.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 111 - type: solid_wall - components: - - parent: 216 - pos: 18.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 112 - type: solid_wall - components: - - parent: 216 - pos: 18.5,20.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 113 - type: solid_wall - components: - - parent: 216 - pos: 18.5,19.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 114 - type: solid_wall - components: - - parent: 216 - pos: 18.5,18.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 115 - type: solid_wall - components: - - parent: 216 - pos: 18.5,17.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 116 - type: solid_wall - components: - - parent: 216 - pos: 18.5,16.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 117 - type: solid_wall - components: - - parent: 216 - pos: 18.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 118 - type: solid_wall - components: - - parent: 216 - pos: 17.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 119 - type: solid_wall - components: - - parent: 216 - pos: 17.5,18.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 120 - type: solid_wall - components: - - parent: 216 - pos: 15.5,18.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 121 - type: solid_wall - components: - - parent: 216 - pos: 14.5,19.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 122 - type: solid_wall - components: - - parent: 216 - pos: 14.5,18.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 123 - type: solid_wall - components: - - parent: 216 - pos: 14.5,17.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 124 - type: solid_wall - components: - - parent: 216 - pos: 14.5,16.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 125 - type: solid_wall - components: - - parent: 216 - pos: 15.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 126 - type: solid_wall - components: - - parent: 216 - pos: 14.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 127 - type: solid_wall - components: - - parent: 216 - pos: 13.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 128 - type: solid_wall - components: - - parent: 216 - pos: 12.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 129 - type: solid_wall - components: - - parent: 216 - pos: 11.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 130 - type: solid_wall - components: - - parent: 216 - pos: 10.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 131 - type: solid_wall - components: - - parent: 216 - pos: 8.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 132 - type: solid_wall - components: - - parent: 216 - pos: 7.5,19.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 133 - type: solid_wall - components: - - parent: 216 - pos: 7.5,18.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 134 - type: solid_wall - components: - - parent: 216 - pos: 7.5,17.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 135 - type: solid_wall - components: - - parent: 216 - pos: 7.5,16.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 136 - type: solid_wall - components: - - parent: 216 - pos: 7.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 137 - type: solid_wall - components: - - parent: 216 - pos: 4.5,15.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 138 - type: solid_wall - components: - - parent: 216 - pos: 4.5,16.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 139 - type: solid_wall - components: - - parent: 216 - pos: 4.5,17.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 140 - type: solid_wall - components: - - parent: 216 - pos: 4.5,18.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 141 - type: solid_wall - components: - - parent: 216 - pos: 4.5,19.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 142 - type: solid_wall - components: - - parent: 216 - pos: 4.5,20.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 143 - type: solid_wall - components: - - parent: 216 - pos: 4.5,21.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 144 - type: solid_wall - components: - - parent: 216 - pos: 4.5,22.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 145 - type: solid_wall - components: - - parent: 216 - pos: 4.5,23.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 146 - type: solid_wall - components: - - parent: 216 - pos: 4.5,24.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 147 - type: LockerChemistry - components: - - parent: 216 - pos: 27.5,6.5 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 148 - type: LockerMedical - components: - - parent: 216 - pos: 27.5,5.5 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 149 - type: LockerMedical - components: - - parent: 216 - pos: 29.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 150 - type: LockerMedical - components: - - parent: 216 - pos: 30.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 151 - type: CrateMedical - components: - - parent: 216 - pos: 31.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 152 - type: CrateMedical - components: - - parent: 216 - pos: 32.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 153 - type: Beaker - components: - - parent: 216 - pos: 33.62275,-4.634824 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 154 - type: Beaker - components: - - parent: 216 - pos: 33.62275,-4.228574 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 155 - type: Beaker - components: - - parent: 216 - pos: 33.388374,-4.431699 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 156 - type: Beaker - components: - - parent: 216 - pos: 33.357124,-4.166074 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 157 - type: Beaker - components: - - parent: 216 - pos: 33.357124,-4.837949 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 158 - type: LargeBeaker - components: - - parent: 216 - pos: 33.544624,-5.572324 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 159 - type: LargeBeaker - components: - - parent: 216 - pos: 33.294624,-5.181699 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 160 - type: LargeBeaker - components: - - parent: 216 - pos: 33.18525,-5.681699 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 161 - type: Table - components: - - parent: 216 - pos: 33.5,-5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 162 - type: Table - components: - - parent: 216 - pos: 33.5,-4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 163 - type: Table - components: - - parent: 216 - pos: 33.5,-3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 164 - type: Table - components: - - parent: 216 - pos: 33.5,-2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 165 - type: Table - components: - - parent: 216 - pos: 33.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 166 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: 19.5,-3.5 - rot: 1.5707963267948966 rad - type: Transform -- uid: 167 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: 17.5,8.5 - rot: 1.5707963267948966 rad - type: Transform -- uid: 168 - type: Ointment - components: - - parent: 216 - pos: 18.77326,6.653532 - rot: 1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 169 - type: Ointment - components: - - parent: 216 - pos: 18.49201,6.059782 - rot: 1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 170 - type: Brutepack - components: - - parent: 216 - pos: 18.601385,5.512907 - rot: 1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 171 - type: Brutepack - components: - - parent: 216 - pos: 18.476385,4.841032 - rot: 1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 172 - type: LightTube - components: - - parent: 173 - type: Transform - - anchored: False - type: Physics -- uid: 173 - type: Poweredlight - components: - - parent: 216 - pos: 23.5,-6 - rot: 1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 172 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 174 - type: ComputerMedicalRecords - components: - - parent: 216 - pos: 22.5,-5.5 - rot: 1.5707963267948966 rad - type: Transform - - deadThreshold: 100 - type: BreakableConstruction -- uid: 175 - type: MedkitFilled - components: - - parent: 216 - pos: 13.632214,1.5673001 - rot: 3.141592653589793 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 176 - type: MedkitFilled - components: - - parent: 216 - pos: 13.460339,0.6141751 - rot: 3.141592653589793 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 177 - type: VendingMachineWallMedical - components: - - parent: 216 - pos: 1.5,-3.5 - rot: 3.141592653589793 rad - type: Transform -- uid: 178 - type: VendingMachineMedical - components: - - parent: 216 - pos: 25.5,-5.5 - rot: 3.141592653589793 rad - type: Transform -- uid: 179 - type: VendingMachineMedical - components: - - parent: 216 - pos: 27.5,-5.5 - rot: 3.141592653589793 rad - type: Transform -- uid: 180 - type: VendingMachineMedical - components: - - parent: 216 - pos: 29.5,3.5 - rot: 3.141592653589793 rad - type: Transform -- uid: 181 - type: LightTube - components: - - parent: 182 - type: Transform - - anchored: False - type: Physics -- uid: 182 - type: Poweredlight - components: - - parent: 216 - pos: 28,7.5 - rot: 3.141592653589793 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 181 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 183 - type: LightTube - components: - - parent: 184 - type: Transform - - anchored: False - type: Physics -- uid: 184 - type: Poweredlight - components: - - parent: 216 - pos: 30,1.5 - rot: 3.141592653589793 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 183 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 185 - type: LightTube - components: - - parent: 186 - type: Transform - - anchored: False - type: Physics -- uid: 186 - type: Poweredlight - components: - - parent: 216 - pos: 31.5,-6 - rot: 1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 185 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 187 - type: solid_wall - components: - - parent: 216 - pos: 6.5,2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 188 - type: solid_wall - components: - - parent: 216 - pos: 5.5,2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 189 - type: Table - components: - - parent: 216 - pos: 24.5,-5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 190 - type: Table - components: - - parent: 216 - pos: 23.5,-5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 191 - type: LightTube - components: - - parent: 192 - type: Transform - - anchored: False - type: Physics -- uid: 192 - type: Poweredlight - components: - - parent: 216 - pos: 16.5,-6 - rot: 1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 191 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 193 - type: LightTube - components: - - parent: 194 - type: Transform - - anchored: False - type: Physics -- uid: 194 - type: Poweredlight - components: - - parent: 216 - pos: 22,9.5 - rot: 3.141592653589793 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 193 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 195 - type: LightTube - components: - - parent: 196 - type: Transform - - anchored: False - type: Physics -- uid: 196 - type: Poweredlight - components: - - parent: 216 - pos: 14,9.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 195 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 197 - type: solid_wall - components: - - parent: 216 - pos: 8.5,2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 198 - type: LightTube - components: - - parent: 199 - type: Transform - - anchored: False - type: Physics -- uid: 199 - type: Poweredlight - components: - - parent: 216 - pos: 13.5,3 - rot: -1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 198 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 200 - type: LightTube - components: - - parent: 201 - type: Transform - - anchored: False - type: Physics -- uid: 201 - type: Poweredlight - components: - - parent: 216 - pos: 22.5,3 - rot: -1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 200 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 202 - type: LightTube - components: - - parent: 203 - type: Transform - - anchored: False - type: Physics -- uid: 203 - type: Poweredlight - components: - - parent: 216 - pos: 17.5,4 - rot: 1.5707963267948966 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 202 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 204 - type: solid_wall - components: - - parent: 216 - pos: 7.5,2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 205 - type: solid_wall - components: - - parent: 216 - pos: 8.5,0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 206 - type: Airlock - components: - - parent: 216 - pos: 13.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 207 - type: Airlock - components: - - parent: 216 - pos: 4.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 208 - type: Airlock - components: - - parent: 216 - pos: 1.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 209 - type: Poweredlight - components: - - parent: 216 - pos: 8,-1.5 - rot: 3.141592653589793 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 306 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 210 - type: solid_wall - components: - - parent: 216 - pos: 8.5,1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 211 - type: Beaker - components: - - parent: 216 - pos: 25.291822,10.667244 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 212 - type: Beaker - components: - - parent: 216 - pos: 24.541822,10.635994 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 213 - type: Beaker - components: - - parent: 216 - pos: 26.416822,10.651619 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 214 - type: AirlockMedicalGlass - components: - - parent: 216 - pos: 26.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 215 - type: AirlockMedicalGlass - components: - - parent: 216 - pos: 20.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 216 - components: - - parent: null - type: Transform - - index: 0 - type: MapGrid -- uid: 217 - type: LaserGun - components: - - parent: 216 - pos: -1.47174,4.550247 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - startingCharge: 1000 - type: PowerCell - - containers: - BatteryBarrel-powercell-container: - entities: - - 383 - type: Content.Server.GameObjects.ContainerSlot - BatteryBarrel-ammo-container: - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 218 - type: LaserGun - components: - - parent: 216 - pos: -0.6748645,4.487747 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - startingCharge: 1000 - type: PowerCell - - containers: - BatteryBarrel-powercell-container: - entities: - - 384 - type: Content.Server.GameObjects.ContainerSlot - BatteryBarrel-ammo-container: - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 219 - type: Brutepack - components: - - parent: 216 - pos: -2.106966,-1.457896 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 220 - type: Ointment - components: - - parent: 216 - pos: -1.481966,-1.317271 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 221 - type: Spear - components: - - parent: 216 - pos: -4.144312,7.499083 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 222 - type: Spear - components: - - parent: 216 - pos: -1.238062,7.436583 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 223 - type: PowerCellSmallHigh - components: - - parent: 216 - pos: -2.67511,-10.351 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 224 - type: PowerCellSmallHigh - components: - - parent: 216 - pos: -2.55011,-10.6635 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 225 - type: ClothingOuterVest - components: - - parent: 216 - pos: 1.412994,7.507263 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 226 - type: solid_wall - components: - - parent: 216 - pos: -7.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 227 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 228 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 229 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 230 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 231 - type: solid_wall - components: - - parent: 216 - pos: 0.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 232 - type: solid_wall - components: - - parent: 216 - pos: -0.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 233 - type: solid_wall - components: - - parent: 216 - pos: 3.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 234 - type: solid_wall - components: - - parent: 216 - pos: 4.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 235 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-10.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 236 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-11.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 237 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-12.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 238 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-13.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 239 - type: solid_wall - components: - - parent: 216 - pos: 2.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 240 - type: solid_wall - components: - - parent: 216 - pos: 1.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 241 - type: solid_wall - components: - - parent: 216 - pos: -1.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 242 - type: PoweredSmallLight - components: - - parent: 216 - pos: -4.5,-5 - rot: 1.5707963267949 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 246 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 243 - type: MetalStack - components: - - parent: 216 - pos: -15.5,-5.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 244 - type: AirlockMedicalGlass - components: - - parent: 216 - pos: 16.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 245 - type: PoweredSmallLight - components: - - parent: 216 - pos: 0.5,-5 - rot: 1.5707963267949 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 385 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 246 - type: LightBulb - components: - - parent: 242 - type: Transform - - anchored: False - type: Physics -- uid: 247 - type: AirlockMedicalGlass - components: - - parent: 216 - pos: 15.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 248 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-9.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 249 - type: solid_wall - components: - - parent: 216 - pos: -10.5,-7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 250 - type: AirlockEngineering - components: - - parent: 216 - pos: -12.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 251 - type: solid_wall - components: - - parent: 216 - pos: -10.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 252 - type: solid_wall - components: - - parent: 216 - pos: -10.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 253 - type: solid_wall - components: - - parent: 216 - pos: -10.5,-3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 254 - type: solid_wall - components: - - parent: 216 - pos: -10.5,-2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 255 - type: solid_wall - components: - - parent: 216 - pos: -10.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 256 - type: solid_wall - components: - - parent: 216 - pos: -3.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 257 - type: solid_wall - components: - - parent: 216 - pos: 1.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 258 - type: solid_wall - components: - - parent: 216 - pos: 0.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 259 - type: solid_wall - components: - - parent: 216 - pos: -0.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 260 - type: solid_wall - components: - - parent: 216 - pos: -1.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 261 - type: solid_wall - components: - - parent: 216 - pos: -2.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 262 - type: solid_wall - components: - - parent: 216 - pos: -3.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 263 - type: solid_wall - components: - - parent: 216 - pos: -4.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 264 - type: solid_wall - components: - - parent: 216 - pos: -5.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 265 - type: solid_wall - components: - - parent: 216 - pos: -6.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 266 - type: solid_wall - components: - - parent: 216 - pos: 4.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 267 - type: solid_wall - components: - - parent: 216 - pos: 5.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 268 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 269 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 270 - type: solid_wall - components: - - parent: 216 - pos: -2.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 271 - type: solid_wall - components: - - parent: 216 - pos: -6.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 272 - type: solid_wall - components: - - parent: 216 - pos: -5.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 273 - type: solid_wall - components: - - parent: 216 - pos: -4.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 274 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-10.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 275 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-11.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 276 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-12.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 277 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-13.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 278 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 279 - type: solid_wall - components: - - parent: 216 - pos: 5.5,-14.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 280 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 281 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 282 - type: solid_wall - components: - - parent: 216 - pos: -8.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 283 - type: solid_wall - components: - - parent: 216 - pos: -9.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 284 - type: solid_wall - components: - - parent: 216 - pos: -10.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 285 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 286 - type: Catwalk - components: - - parent: 216 - pos: -6.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 287 - type: Catwalk - components: - - parent: 216 - pos: -8.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 288 - type: solid_wall - components: - - parent: 216 - pos: 5.5,-7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 289 - type: solid_wall - components: - - parent: 216 - pos: 5.5,-9.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 290 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-9.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 291 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 292 - type: Catwalk - components: - - parent: 216 - pos: 4.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 293 - type: LargeBeaker - components: - - parent: 216 - pos: 23.494947,7.0422435 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 294 - type: solid_wall - components: - - parent: 216 - pos: 7.5,-9.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 295 - type: AirlockExternal - components: - - parent: 216 - pos: 7.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 296 - type: AirlockExternal - components: - - parent: 216 - pos: 5.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 297 - type: AirlockEngineering - components: - - parent: 216 - pos: -7.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 298 - type: AirlockEngineering - components: - - parent: 216 - pos: 3.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 299 - type: AirlockEngineering - components: - - parent: 216 - pos: 2.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 300 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 301 - type: solid_wall - components: - - parent: 216 - pos: 6.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 302 - type: Table - components: - - parent: 216 - pos: -3.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 303 - type: Table - components: - - parent: 216 - pos: -2.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 304 - type: Table - components: - - parent: 216 - pos: -1.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 305 - type: Table - components: - - parent: 216 - pos: -0.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 306 - type: LightTube - components: - - parent: 209 - type: Transform - - anchored: False - type: Physics -- uid: 307 - type: CrateGeneric - components: - - parent: 216 - pos: 5.5,-6.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 308 - type: Table - components: - - parent: 216 - pos: 23.5,5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 309 - type: Table - components: - - parent: 216 - pos: 23.5,6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 310 - type: Catwalk - components: - - parent: 216 - pos: 12.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 311 - type: Catwalk - components: - - parent: 216 - pos: 5.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 312 - type: solid_wall - components: - - parent: 216 - pos: 1.5,14.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 313 - type: solid_wall - components: - - parent: 216 - pos: 1.5,13.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 314 - type: solid_wall - components: - - parent: 216 - pos: 1.5,12.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 315 - type: solid_wall - components: - - parent: 216 - pos: -7.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 316 - type: solid_wall - components: - - parent: 216 - pos: -6.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 317 - type: solid_wall - components: - - parent: 216 - pos: -5.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 318 - type: solid_wall - components: - - parent: 216 - pos: -4.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 319 - type: solid_wall - components: - - parent: 216 - pos: -3.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 320 - type: solid_wall - components: - - parent: 216 - pos: -2.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 321 - type: solid_wall - components: - - parent: 216 - pos: -1.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 322 - type: solid_wall - components: - - parent: 216 - pos: -0.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 323 - type: solid_wall - components: - - parent: 216 - pos: 0.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 324 - type: solid_wall - components: - - parent: 216 - pos: 1.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 325 - type: solid_wall - components: - - parent: 216 - pos: 1.5,9.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 326 - type: solid_wall - components: - - parent: 216 - pos: 4.5,9.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 327 - type: Catwalk - components: - - parent: 216 - pos: 2.5,-11.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 328 - type: Catwalk - components: - - parent: 216 - pos: -4.5,-11.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 329 - type: solid_wall - components: - - parent: 216 - pos: 12.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 330 - type: solid_wall - components: - - parent: 216 - pos: 11.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 331 - type: solid_wall - components: - - parent: 216 - pos: 10.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 332 - type: solid_wall - components: - - parent: 216 - pos: 9.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 333 - type: solid_wall - components: - - parent: 216 - pos: 8.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 334 - type: solid_wall - components: - - parent: 216 - pos: 7.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 335 - type: solid_wall - components: - - parent: 216 - pos: 6.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 336 - type: solid_wall - components: - - parent: 216 - pos: 5.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 337 - type: solid_wall - components: - - parent: 216 - pos: 4.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 338 - type: solid_wall - components: - - parent: 216 - pos: 5.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 339 - type: solid_wall - components: - - parent: 216 - pos: 6.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 340 - type: solid_wall - components: - - parent: 216 - pos: 7.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 341 - type: solid_wall - components: - - parent: 216 - pos: 8.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 342 - type: solid_wall - components: - - parent: 216 - pos: 9.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 343 - type: solid_wall - components: - - parent: 216 - pos: 10.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 344 - type: solid_wall - components: - - parent: 216 - pos: 11.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 345 - type: solid_wall - components: - - parent: 216 - pos: 12.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 346 - type: MetalStack - components: - - parent: 216 - pos: 9.435405,21.503613 - type: Transform - - anchored: False - type: Physics -- uid: 347 - type: MetalStack - components: - - parent: 216 - pos: 9.654155,21.628613 - type: Transform - - anchored: False - type: Physics -- uid: 348 - type: MagazinePistolSmg - components: - - parent: 484 - type: Transform - - anchored: False - type: Physics - - containers: - RangedMagazine-magazine: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 349 - type: MagazinePistolSmg - components: - - parent: 485 - type: Transform - - anchored: False - type: Physics - - containers: - RangedMagazine-magazine: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 350 - type: Multitool - components: - - parent: 216 - pos: -1.249865,-10.43489 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 351 - type: Catwalk - components: - - parent: 216 - pos: -2.5,-12.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 352 - type: Catwalk - components: - - parent: 216 - pos: 1.5,-12.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 353 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -1.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 354 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: 0.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 355 - type: Table - components: - - parent: 216 - pos: -3.5,-10.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 356 - type: Table - components: - - parent: 216 - pos: -2.5,-10.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 357 - type: Table - components: - - parent: 216 - pos: -1.5,-10.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 358 - type: Table - components: - - parent: 216 - pos: -0.5,-10.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 359 - type: solid_wall - components: - - parent: 216 - pos: -7.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 360 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -3.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 361 - type: ClothingOuterVest - components: - - parent: 216 - pos: 0.5223687,7.507263 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 362 - type: LockerGeneric - components: - - parent: 216 - pos: 1.5,-10.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - Content.Server.GameObjects.Components.EntityStorageComponent149: - type: Robust.Server.GameObjects.Components.Container.Container - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 363 - type: MedkitFilled - components: - - parent: 216 - pos: -3.209215,-1.486604 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 364 - type: MedkitFilled - components: - - parent: 216 - pos: -4.146715,-1.408479 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 365 - type: LockerGeneric - components: - - parent: 216 - pos: 0.5,-10.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - Content.Server.GameObjects.Components.EntityStorageComponent153: - type: Robust.Server.GameObjects.Components.Container.Container - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 366 - type: FireExtinguisher - components: - - parent: 216 - pos: -1.297692,-5.396082 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 367 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -0.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 368 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -5.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 369 - type: ComputerSupplyRequest - components: - - parent: 216 - pos: 0.5,-5.5 - rot: -1.5707963267949 rad - type: Transform - - products: - - cargo.dice - - cargo.flashlight - - cargo.Medkit - type: GalacticMarket - - deadThreshold: 100 - type: BreakableConstruction -- uid: 370 - type: ComputerSupplyOrdering - components: - - parent: 216 - pos: 0.5,0.5 - rot: -1.5707963267949 rad - type: Transform - - products: - - cargo.dice - - cargo.flashlight - - cargo.Medkit - type: GalacticMarket - - deadThreshold: 100 - type: BreakableConstruction -- uid: 371 - type: Table - components: - - parent: 216 - pos: -4.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 372 - type: Table - components: - - parent: 216 - pos: -1.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 373 - type: Table - components: - - parent: 216 - pos: -2.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 374 - type: Table - components: - - parent: 216 - pos: -3.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 375 - type: GravityGenerator - components: - - parent: 216 - pos: 6.5,0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 376 - type: Catwalk - components: - - parent: 216 - pos: 4.5,-13.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 377 - type: Catwalk - components: - - parent: 216 - pos: -5.5,-13.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 378 - type: solid_wall - components: - - parent: 216 - pos: 13.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 379 - type: solid_wall - components: - - parent: 216 - pos: 14.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 380 - type: solid_wall - components: - - parent: 216 - pos: 13.5,9.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 381 - type: solid_wall - components: - - parent: 216 - pos: 13.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 382 - type: solid_wall - components: - - parent: 216 - pos: 13.5,7.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 383 - type: PowerCellSmallStandard - components: - - parent: 217 - type: Transform - - anchored: False - type: Physics -- uid: 384 - type: PowerCellSmallStandard - components: - - parent: 218 - type: Transform - - anchored: False - type: Physics -- uid: 385 - type: LightBulb - components: - - parent: 245 - type: Transform - - anchored: False - type: Physics -- uid: 386 - type: WallLight - components: - - parent: 216 - pos: -0.5,-14 - rot: 1.5707963267949 rad - type: Transform -- uid: 387 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -9.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 388 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -0.5,5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 389 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -5.5,5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 390 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -0.5,-2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 391 - type: SpawnPointLatejoin - components: - - parent: 216 - pos: -5.5,-2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 392 - type: Catwalk - components: - - parent: 216 - pos: 9.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 393 - type: Catwalk - components: - - parent: 216 - pos: 9.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 394 - type: Catwalk - components: - - parent: 216 - pos: 9.5,2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 395 - type: Catwalk - components: - - parent: 216 - pos: 9.5,3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 396 - type: Catwalk - components: - - parent: 216 - pos: 9.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 397 - type: VendingMachineYouTool - components: - - parent: 216 - pos: -11.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 398 - type: ApcExtensionCableStack1 - components: - - parent: 216 - pos: 10.561831,21.767809 - type: Transform - - anchored: False - type: Physics -- uid: 399 - type: solid_wall - components: - - parent: 216 - pos: 13.5,6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 400 - type: solid_wall - components: - - parent: 216 - pos: 13.5,5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 401 - type: GlassStack - components: - - parent: 216 - pos: 8.57603,21.566113 - type: Transform - - anchored: False - type: Physics -- uid: 402 - type: Table - components: - - parent: 216 - pos: -6.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 403 - type: Table - components: - - parent: 216 - pos: -5.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 404 - type: Table - components: - - parent: 216 - pos: -4.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 405 - type: Table - components: - - parent: 216 - pos: -3.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 406 - type: Table - components: - - parent: 216 - pos: -2.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 407 - type: Table - components: - - parent: 216 - pos: -1.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 408 - type: Table - components: - - parent: 216 - pos: -0.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 409 - type: Table - components: - - parent: 216 - pos: 0.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 410 - type: Table - components: - - parent: 216 - pos: 1.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 411 - type: Table - components: - - parent: 216 - pos: -4.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 412 - type: Table - components: - - parent: 216 - pos: -3.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 413 - type: Table - components: - - parent: 216 - pos: -2.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 414 - type: Table - components: - - parent: 216 - pos: -1.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 415 - type: Table - components: - - parent: 216 - pos: -0.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 416 - type: AirlockMedicalGlass - components: - - parent: 216 - pos: 26.5,-3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 417 - type: AirlockMedicalGlass - components: - - parent: 216 - pos: 28.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 418 - type: Catwalk - components: - - parent: 216 - pos: -9.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 419 - type: solid_wall - components: - - parent: 216 - pos: 13.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 420 - type: solid_wall - components: - - parent: 216 - pos: 25.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 421 - type: solid_wall - components: - - parent: 216 - pos: 23.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 422 - type: solid_wall - components: - - parent: 216 - pos: 17.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 423 - type: solid_wall - components: - - parent: 216 - pos: -10.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 424 - type: solid_wall - components: - - parent: 216 - pos: -10.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 425 - type: Airlock - components: - - parent: 216 - pos: -9.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 426 - type: LightTube - components: - - parent: 427 - type: Transform - - anchored: False - type: Physics -- uid: 427 - type: Poweredlight - components: - - parent: 216 - pos: 0.5,1 - rot: -1.5707963267949 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 426 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 428 - type: ChairOfficeLight - components: - - parent: 216 - pos: -3.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 429 - type: ChairOfficeDark - components: - - parent: 216 - pos: 0.5,-6.5 - rot: 1.5707963267949 rad - type: Transform -- uid: 430 - type: Poweredlight - components: - - parent: 216 - pos: -6.5,1 - rot: -1.5707963267949 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 531 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 431 - type: MetalStack - components: - - parent: 216 - pos: -15.5,-5.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 432 - type: Stool - components: - - parent: 216 - pos: -1.5,-9.5 - rot: 1.5707963267949 rad - type: Transform -- uid: 433 - type: ChairOfficeLight - components: - - parent: 216 - pos: -3.5,-2.5 - rot: 1.5707963267949 rad - type: Transform -- uid: 434 - type: ChairOfficeLight - components: - - parent: 216 - pos: -2.5,-2.5 - rot: 1.5707963267949 rad - type: Transform -- uid: 435 - type: ChairOfficeLight - components: - - parent: 216 - pos: -2.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 436 - type: Stool - components: - - parent: 216 - pos: -2.5,-6.5 - rot: 1.5707963267949 rad - type: Transform -- uid: 437 - type: LightBulb - components: - - parent: 466 - type: Transform - - anchored: False - type: Physics -- uid: 438 - type: WardrobeScience - components: - - parent: 216 - pos: 12.5,21.5 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 439 - type: solid_wall - components: - - parent: 216 - pos: 18.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 440 - type: solid_wall - components: - - parent: 216 - pos: 19.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 441 - type: solid_wall - components: - - parent: 216 - pos: 21.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 442 - type: solid_wall - components: - - parent: 216 - pos: 22.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 443 - type: solid_wall - components: - - parent: 216 - pos: 22.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 444 - type: solid_wall - components: - - parent: 216 - pos: 22.5,5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 445 - type: solid_wall - components: - - parent: 216 - pos: 22.5,6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 446 - type: solid_wall - components: - - parent: 216 - pos: 22.5,7.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 447 - type: solid_wall - components: - - parent: 216 - pos: 22.5,9.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 448 - type: solid_wall - components: - - parent: 216 - pos: 22.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 449 - type: solid_wall - components: - - parent: 216 - pos: 21.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 450 - type: solid_wall - components: - - parent: 216 - pos: 22.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 451 - type: LargeBeaker - components: - - parent: 216 - pos: 23.510572,7.7141185 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics -- uid: 452 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 453 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 454 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 455 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 456 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 457 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 458 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 459 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 460 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 461 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-9.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 462 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-10.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 463 - type: Catwalk - components: - - parent: 216 - pos: 9.5,-11.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 464 - type: Catwalk - components: - - parent: 216 - pos: 8.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 465 - type: AirlockEngineering - components: - - parent: 216 - pos: 4.5,-2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 466 - type: PoweredSmallLight - components: - - parent: 216 - pos: 5,-9.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 437 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 467 - type: solid_wall - components: - - parent: 216 - pos: 7.5,-7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 468 - type: ToolboxElectricalFilled - components: - - parent: 216 - pos: -0.8099712,-5.21454 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 469 - type: ToolboxElectricalFilled - components: - - parent: 216 - pos: -0.5597038,-5.679647 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 470 - type: FlashlightLantern - components: - - parent: 216 - pos: -1.934832,-5.154238 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - flashlight_cell_container: - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 471 - type: FlashlightLantern - components: - - parent: 216 - pos: -2.017696,-5.71715 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - flashlight_cell_container: - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 472 - type: Crowbar - components: - - parent: 216 - pos: -2.861032,-5.524786 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 473 - type: ClothingUniformJumpsuitEngineering - components: - - parent: 216 - pos: -0.6474335,-10.27245 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 474 - type: ClothingMaskGas - components: - - parent: 216 - pos: -0.2880585,-10.69432 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 475 - type: ClothingOuterVest - components: - - parent: 216 - pos: -0.9130585,-10.66307 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 476 - type: ClothingBeltUtilityFilled - components: - - parent: 216 - pos: -1.895102,-10.33495 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 477 - type: ClothingBeltUtilityFilled - components: - - parent: 216 - pos: -1.770102,-10.63182 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 478 - type: MagazinePistolSmg - components: - - parent: 216 - pos: -6.605512,7.638151 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - magazine_bullet_container: - type: Robust.Server.GameObjects.Components.Container.Container - RangedMagazine-magazine: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 479 - type: MagazinePistolSmg - components: - - parent: 216 - pos: -6.339887,7.669401 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - magazine_bullet_container: - type: Robust.Server.GameObjects.Components.Container.Container - RangedMagazine-magazine: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 480 - type: MagazinePistolSmg - components: - - parent: 216 - pos: -6.027387,7.622526 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - magazine_bullet_container: - type: Robust.Server.GameObjects.Components.Container.Container - RangedMagazine-magazine: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 481 - type: ClothingBackpack - components: - - parent: 216 - pos: -5.089887,7.591276 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 482 - type: ClothingBackpack - components: - - parent: 216 - pos: -4.683637,7.606901 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - containers: - storagebase: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 483 - type: ClothingHandsGlovesColorBlack - components: - - parent: 216 - pos: -3.386762,7.466276 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 484 - type: SmgC20r - components: - - parent: 216 - pos: -2.524035,7.579326 - rot: -1.5707963267949 rad - type: Transform - - maxAngle: 59.99999999999999 - type: MagazineBarrel - - anchored: False - type: Physics - - containers: - ballistics_chamber_0: - type: Content.Server.GameObjects.ContainerSlot - ballistic_gun_magazine: - type: Content.Server.GameObjects.ContainerSlot - MagazineBarrel-chamber: - type: Content.Server.GameObjects.ContainerSlot - MagazineBarrel-magazine: - entities: - - 348 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 485 - type: SmgC20r - components: - - parent: 216 - pos: -1.94591,7.485576 - rot: -1.5707963267949 rad - type: Transform - - maxAngle: 59.99999999999999 - type: MagazineBarrel - - anchored: False - type: Physics - - containers: - ballistics_chamber_0: - type: Content.Server.GameObjects.ContainerSlot - ballistic_gun_magazine: - type: Content.Server.GameObjects.ContainerSlot - MagazineBarrel-chamber: - type: Content.Server.GameObjects.ContainerSlot - MagazineBarrel-magazine: - entities: - - 349 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 486 - type: solid_wall - components: - - parent: 216 - pos: -10.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 487 - type: solid_wall - components: - - parent: 216 - pos: -11.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 488 - type: solid_wall - components: - - parent: 216 - pos: -10.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 489 - type: solid_wall - components: - - parent: 216 - pos: -9.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 490 - type: solid_wall - components: - - parent: 216 - pos: -8.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 491 - type: solid_wall - components: - - parent: 216 - pos: -7.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 492 - type: solid_wall - components: - - parent: 216 - pos: -8.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 493 - type: solid_wall - components: - - parent: 216 - pos: -5.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 494 - type: solid_wall - components: - - parent: 216 - pos: -6.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 495 - type: solid_wall - components: - - parent: 216 - pos: -7.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 496 - type: solid_wall - components: - - parent: 216 - pos: -0.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 497 - type: solid_wall - components: - - parent: 216 - pos: 0.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 498 - type: solid_wall - components: - - parent: 216 - pos: 1.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 499 - type: solid_wall - components: - - parent: 216 - pos: 1.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 500 - type: solid_wall - components: - - parent: 216 - pos: 1.5,-3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 501 - type: solid_wall - components: - - parent: 216 - pos: 4.5,-3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 502 - type: WardrobeScience - components: - - parent: 216 - pos: 13.5,21.5 - rot: -1.5707963267948966 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 503 - type: solid_wall - components: - - parent: 216 - pos: 4.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 504 - type: solid_wall - components: - - parent: 216 - pos: 4.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 505 - type: solid_wall - components: - - parent: 216 - pos: 4.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 506 - type: solid_wall - components: - - parent: 216 - pos: 4.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 507 - type: solid_wall - components: - - parent: 216 - pos: 4.5,2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 508 - type: solid_wall - components: - - parent: 216 - pos: 4.5,3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 509 - type: solid_wall - components: - - parent: 216 - pos: 4.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 510 - type: solid_wall - components: - - parent: 216 - pos: 4.5,5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 511 - type: solid_wall - components: - - parent: 216 - pos: 4.5,6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 512 - type: solid_wall - components: - - parent: 216 - pos: 4.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 513 - type: solid_wall - components: - - parent: 216 - pos: 4.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 514 - type: solid_wall - components: - - parent: 216 - pos: 1.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 515 - type: solid_wall - components: - - parent: 216 - pos: 0.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 516 - type: solid_wall - components: - - parent: 216 - pos: -0.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 517 - type: solid_wall - components: - - parent: 216 - pos: -1.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 518 - type: solid_wall - components: - - parent: 216 - pos: -2.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 519 - type: solid_wall - components: - - parent: 216 - pos: -3.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 520 - type: solid_wall - components: - - parent: 216 - pos: -4.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 521 - type: solid_wall - components: - - parent: 216 - pos: -5.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 522 - type: solid_wall - components: - - parent: 216 - pos: -6.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 523 - type: solid_wall - components: - - parent: 216 - pos: -7.5,8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 524 - type: solid_wall - components: - - parent: 216 - pos: -7.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 525 - type: solid_wall - components: - - parent: 216 - pos: -7.5,6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 526 - type: solid_wall - components: - - parent: 216 - pos: -7.5,5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 527 - type: ClothingHandsGlovesLeather - components: - - parent: 216 - pos: -4.332221,4.64238 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 528 - type: ClothingHandsGlovesLeather - components: - - parent: 216 - pos: -3.519721,4.64238 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 529 - type: ClothingHandsGlovesLeather - components: - - parent: 216 - pos: -2.597846,4.61113 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 530 - type: LedLightTube - components: - - parent: 216 - pos: -3.511025,-10.35149 - rot: -1.5707963267949 rad - type: Transform - - color: '#EEEEFFFF' - type: Sprite - - anchored: False - type: Physics -- uid: 531 - type: LightTube - components: - - parent: 430 - type: Transform - - anchored: False - type: Physics -- uid: 532 - type: Poweredlight - components: - - parent: 216 - pos: -1.5,8 - rot: -1.5707963267949 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 533 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 533 - type: LightTube - components: - - parent: 532 - type: Transform - - anchored: False - type: Physics -- uid: 534 - type: Poweredlight - components: - - parent: 216 - pos: 4,3.5 - rot: 3.14159265358979 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 535 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 535 - type: LightTube - components: - - parent: 534 - type: Transform - - anchored: False - type: Physics -- uid: 536 - type: WallLight - components: - - parent: 216 - pos: -7,-10.5 - type: Transform -- uid: 537 - type: PoweredSmallLight - components: - - parent: 216 - pos: -10,-5.5 - rot: 3.14159265358979 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 538 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 538 - type: LightBulb - components: - - parent: 537 - type: Transform - - anchored: False - type: Physics -- uid: 539 - type: solid_wall - components: - - parent: 216 - pos: -15.5,2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 540 - type: solid_wall - components: - - parent: 216 - pos: -15.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 541 - type: solid_wall - components: - - parent: 216 - pos: -15.5,3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 542 - type: solid_wall - components: - - parent: 216 - pos: -14.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 543 - type: solid_wall - components: - - parent: 216 - pos: -12.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 544 - type: solid_wall - components: - - parent: 216 - pos: -15.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 545 - type: solid_wall - components: - - parent: 216 - pos: -14.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 546 - type: solid_wall - components: - - parent: 216 - pos: -11.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 547 - type: solid_wall - components: - - parent: 216 - pos: -14.5,5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 548 - type: solid_wall - components: - - parent: 216 - pos: -14.5,6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 549 - type: solid_wall - components: - - parent: 216 - pos: -12.5,6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 550 - type: solid_wall - components: - - parent: 216 - pos: -12.5,5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 551 - type: solid_wall - components: - - parent: 216 - pos: -16.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 552 - type: solid_wall - components: - - parent: 216 - pos: -16.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 553 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 554 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 555 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-2.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 556 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 557 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 558 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 559 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 560 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 561 - type: solid_wall - components: - - parent: 216 - pos: -16.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 562 - type: solid_wall - components: - - parent: 216 - pos: -15.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 563 - type: solid_wall - components: - - parent: 216 - pos: -14.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 564 - type: solid_wall - components: - - parent: 216 - pos: -13.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 565 - type: solid_wall - components: - - parent: 216 - pos: -12.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 566 - type: solid_wall - components: - - parent: 216 - pos: -11.5,-8.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 567 - type: AirlockExternal - components: - - parent: 216 - pos: -13.5,4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 568 - type: AirlockExternal - components: - - parent: 216 - pos: -13.5,6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 569 - type: AirlockEngineering - components: - - parent: 216 - pos: -13.5,1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 570 - type: Table - components: - - parent: 216 - pos: -15.5,-5.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 571 - type: Table - components: - - parent: 216 - pos: -15.5,-1.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 572 - type: solid_wall - components: - - parent: 216 - pos: 23.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 573 - type: solid_wall - components: - - parent: 216 - pos: 24.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 574 - type: solid_wall - components: - - parent: 216 - pos: 25.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 575 - type: Table - components: - - parent: 216 - pos: -15.5,-0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 576 - type: Catwalk - components: - - parent: 216 - pos: -14.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 577 - type: Catwalk - components: - - parent: 216 - pos: -13.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 578 - type: Catwalk - components: - - parent: 216 - pos: -12.5,7.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 579 - type: LockerToolFilled - components: - - parent: 216 - pos: -11.5,-5.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 580 - type: LockerToolFilled - components: - - parent: 216 - pos: -11.5,-4.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 581 - type: LockerToolFilled - components: - - parent: 216 - pos: -11.5,-3.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 582 - type: LockerToolFilled - components: - - parent: 216 - pos: -11.5,-2.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 583 - type: LockerToolFilled - components: - - parent: 216 - pos: -11.5,-1.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics - - IsPlaceable: False - type: PlaceableSurface - - containers: - EntityStorageComponent: - type: Robust.Server.GameObjects.Components.Container.Container - type: ContainerContainer -- uid: 584 - type: GlassStack - components: - - parent: 216 - pos: -15.5,-3.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 585 - type: AirlockEngineering - components: - - parent: 216 - pos: -10.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 586 - type: Autolathe - components: - - parent: 216 - pos: -14.5,-7.5 - rot: -1.5707963267949 rad - type: Transform - - recipes: - - Brutepack - - Ointment - - LightTube - - LightBulb - - MetalStack - - GlassStack - - Wirecutter - - Screwdriver - - Welder - - Wrench - - Crowbar - - Multitool - type: LatheDatabase -- uid: 587 - type: Autolathe - components: - - parent: 216 - pos: -13.5,-7.5 - rot: -1.5707963267949 rad - type: Transform - - recipes: - - Brutepack - - Ointment - - LightTube - - LightBulb - - MetalStack - - GlassStack - - Wirecutter - - Screwdriver - - Welder - - Wrench - - Crowbar - - Multitool - type: LatheDatabase -- uid: 588 - type: Autolathe - components: - - parent: 216 - pos: -12.5,-7.5 - rot: -1.5707963267949 rad - type: Transform - - recipes: - - Brutepack - - Ointment - - LightTube - - LightBulb - - MetalStack - - GlassStack - - Wirecutter - - Screwdriver - - Welder - - Wrench - - Crowbar - - Multitool - type: LatheDatabase -- uid: 589 - type: Poweredlight - components: - - parent: 216 - pos: -11,-5.5 - rot: 3.14159265358979 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 590 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 590 - type: LightTube - components: - - parent: 589 - type: Transform - - anchored: False - type: Physics -- uid: 591 - type: Poweredlight - components: - - parent: 216 - pos: -11,-0.5 - rot: 3.14159265358979 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 592 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 592 - type: LightTube - components: - - parent: 591 - type: Transform - - anchored: False - type: Physics -- uid: 593 - type: Poweredlight - components: - - parent: 216 - pos: -16,-0.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 594 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 594 - type: LightTube - components: - - parent: 593 - type: Transform - - anchored: False - type: Physics -- uid: 595 - type: Poweredlight - components: - - parent: 216 - pos: -16,-5.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 596 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 596 - type: LightTube - components: - - parent: 595 - type: Transform - - anchored: False - type: Physics -- uid: 597 - type: Poweredlight - components: - - parent: 216 - pos: -15,3.5 - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 598 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 598 - type: LightTube - components: - - parent: 597 - type: Transform - - anchored: False - type: Physics -- uid: 599 - type: PoweredSmallLight - components: - - parent: 216 - pos: -14.5,7 - rot: -1.5707963267949 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 600 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 600 - type: LightBulb - components: - - parent: 599 - type: Transform - - anchored: False - type: Physics -- uid: 601 - type: ApcExtensionCableStack1 - components: - - parent: 216 - pos: -15.5,-0.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 602 - type: ApcExtensionCableStack1 - components: - - parent: 216 - pos: -15.5,-0.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 603 - type: solid_wall - components: - - parent: 216 - pos: 26.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 604 - type: solid_wall - components: - - parent: 216 - pos: 27.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 605 - type: Catwalk - components: - - parent: 216 - pos: -11.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 606 - type: Catwalk - components: - - parent: 216 - pos: -9.5,-6.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 607 - type: Poweredlight - components: - - parent: 216 - pos: -10.5,4 - rot: -1.5707963267949 rad - type: Transform - - color: '#FFFFFFFF' - type: PointLight - - containers: - light_bulb: - entities: - - 608 - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 608 - type: LightTube - components: - - parent: 607 - type: Transform - - anchored: False - type: Physics -- uid: 609 - type: MetalStack - components: - - parent: 216 - pos: -15.5,-4.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 610 - type: MetalStack - components: - - parent: 216 - pos: -15.5,-4.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 611 - type: solid_wall - components: - - parent: 216 - pos: 7.5,-4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 612 - type: solid_wall - components: - - parent: 216 - pos: 8.5,-4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 613 - type: solid_wall - components: - - parent: 216 - pos: 28.5,11.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 614 - type: solid_wall - components: - - parent: 216 - pos: 28.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 615 - type: solid_wall - components: - - parent: 216 - pos: 28.5,9.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 616 - type: solid_wall - components: - - parent: 216 - pos: 28.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 617 - type: solid_wall - components: - - parent: 216 - pos: 28.5,7.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 618 - type: solid_wall - components: - - parent: 216 - pos: 28.5,6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 619 - type: solid_wall - components: - - parent: 216 - pos: 28.5,5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 620 - type: solid_wall - components: - - parent: 216 - pos: 26.5,-2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 621 - type: solid_wall - components: - - parent: 216 - pos: 26.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 622 - type: solid_wall - components: - - parent: 216 - pos: 25.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 623 - type: solid_wall - components: - - parent: 216 - pos: 26.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 624 - type: solid_wall - components: - - parent: 216 - pos: 27.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 625 - type: Table - components: - - parent: 216 - pos: -15.5,-4.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 626 - type: Table - components: - - parent: 216 - pos: -15.5,-3.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 627 - type: Table - components: - - parent: 216 - pos: -15.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 628 - type: ApcExtensionCableStack1 - components: - - parent: 216 - pos: -15.5,0.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 629 - type: ApcExtensionCableStack1 - components: - - parent: 216 - pos: -15.5,0.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 630 - type: GlassStack - components: - - parent: 216 - pos: -15.5,-1.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 631 - type: GlassStack - components: - - parent: 216 - pos: -15.5,-1.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 632 - type: GlassStack - components: - - parent: 216 - pos: -15.5,-3.5 - rot: -1.5707963267949 rad - type: Transform - - anchored: False - type: Physics -- uid: 633 - type: VendingMachineEngivend - components: - - parent: 216 - pos: -11.5,0.5 - rot: -1.5707963267949 rad - type: Transform -- uid: 634 - type: Table - components: - - parent: 216 - pos: 18.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 635 - type: Table - components: - - parent: 216 - pos: 21.5,6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 636 - type: Table - components: - - parent: 216 - pos: 20.5,6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 637 - type: Table - components: - - parent: 216 - pos: 18.5,6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 638 - type: Table - components: - - parent: 216 - pos: 19.5,6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 639 - type: Table - components: - - parent: 216 - pos: 18.5,5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 640 - type: Table - components: - - parent: 216 - pos: 22.5,8.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 641 - type: Table - components: - - parent: 216 - pos: 24.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 642 - type: ChairOfficeLight - components: - - parent: 216 - pos: 19.5,4.5 - rot: 3.141592653589793 rad - type: Transform -- uid: 643 - type: ChairOfficeLight - components: - - parent: 216 - pos: 20.5,5.5 - rot: 1.5707963267948966 rad - type: Transform -- uid: 644 - type: ChairOfficeLight - components: - - parent: 216 - pos: 23.5,8.5 - rot: 3.141592653589793 rad - type: Transform -- uid: 645 - type: ChairOfficeLight - components: - - parent: 216 - pos: 24.5,5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 646 - type: Chair - components: - - parent: 216 - pos: 14.5,6.5 - type: Transform -- uid: 647 - type: Chair - components: - - parent: 216 - pos: 14.5,8.5 - type: Transform -- uid: 648 - type: Chair - components: - - parent: 216 - pos: 14.5,7.5 - type: Transform -- uid: 649 - type: chem_dispenser - components: - - parent: 216 - pos: 23.5,9.5 - type: Transform - - containers: - ReagentDispenser-reagentContainerContainer: - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 650 - type: Table - components: - - parent: 216 - pos: 23.5,7.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 651 - type: Catwalk - components: - - parent: 216 - pos: 0.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 652 - type: Table - components: - - parent: 216 - pos: 25.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 653 - type: Table - components: - - parent: 216 - pos: 23.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 654 - type: Table - components: - - parent: 216 - pos: 24.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 655 - type: Table - components: - - parent: 216 - pos: 26.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 656 - type: Table - components: - - parent: 216 - pos: 27.5,10.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 657 - type: ComputerMedicalRecords - components: - - parent: 216 - pos: 21.5,5.5 - rot: 3.141592653589793 rad - type: Transform - - deadThreshold: 100 - type: BreakableConstruction -- uid: 658 - type: MedicalScanner - components: - - parent: 216 - pos: 18.5,-1.5 - rot: 3.141592653589793 rad - type: Transform - - containers: - MedicalScanner-bodyContainer: - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 659 - type: MedicalScanner - components: - - parent: 216 - pos: 18.5,-5.5 - rot: 3.141592653589793 rad - type: Transform - - containers: - MedicalScanner-bodyContainer: - type: Content.Server.GameObjects.ContainerSlot - type: ContainerContainer -- uid: 660 - type: Table - components: - - parent: 216 - pos: 13.5,2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 661 - type: Table - components: - - parent: 216 - pos: 13.5,0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 662 - type: Table - components: - - parent: 216 - pos: 13.5,1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 663 - type: solid_wall - components: - - parent: 216 - pos: 22.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 664 - type: solid_wall - components: - - parent: 216 - pos: 17.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 665 - type: solid_wall - components: - - parent: 216 - pos: 18.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 666 - type: solid_wall - components: - - parent: 216 - pos: 20.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 667 - type: solid_wall - components: - - parent: 216 - pos: 21.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 668 - type: solid_wall - components: - - parent: 216 - pos: 19.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 669 - type: solid_wall - components: - - parent: 216 - pos: 14.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 670 - type: solid_wall - components: - - parent: 216 - pos: 13.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 671 - type: solid_wall - components: - - parent: 216 - pos: 12.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 672 - type: solid_wall - components: - - parent: 216 - pos: 12.5,2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 673 - type: solid_wall - components: - - parent: 216 - pos: 12.5,1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 674 - type: solid_wall - components: - - parent: 216 - pos: 12.5,0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 675 - type: solid_wall - components: - - parent: 216 - pos: 12.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 676 - type: solid_wall - components: - - parent: 216 - pos: 13.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 677 - type: solid_wall - components: - - parent: 216 - pos: 14.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 678 - type: solid_wall - components: - - parent: 216 - pos: 13.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 679 - type: solid_wall - components: - - parent: 216 - pos: 13.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 680 - type: solid_wall - components: - - parent: 216 - pos: 13.5,-5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 681 - type: solid_wall - components: - - parent: 216 - pos: 13.5,-4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 682 - type: solid_wall - components: - - parent: 216 - pos: 13.5,-3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 683 - type: solid_wall - components: - - parent: 216 - pos: 13.5,-2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 684 - type: solid_wall - components: - - parent: 216 - pos: 14.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 685 - type: solid_wall - components: - - parent: 216 - pos: 15.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 686 - type: solid_wall - components: - - parent: 216 - pos: 16.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 687 - type: solid_wall - components: - - parent: 216 - pos: 17.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 688 - type: solid_wall - components: - - parent: 216 - pos: 18.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 689 - type: solid_wall - components: - - parent: 216 - pos: 19.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 690 - type: solid_wall - components: - - parent: 216 - pos: 20.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 691 - type: solid_wall - components: - - parent: 216 - pos: 21.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 692 - type: solid_wall - components: - - parent: 216 - pos: 22.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 693 - type: solid_wall - components: - - parent: 216 - pos: 23.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 694 - type: solid_wall - components: - - parent: 216 - pos: 24.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 695 - type: solid_wall - components: - - parent: 216 - pos: 25.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 696 - type: solid_wall - components: - - parent: 216 - pos: 26.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 697 - type: solid_wall - components: - - parent: 216 - pos: 26.5,-5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 698 - type: solid_wall - components: - - parent: 216 - pos: 26.5,-4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 699 - type: solid_wall - components: - - parent: 216 - pos: 27.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 700 - type: solid_wall - components: - - parent: 216 - pos: 28.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 701 - type: solid_wall - components: - - parent: 216 - pos: 29.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 702 - type: solid_wall - components: - - parent: 216 - pos: 30.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 703 - type: solid_wall - components: - - parent: 216 - pos: 31.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 704 - type: solid_wall - components: - - parent: 216 - pos: 32.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 705 - type: solid_wall - components: - - parent: 216 - pos: 33.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 706 - type: solid_wall - components: - - parent: 216 - pos: 34.5,-6.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 707 - type: solid_wall - components: - - parent: 216 - pos: 34.5,-5.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 708 - type: solid_wall - components: - - parent: 216 - pos: 34.5,-4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 709 - type: solid_wall - components: - - parent: 216 - pos: 34.5,-3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 710 - type: solid_wall - components: - - parent: 216 - pos: 34.5,-2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 711 - type: solid_wall - components: - - parent: 216 - pos: 34.5,-1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 712 - type: solid_wall - components: - - parent: 216 - pos: 34.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 713 - type: solid_wall - components: - - parent: 216 - pos: 33.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 714 - type: solid_wall - components: - - parent: 216 - pos: 32.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 715 - type: solid_wall - components: - - parent: 216 - pos: 31.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 716 - type: solid_wall - components: - - parent: 216 - pos: 30.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 717 - type: solid_wall - components: - - parent: 216 - pos: 29.5,-0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 718 - type: solid_wall - components: - - parent: 216 - pos: 30.5,0.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 719 - type: solid_wall - components: - - parent: 216 - pos: 30.5,1.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 720 - type: solid_wall - components: - - parent: 216 - pos: 30.5,2.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 721 - type: solid_wall - components: - - parent: 216 - pos: 30.5,3.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 722 - type: solid_wall - components: - - parent: 216 - pos: 30.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 723 - type: solid_wall - components: - - parent: 216 - pos: 29.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 724 - type: solid_wall - components: - - parent: 216 - pos: 28.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -- uid: 725 - type: solid_wall - components: - - parent: 216 - pos: 27.5,4.5 - rot: -1.5707963267948966 rad - type: Transform -... diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml index ba9ee9ec27..5be4593ab4 100644 --- a/Resources/Prototypes/Alerts/alerts.yml +++ b/Resources/Prototypes/Alerts/alerts.yml @@ -29,7 +29,9 @@ - type: alert alertType: LowPressure category: Pressure - icon: /Textures/Interface/Alerts/Pressure/lowpressure.png + icon: + sprite: /Textures/Interface/Alerts/pressure.rsi + state: lowpressure maxSeverity: 2 name: "[color=red]Low Pressure[/color]" description: "The air around you is [color=red]hazardously thin[/color]. A [color=green]space suit[/color] would protect you." @@ -37,7 +39,9 @@ - type: alert alertType: HighPressure category: Pressure - icon: /Textures/Interface/Alerts/Pressure/highpressure.png + icon: + sprite: /Textures/Interface/Alerts/pressure.rsi + state: highpressure maxSeverity: 2 name: "[color=red]High Pressure[/color]" description: "The air around you is [color=red]hazardously thick[/color]. A [color=green]pressurized suit[/color] would be enough protect you" @@ -52,7 +56,9 @@ - type: alert alertType: Cold category: Temperature - icon: /Textures/Interface/Alerts/Temperature/cold.png + icon: + sprite: /Textures/Interface/Alerts/temperature.rsi + state: cold maxSeverity: 3 name: "[color=cyan]Too Cold[/color]" description: "You're [color=cyan]freezing cold![/color] Get somewhere warmer and take off any insulating clothing like a space suit." @@ -60,7 +66,9 @@ - type: alert alertType: Hot category: Temperature - icon: /Textures/Interface/Alerts/Temperature/hot.png + icon: + sprite: /Textures/Interface/Alerts/temperature.rsi + state: hot maxSeverity: 3 name: "[color=red]Too Hot[/color]" description: "It's [color=red]too hot![/color] Flee to space or at least away from the flames. Standing on weeds will heal you." @@ -70,7 +78,7 @@ icon: /Textures/Interface/Alerts/Weightless/weightless.png name: Weightless description: > - Gravity has ceased affecting you, and you're floating around aimlessly. Find something sturdy to hold onto, or throw or shoot something in a direction opposite of you. + Gravity has ceased affecting you, and you're floating around aimlessly. Find something sturdy to hold onto, or throw or shoot something in a direction opposite of you. Mag-boots or jetpacks would help you move with more control - type: alert @@ -96,21 +104,27 @@ - type: alert alertType: HumanCrit category: Health - icon: /Textures/Interface/Alerts/Human/humancrit-0.png + icon: + sprite: /Textures/Interface/Alerts/human_health.rsi + state: health6 name: "[color=red]Critical Condition[/color]" description: "You're severely injured and unconscious." - type: alert alertType: HumanDead category: Health - icon: /Textures/Interface/Alerts/Human/humandead.png + icon: + sprite: /Textures/Interface/Alerts/human_health.rsi + state: health7 name: Dead description: You're dead, note that you can still be revived! - type: alert alertType: HumanHealth category: Health - icon: /Textures/Interface/Alerts/Human/human.png + icon: + sprite: /Textures/Interface/Alerts/human_health.rsi + state: health name: Health description: "[color=green]Green[/color] good. [color=red]Red[/color] bad." minSeverity: 0 diff --git a/Resources/Prototypes/Catalog/LatheRecipes/botany.yml b/Resources/Prototypes/Catalog/LatheRecipes/botany.yml index 57d7115d1c..d011c676da 100644 --- a/Resources/Prototypes/Catalog/LatheRecipes/botany.yml +++ b/Resources/Prototypes/Catalog/LatheRecipes/botany.yml @@ -30,3 +30,26 @@ materials: steel: 60 glass: 10 + +- type: latheRecipe + id: Shovel + icon: + sprite: Constructible/Hydroponics/hydro_tools.rsi + state: shovel + result: Shovel + completetime: 500 + materials: + steel: 60 + glass: 10 + +- type: latheRecipe + id: Spade + icon: + sprite: Constructible/Hydroponics/hydro_tools.rsi + state: spade + result: Spade + completetime: 500 + materials: + steel: 30 + glass: 10 + diff --git a/Resources/Prototypes/Entities/Constructible/Furniture/beds.yml b/Resources/Prototypes/Entities/Constructible/Furniture/beds.yml index 173ef58fd1..33ed616d29 100644 --- a/Resources/Prototypes/Entities/Constructible/Furniture/beds.yml +++ b/Resources/Prototypes/Entities/Constructible/Furniture/beds.yml @@ -13,12 +13,6 @@ bounds: "-0.45, -0.45, 0.05, 0.45" mask: - Impassable - - MobImpassable - - VaultImpassable - - SmallImpassable - layer: - - Opaque - - MobImpassable - VaultImpassable - SmallImpassable - type: Sprite diff --git a/Resources/Prototypes/Entities/Constructible/Ground/gasgenerator.yml b/Resources/Prototypes/Entities/Constructible/Ground/gasgenerator.yml new file mode 100644 index 0000000000..028b736c17 --- /dev/null +++ b/Resources/Prototypes/Entities/Constructible/Ground/gasgenerator.yml @@ -0,0 +1,45 @@ +- type: entity + abstract: true + id: GasGeneratorBase + placement: + mode: SnapgridCenter + components: + - type: Clickable + - type: InteractionOutline + - type: Physics + anchored: true + shapes: + - !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,0.5" + layer: + - Impassable + - MobImpassable + - VaultImpassable + - Opaque + mask: + - Impassable + - MobImpassable + - VaultImpassable + - type: SnapGrid + offset: Center + - type: GasGenerator + +- type: entity + parent: GasGeneratorBase + id: GasGenerator + name: gas generator + description: Fabricates gas. + components: + - type: Sprite + netsync: false + sprite: Constructible/Atmos/gasgenerator.rsi + layers: + - sprite: Constructible/Atmos/pipe.rsi + state: pipeFourway + - state: gasGenerator + - type: NodeContainer + nodes: + - !type:PipeNode + nodeGroupID: Pipe + pipeDirection: Fourway + diff --git a/Resources/Prototypes/Entities/Constructible/Power/lathe.yml b/Resources/Prototypes/Entities/Constructible/Power/lathe.yml index 16c48e451f..9bfa935619 100644 --- a/Resources/Prototypes/Entities/Constructible/Power/lathe.yml +++ b/Resources/Prototypes/Entities/Constructible/Power/lathe.yml @@ -77,6 +77,11 @@ - CableStack - Crowbar - Multitool + - MiniHoe + - Scythe + - Hatchet + - Shovel + - Spade - type: Appearance visuals: - type: AutolatheVisualizer diff --git a/Resources/Prototypes/Entities/Constructible/Specific/Cooking/microwave.yml b/Resources/Prototypes/Entities/Constructible/Specific/Cooking/microwave.yml index 629bcfd5b3..cd7565c4db 100644 --- a/Resources/Prototypes/Entities/Constructible/Specific/Cooking/microwave.yml +++ b/Resources/Prototypes/Entities/Constructible/Specific/Cooking/microwave.yml @@ -12,7 +12,7 @@ - type: InteractionOutline - type: SolutionContainer maxVol: 100 - caps: AddTo + caps: Refillable - type: Appearance visuals: - type: MicrowaveVisualizer diff --git a/Resources/Prototypes/Entities/Constructible/Specific/Dispensers/booze_dispenser.yml b/Resources/Prototypes/Entities/Constructible/Specific/Dispensers/booze_dispenser.yml index 66b2844c9e..24b5de3306 100644 --- a/Resources/Prototypes/Entities/Constructible/Specific/Dispensers/booze_dispenser.yml +++ b/Resources/Prototypes/Entities/Constructible/Specific/Dispensers/booze_dispenser.yml @@ -21,3 +21,4 @@ - chem.Vodka - chem.Cognac - chem.Kahlua + - chem.Rum diff --git a/Resources/Prototypes/Entities/Constructible/Specific/Dispensers/chem_dispenser.yml b/Resources/Prototypes/Entities/Constructible/Specific/Dispensers/chem_dispenser.yml index f7de3d2bf4..92840e7a79 100644 --- a/Resources/Prototypes/Entities/Constructible/Specific/Dispensers/chem_dispenser.yml +++ b/Resources/Prototypes/Entities/Constructible/Specific/Dispensers/chem_dispenser.yml @@ -21,6 +21,7 @@ - chem.Water - chem.Ethanol - chem.Glucose + - chem.Sugar - chem.Hydrogen - chem.Oxygen - chem.Sulfur diff --git a/Resources/Prototypes/Entities/Constructible/Specific/hydroponics.yml b/Resources/Prototypes/Entities/Constructible/Specific/hydroponics.yml index 416b1324de..ab9faa97dd 100644 --- a/Resources/Prototypes/Entities/Constructible/Specific/hydroponics.yml +++ b/Resources/Prototypes/Entities/Constructible/Specific/hydroponics.yml @@ -38,8 +38,7 @@ drawWarnings: false - type: SolutionContainer maxVol: 200 - caps: AddTo - - type: Pourable + caps: Refillable - type: SnapGrid offset: Center - type: Appearance diff --git a/Resources/Prototypes/Entities/Constructible/Storage/StorageTanks/base_tank.yml b/Resources/Prototypes/Entities/Constructible/Storage/StorageTanks/base_tank.yml index 98d0b7efda..54110ab38d 100644 --- a/Resources/Prototypes/Entities/Constructible/Storage/StorageTanks/base_tank.yml +++ b/Resources/Prototypes/Entities/Constructible/Storage/StorageTanks/base_tank.yml @@ -33,9 +33,9 @@ acts: ["Destruction"] - type: SolutionContainer maxVol: 1500 - caps: RemoveFrom - - type: Pourable - transferAmount: 100.0 + caps: Drainable + - type: ReagentTank + placement: snap: - Wall diff --git a/Resources/Prototypes/Entities/Constructible/Storage/StorageTanks/fuel_tank.yml b/Resources/Prototypes/Entities/Constructible/Storage/StorageTanks/fuel_tank.yml index 5249cb04ea..f66808039f 100644 --- a/Resources/Prototypes/Entities/Constructible/Storage/StorageTanks/fuel_tank.yml +++ b/Resources/Prototypes/Entities/Constructible/Storage/StorageTanks/fuel_tank.yml @@ -17,9 +17,7 @@ reagents: - ReagentId: chem.WeldingFuel Quantity: 1500 - - type: DamageOnToolInteract - damage: 200 - tools: - - Welding - type: Anchorable - type: Pullable + - type: ReagentTank + tankType: Fuel diff --git a/Resources/Prototypes/Entities/Constructible/Walls/bar_sign.yml b/Resources/Prototypes/Entities/Constructible/Walls/bar_sign.yml index 9f396756c2..99f1d83ffe 100644 --- a/Resources/Prototypes/Entities/Constructible/Walls/bar_sign.yml +++ b/Resources/Prototypes/Entities/Constructible/Walls/bar_sign.yml @@ -38,18 +38,3 @@ components: - type: BarSign current: EngineChange - -- type: entity - id: BarSignCyberSylph - name: Cyber Sylph - parent: LargeBarSign - components: - - type: BarSign - current: CyberSylph - - type: Physics - shapes: - - !type:PhysShapeAabb - bounds: "-0.45, -0.95, 0.95, 1.5" - layer: [ Passable ] - - type: Sprite - drawdepth: Ghosts diff --git a/Resources/Prototypes/Entities/Constructible/Walls/windows.yml b/Resources/Prototypes/Entities/Constructible/Walls/windows.yml index c63b189159..9f9778ae6e 100644 --- a/Resources/Prototypes/Entities/Constructible/Walls/windows.yml +++ b/Resources/Prototypes/Entities/Constructible/Walls/windows.yml @@ -46,7 +46,6 @@ - type: Airtight - type: Window base: window - maxDamage: 15 - type: Construction graph: window node: window @@ -81,7 +80,6 @@ acts: [ "Destruction" ] - type: Window base: rwindow - maxDamage: 75 - type: Construction graph: window node: reinforcedWindow @@ -114,7 +112,6 @@ resistances: metallicResistances - type: Window base: pwindow - maxDamage: 100 - type: Construction graph: window node: phoronWindow diff --git a/Resources/Prototypes/Entities/Effects/Markers/clientsideclone.yml b/Resources/Prototypes/Entities/Effects/Markers/clientsideclone.yml new file mode 100644 index 0000000000..a3c662c28a --- /dev/null +++ b/Resources/Prototypes/Entities/Effects/Markers/clientsideclone.yml @@ -0,0 +1,8 @@ +- type: entity + name: clientsideclone + id: clientsideclone + abstract: true + components: + - type: Sprite + - type: Physics + - type: AnimationPlayer diff --git a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml new file mode 100644 index 0000000000..00e78fce7f --- /dev/null +++ b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml @@ -0,0 +1,149 @@ +- type: entity + id: Smoke + name: smoke + abstract: true + components: + - type: Sprite + drawdepth: Effects + sprite: Effects/chemsmoke.rsi + state: chemsmoke + - type: Appearance + visuals: + - type: SmokeVisualizer + - type: Occluder + sizeX: 32 + sizeY: 32 + - type: SnapGrid + offset: Center + - type: SmokeSolutionAreaEffect + - type: SolutionContainer + maxVol: 600 + +- type: entity + id: Foam + name: foam + abstract: true + components: + - type: Sprite + netsync: false + drawdepth: Effects + color: "#ffffffcc" #Add some transparency + sprite: Effects/foam.rsi + state: foam + layers: + - state: foam + map: ["enum.FoamVisualLayers.Base"] + - type: AnimationPlayer + - type: Appearance + visuals: + - type: FoamVisualizer + animationTime: 0.6 + animationState: foam-dissolve + - type: SnapGrid + offset: Center + - type: Physics + shapes: + - !type:PhysShapeAabb + bounds: "-0.4,-0.4,0.4,0.4" + layer: + - MobImpassable + - type: FoamSolutionAreaEffect + - type: SolutionContainer + maxVol: 600 + - type: Slippery + +- type: entity + id: IronMetalFoam + name: iron metal foam + abstract: true + parent: Foam + components: + - type: Sprite + state: mfoam + layers: + - state: mfoam + map: ["enum.FoamVisualLayers.Base"] + - type: Appearance + visuals: + - type: FoamVisualizer + animationTime: 0.6 + animationState: mfoam-dissolve + - type: FoamSolutionAreaEffect + foamedMetalPrototype: FoamedIronMetal + +- type: entity + id: AluminiumMetalFoam + name: aluminium metal foam + abstract: true + parent: Foam + components: + - type: Sprite + state: mfoam + layers: + - state: mfoam + map: ["enum.FoamVisualLayers.Base"] + - type: Appearance + visuals: + - type: FoamVisualizer + animationTime: 0.6 + animationState: mfoam-dissolve + - type: FoamSolutionAreaEffect + foamedMetalPrototype: FoamedAluminiumMetal + +- type: entity + id: BaseFoamedMetal + name: base foamed metal + description: Keeps the air in and the greytide out. + abstract: true + placement: + mode: SnapgridCenter + snap: + - Wall + components: + - type: RCDDeconstructWhitelist + - type: Clickable + - type: InteractionOutline + - type: Sprite + netsync: false + drawdepth: Walls + - type: Physics + shapes: + - !type:PhysShapeAabb + layer: + - Opaque + - Impassable + - MobImpassable + - VaultImpassable + - SmallImpassable + - type: Occluder + sizeX: 32 + sizeY: 32 + - type: SnapGrid + offset: Center + - type: Airtight + - type: Damageable + resistances: metallicResistances + - type: Destructible + thresholds: + 50: + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + +- type: entity + id: FoamedIronMetal + name: foamed iron metal + parent: BaseFoamedMetal + components: + - type: Sprite + sprite: Effects/foam.rsi + state: ironfoam + +- type: entity + id: FoamedAluminiumMetal + name: foamed aluminium metal + parent: BaseFoamedMetal + components: + - type: Sprite + sprite: Effects/foam.rsi + state: metalfoam diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index afe8be1e5b..fda0135061 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -15,7 +15,6 @@ innateActions: - HumanScream - Disarm - - type: OverlayEffectsUI - type: Eye zoom: 0.5, 0.5 - type: CameraRecoil diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index e85e369fe1..3f9254499c 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -20,7 +20,7 @@ # Organs - type: SolutionContainer maxVol: 250 - caps: AddTo, RemoveFrom + caps: Injectable, Drawable - type: Bloodstream max_volume: 100 # StatusEffects @@ -196,6 +196,7 @@ - type: Pullable - type: DoAfter - type: CreamPied + - type: Stripping - type: Strippable - type: UserInterface interfaces: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/drinks.yml index c01489c8d5..545c343390 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/drinks.yml @@ -1,4 +1,4 @@ -# TODO: Find remaining cans and move to drinks_cans +# TODO: Find remaining cans and move to drinks_cans # TODO: Find empty containers (e.g. mug, pitcher) and move to their own yml # TODO: Move bottles to their own yml - type: entity @@ -8,7 +8,7 @@ components: - type: SolutionContainer maxVol: 50 - - type: Pourable + - type: SolutionTransfer transferAmount: 5 - type: Drink - type: Sprite @@ -55,7 +55,7 @@ - type: SolutionContainer fillingState: glass maxVol: 50 - - type: Pourable + - type: SolutionTransfer transferAmount: 5 - type: TransformableContainer diff --git a/Resources/Prototypes/Entities/Objects/Consumable/drinks_bottles.yml b/Resources/Prototypes/Entities/Objects/Consumable/drinks_bottles.yml index 82da85a1da..1dce8418b5 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/drinks_bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/drinks_bottles.yml @@ -6,7 +6,8 @@ - type: Drink openSounds: bottleOpenSounds - type: SolutionContainer - - type: Pourable + maxVol: 100 + - type: SolutionTransfer transferAmount: 5 - type: Sprite state: icon @@ -34,13 +35,17 @@ - type: entity parent: DrinkBottleBaseFull id: DrinkAbsintheBottleFull - name: jailbreaker verte + name: Jailbreaker Verte description: One sip of this and you just know you're gonna have a good time. components: - type: Drink - type: Sprite sprite: Objects/Consumable/Drinks/absinthebottle.rsi - + - type: SolutionContainer + contents: + reagents: + - ReagentId: chem.Absinthe + Quantity: 100 - type: entity parent: DrinkBottleBaseFull @@ -56,15 +61,15 @@ - type: entity parent: DrinkBottleBaseFull id: DrinkAleBottleFull - name: magm-ale + name: Magm-Ale description: A true dorf's drink of choice. components: - type: SolutionContainer - maxVol: 80 + maxVol: 100 contents: reagents: - ReagentId: chem.Ale - Quantity: 80 + Quantity: 100 - type: Sprite sprite: Objects/Consumable/Drinks/alebottle.rsi @@ -87,11 +92,10 @@ description: A sweet and strongly alchoholic drink, made after numerous distillations and years of maturing. You might as well not scream 'SHITCURITY' this time. components: - type: SolutionContainer - maxVol: 80 contents: reagents: - ReagentId: chem.Cognac - Quantity: 80 + Quantity: 100 - type: Sprite sprite: Objects/Consumable/Drinks/cognacbottle.rsi @@ -99,13 +103,17 @@ - type: entity parent: DrinkBottleBaseFull id: DrinkGinBottleFull - name: griffeater gin bottle + name: Griffeater Gin description: A bottle of high quality gin, produced in the New London Space Station. components: - type: Drink - type: Sprite sprite: Objects/Consumable/Drinks/ginbottle.rsi - + - type: SolutionContainer + contents: + reagents: + - ReagentId: chem.Gin + Quantity: 100 - type: entity parent: DrinkBottleBaseFull diff --git a/Resources/Prototypes/Entities/Objects/Consumable/drinks_cans.yml b/Resources/Prototypes/Entities/Objects/Consumable/drinks_cans.yml index d1e0e53cd8..7c44c0888e 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/drinks_cans.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/drinks_cans.yml @@ -8,12 +8,12 @@ pressurized: true - type: SolutionContainer maxVol: 20 - caps: AddTo, RemoveFrom + caps: None contents: reagents: - ReagentId: chem.Cola Quantity: 20 - - type: Pourable + - type: SolutionTransfer transferAmount: 5 - type: Sprite state: icon diff --git a/Resources/Prototypes/Entities/Objects/Consumable/drinks_cups.yml b/Resources/Prototypes/Entities/Objects/Consumable/drinks_cups.yml index 5094bb3266..a263bf2d13 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/drinks_cups.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/drinks_cups.yml @@ -7,7 +7,7 @@ components: - type: SolutionContainer maxVol: 20 - - type: Pourable + - type: SolutionTransfer transferAmount: 5 - type: Drink isOpen: true diff --git a/Resources/Prototypes/Entities/Objects/Consumable/kitchen_reagent_containers.yml b/Resources/Prototypes/Entities/Objects/Consumable/kitchen_reagent_containers.yml index 3a0fc6f0d4..ac3e0b1beb 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/kitchen_reagent_containers.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/kitchen_reagent_containers.yml @@ -10,7 +10,7 @@ reagents: - ReagentId: chem.Flour Quantity: 50 - - type: Pourable + - type: SolutionTransfer transferAmount: 5 - type: Drink - type: Sprite diff --git a/Resources/Prototypes/Entities/Objects/Consumable/trash.yml b/Resources/Prototypes/Entities/Objects/Consumable/trash.yml index 71490e6b8b..deabc3b5df 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/trash.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/trash.yml @@ -152,18 +152,7 @@ components: - type: Sprite sprite: Objects/Consumable/Trash/tastybread.rsi - - -- type: entity - name: trash bag - parent: TrashBase - id: TrashBag - components: - - type: Sprite - sprite: Objects/Consumable/Trash/trashbag.rsi - - - type: Storage - capacity: 125 + - type: entity name: tray (trash) diff --git a/Resources/Prototypes/Entities/Objects/Consumable/trash_drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/trash_drinks.yml index 5364681a1f..ab854aa184 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/trash_drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/trash_drinks.yml @@ -12,7 +12,7 @@ - type: SolutionContainer maxVol: 10 - - type: Pourable + - type: SolutionTransfer transferAmount: 5 - type: Drink isOpen: true diff --git a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml index 7070e43629..77c85606d3 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml @@ -14,7 +14,7 @@ size: 10 - type: SolutionContainer maxVol: 100 - caps: AddTo, RemoveFrom + caps: Refillable, Drainable contents: reagents: - ReagentId: chem.Water diff --git a/Resources/Prototypes/Entities/Objects/Power/powercells.yml b/Resources/Prototypes/Entities/Objects/Power/powercells.yml index d94314de03..e9d51da5ce 100644 --- a/Resources/Prototypes/Entities/Objects/Power/powercells.yml +++ b/Resources/Prototypes/Entities/Objects/Power/powercells.yml @@ -15,6 +15,10 @@ - type: PowerCell - type: Sprite netsync: false + - type: SolutionContainer + maxVol: 5 + caps: Injectable, Drawable + - type: entity id: PowerCellSmallBase diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml index 28bfe4a37c..ecb95dc641 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml @@ -13,8 +13,8 @@ - type: SolutionContainer fillingState: beaker maxVol: 50 - caps: CanExamine, AddTo, RemoveFrom, FitsInDispenser # can add and remove solutions and fits in the chemmaster. - - type: Pourable + caps: OpenContainer, FitsInDispenser # can add and remove solutions and fits in the chemmaster. + - type: SolutionTransfer transferAmount: 5.0 - type: Spillable - type: GlassBeaker @@ -34,8 +34,8 @@ - type: SolutionContainer fillingState: beakerlarge maxVol: 100 - caps: CanExamine, AddTo, RemoveFrom, FitsInDispenser - - type: Pourable + caps: OpenContainer, FitsInDispenser + - type: SolutionTransfer transferAmount: 5.0 - type: Spillable - type: GlassBeaker @@ -53,7 +53,7 @@ fillingState: dropper fillingSteps: 2 maxVol: 5 - - type: Pourable + - type: SolutionTransfer transferAmount: 5.0 - type: Spillable @@ -85,13 +85,13 @@ - type: Drink - type: SolutionContainer maxVol: 30 - - type: Pourable + - type: SolutionTransfer transferAmount: 5 - type: Spillable - type: entity name: pill - parent: FoodBase + parent: BaseItem id: pill description: It's not a suppository. components: diff --git a/Resources/Prototypes/Entities/Objects/Specific/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/janitor.yml index 4b4ba32251..2aea0da9b9 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/janitor.yml @@ -198,8 +198,8 @@ state: cleaner - type: SolutionContainer maxVol: 100 - caps: AddTo, RemoveFrom - - type: Pourable + caps: Refillable, Drainable + - type: SolutionTransfer transferAmount: 5.0 - type: Spillable - type: ItemCooldown @@ -234,3 +234,18 @@ reagents: - ReagentId: chem.SpaceCleaner Quantity: 100 + + +- type: entity + name: trash bag + id: TrashBag + parent: BaseItem + components: + - type: Sprite + sprite: Objects/Specific/Janitorial/trashbag.rsi + state: icon + - type: Storage + capacity: 125 + quickInsert: true + areaInsert: true + storageSoundCollection: trashBagRustle diff --git a/Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml b/Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml index 7bea165c02..7c9c5c04bd 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/rehydrateable.yml @@ -10,7 +10,7 @@ - ReagentId: chem.Nutriment Quantity: 10 maxVol: 11 # needs room for water - caps: AddTo + caps: Refillable - type: Sprite sprite: Objects/Consumable/Food/monkeycube.rsi - type: Rehydratable @@ -28,6 +28,6 @@ - ReagentId: chem.Nutriment Quantity: 10 maxVol: 11 # needs room for water - caps: AddTo + caps: Refillable - type: Rehydratable target: CarpMob_Content diff --git a/Resources/Prototypes/Entities/Objects/Tools/botany_tools.yml b/Resources/Prototypes/Entities/Objects/Tools/botany_tools.yml index b4dceedbf2..9f65f81ba3 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/botany_tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/botany_tools.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity name: mini hoe parent: BaseItem id: MiniHoe @@ -24,7 +24,7 @@ state: plantbgone - type: SolutionContainer maxVol: 100 - caps: RemoveFrom + caps: Drainable contents: reagents: - ReagentId: chem.PlantBGone @@ -42,12 +42,12 @@ state: weedspray - type: SolutionContainer maxVol: 50 - caps: RemoveFrom + caps: Drainable contents: reagents: - ReagentId: chem.WeedKiller Quantity: 50 - - type: Pourable + - type: SolutionTransfer transferAmount: 1.0 - type: Spillable - type: ItemCooldown @@ -65,7 +65,7 @@ state: pestspray - type: SolutionContainer maxVol: 50 - caps: RemoveFrom + caps: Drainable contents: reagents: - ReagentId: chem.PestKiller @@ -98,3 +98,32 @@ - type: MeleeWeapon - type: BotanySharp - type: Item + +- type: entity + name: spade + parent: BaseItem + id: Spade + description: A small tool for digging and moving dirt. + components: + - type: Sprite + sprite: Constructible/Hydroponics/hydro_tools.rsi + state: spade + - type: ItemCooldown + - type: MeleeWeapon + - type: Shovel + - type: Item + +- type: entity + name: shovel + parent: BaseItem + id: Shovel + description: A large tool for digging and moving dirt. + components: + - type: Sprite + sprite: Constructible/Hydroponics/hydro_tools.rsi + state: shovel + - type: ItemCooldown + - type: MeleeWeapon + - type: Shovel + - type: Item + diff --git a/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml b/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml index 0545aad5fd..df9d23c359 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity name: haycutters parent: BaseItem id: Haycutters @@ -114,7 +114,7 @@ - type: ItemStatus - type: SolutionContainer maxVol: 50 - caps: AddTo + caps: Refillable contents: reagents: - ReagentId: chem.WeldingFuel diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index 7906328243..3827ccd87a 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -20,7 +20,7 @@ - type: ItemStatus - type: SolutionContainer maxVol: 100 - caps: AddTo + caps: Refillable contents: reagents: - ReagentId: chem.WeldingFuel @@ -44,7 +44,7 @@ sprite: Objects/Tools/welder_experimental.rsi - type: SolutionContainer maxVol: 1000 - caps: AddTo + caps: Refillable contents: reagents: - ReagentId: chem.WeldingFuel @@ -66,7 +66,7 @@ sprite: Objects/Tools/welder_mini.rsi - type: SolutionContainer maxVol: 25 - caps: AddTo + caps: Refillable contents: reagents: - ReagentId: chem.WeldingFuel diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Shotgun/cartridges.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Shotgun/cartridges.yml index c6a37c4017..dbe23a0384 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Shotgun/cartridges.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Shotgun/cartridges.yml @@ -102,5 +102,5 @@ - type: ChemicalAmmo - type: SolutionContainer maxVol: 15 - caps: AddTo, RemoveFrom - - type: Pourable \ No newline at end of file + caps: Refillable, Drainable + - type: SolutionTransfer diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Shotgun/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Shotgun/projectiles.yml index a60c07a38b..d3ed06e0ee 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Shotgun/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Shotgun/projectiles.yml @@ -91,6 +91,6 @@ Blunt: 1 - type: SolutionContainer maxVol: 15 - caps: AddTo, RemoveFrom + caps: Refillable, Drainable - type: ChemicalInjectionProjectile transferAmount: 15 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml index 6df83f9c61..d73b704788 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity name: spear parent: BaseItem id: Spear @@ -22,7 +22,7 @@ - type: MeleeChemicalInjector - type: SolutionContainer maxVol: 5 - - type: Pourable + - type: SolutionTransfer - type: MeleeWeaponAnimation id: spear diff --git a/Resources/Prototypes/Entities/Objects/hypospray.yml b/Resources/Prototypes/Entities/Objects/hypospray.yml new file mode 100644 index 0000000000..77b16231c6 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/hypospray.yml @@ -0,0 +1,15 @@ +- type: entity + name: hypospray + parent: BaseItem + description: A sterile injector for rapid administration of drugs to patients. + id: Hypospray + components: + - type: Sprite + sprite: Objects/Specific/Medical/hypospray.rsi + state: hypo + - type: Item + sprite: Objects/Specific/Medical/hypospray.rsi + - type: SolutionContainer + maxVol: 30 + caps: Refillable, CanExamine + - type: Hypospray diff --git a/Resources/Prototypes/Reagents/chemicals.yml b/Resources/Prototypes/Reagents/chemicals.yml index d7af2363f1..2a67394e45 100644 --- a/Resources/Prototypes/Reagents/chemicals.yml +++ b/Resources/Prototypes/Reagents/chemicals.yml @@ -126,6 +126,15 @@ - !type:AdjustHealth amount: -8 +- type: reagent + id: chem.FluorosulfuricAcid + name: fluorosulfuric acid + desc: An extremely corrosive chemical substance. + physicalDecs: strong-smelling + color: "#5050ff" + boilingPoint: 165 + meltingPoint: -87 + - type: reagent id: chem.TableSalt name: table salt @@ -241,3 +250,13 @@ meltingPoint: -80.7 tileReactions: - !type:FlammableTileReaction {} + +- type: reagent + id: chem.Fluorosurfactant + name: fluorosurfactant + desc: A perfluoronated sulfonic acid that forms a foam when mixed with water. + physicalDesc: opaque + color: "#9e6b38" + boilingPoint: 190.0 # Perfluorooctanoic Acid. + meltingPoint: 45.0 + diff --git a/Resources/Prototypes/Reagents/drinks.yml b/Resources/Prototypes/Reagents/drinks.yml index 1173cb83d6..f11b3ec508 100644 --- a/Resources/Prototypes/Reagents/drinks.yml +++ b/Resources/Prototypes/Reagents/drinks.yml @@ -1,3 +1,11 @@ +- type: reagent + id: chem.Absinthe + name: absinthe + desc: One sip of this and you just know you're gonna have a good time. + spritePath: absintheglass.rsi + color: "#33EE00" + physicalDesc: strong-smelling + - type: reagent id: chem.Whiskey name: whiskey @@ -38,9 +46,26 @@ - type: reagent id: chem.Vodka name: vodka - desc: The glass contain wodka. Xynta. + desc: The glass contain wodka. Хуета. physicalDesc: strong-smelling color: "#d1d1d155" + spritePath: ginvodkaglass.rsi + +- type: reagent + id: chem.Gin + name: gin + desc: A crystal clear glass of Griffeater gin. + physicalDesc: strong-smelling + color: "#664300" + spritePath: ginvodkaglass.rsi + +- type: reagent + id: chem.Rum + name: rum + desc: Popular with the sailors. Not very popular with anyone else. + physicalDesc: strong-smelling + color: "#664300" + spritePath: rumglass.rsi - type: reagent id: chem.Moonshine diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/catwalk.yml b/Resources/Prototypes/Recipes/Construction/Graphs/catwalk.yml index a218cf8e4c..a43bb1d729 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/catwalk.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/catwalk.yml @@ -6,7 +6,8 @@ edges: - to: Catwalk completed: - - !type:SnapToGrid { } + - !type:SnapToGrid + southRotation: true steps: - material: MetalRod amount: 2 diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/girder.yml b/Resources/Prototypes/Recipes/Construction/Graphs/girder.yml index b1fff3816a..ff840def92 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/girder.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/girder.yml @@ -6,7 +6,8 @@ edges: - to: girder completed: - - !type:SnapToGrid { } + - !type:SnapToGrid + southRotation: true steps: - material: Metal amount: 2 @@ -35,7 +36,8 @@ - to: wall completed: - - !type:SnapToGrid {} + - !type:SnapToGrid + southRotation: true conditions: - !type:EntityAnchored {} steps: @@ -44,7 +46,8 @@ - to: reinforcedGirder completed: - - !type:SnapToGrid { } + - !type:SnapToGrid + southRotation: true conditions: - !type:EntityAnchored {} steps: @@ -72,7 +75,8 @@ edges: - to: reinforcedWall completed: - - !type:SnapToGrid { } + - !type:SnapToGrid + southRotation: true conditions: - !type:EntityAnchored { } steps: @@ -82,7 +86,8 @@ - to: girder completed: - - !type:SnapToGrid { } + - !type:SnapToGrid + southRotation: true conditions: - !type:EntityAnchored { } steps: diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/tables.yml b/Resources/Prototypes/Recipes/Construction/Graphs/tables.yml index afe3f1753c..f94b12ace6 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/tables.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/tables.yml @@ -6,7 +6,8 @@ edges: - to: TableFrame completed: - - !type:SnapToGrid { } + - !type:SnapToGrid + southRotation: true steps: - material: MetalRod amount: 2 diff --git a/Resources/Prototypes/Recipes/Reactions/chemicals.yml b/Resources/Prototypes/Recipes/Reactions/chemicals.yml index 05045b484f..f6f16984ad 100644 --- a/Resources/Prototypes/Recipes/Reactions/chemicals.yml +++ b/Resources/Prototypes/Recipes/Reactions/chemicals.yml @@ -40,6 +40,20 @@ products: chem.PolytrinicAcid: 3 +- type: reaction + id: react.FluorosulfuricAcid + reactants: + chem.Fluorine: + amount: 1 + chem.Hydrogen: + amount: 1 + chem.Potassium: + amount: 1 + chem.SulfuricAcid: + amount: 1 + products: + chem.FluorosulfuricAcid: 4 + - type: reaction id: react.PotassiumExplosion reactants: @@ -57,6 +71,94 @@ scaled: true #Scaled proportionally to amount of potassium and water maxScale: 30 #Explosion strength stops scaling at 30 potassium + 30 water +- type: reaction + id: react.Smoke + reactants: + chem.Phosphorus: + amount: 1 + chem.Potassium: + amount: 1 + chem.Sugar: + amount: 1 + effects: + - !type:SmokeAreaReactionEffect + rangeConstant: 0 + rangeMultiplier: 1.1 #Range formula: rangeConstant + rangeMultiplier*sqrt(ReactionUnits) + maxRange: 10 + duration: 10 + spreadDelay: 0.5 + removeDelay: 0.5 + diluteReagents: false + prototypeId: Smoke + sound: /Audio/Effects/smoke.ogg + +- type: reaction + id: react.Foam + reactants: + chem.Fluorosurfactant: + amount: 1 + chem.Water: + amount: 1 + effects: + - !type:FoamAreaReactionEffect + rangeConstant: 0 + rangeMultiplier: 1.1 #Range formula: rangeConstant + rangeMultiplier*sqrt(ReactionUnits) + maxRange: 10 + duration: 10 + spreadDelay: 1 + removeDelay: 0 + diluteReagents: true + reagentDilutionStart: 4 #At what range should the reagents start diluting + reagentDilutionFactor: 1 + reagentMaxConcentrationFactor: 2 #The reagents will get multiplied by this number if the range turns out to be 0 + prototypeId: Foam + +- type: reaction + id: react.IronMetalFoam + reactants: + chem.Iron: + amount: 3 + chem.FoamingAgent: + amount: 1 + chem.FluorosulfuricAcid: + amount: 1 + effects: + - !type:FoamAreaReactionEffect + rangeConstant: 0 + rangeMultiplier: 1.1 + maxRange: 10 + duration: 10 + spreadDelay: 1 + removeDelay: 0 + diluteReagents: true + reagentDilutionStart: 4 + reagentDilutionFactor: 1 + reagentMaxConcentrationFactor: 2 + prototypeId: IronMetalFoam + +- type: reaction + id: react.AluminiumMetalFoam + reactants: + chem.Aluminium: + amount: 3 + chem.FoamingAgent: + amount: 1 + chem.FluorosulfuricAcid: + amount: 1 + effects: + - !type:FoamAreaReactionEffect + rangeConstant: 0 + rangeMultiplier: 1.1 + maxRange: 10 + duration: 10 + spreadDelay: 1 + removeDelay: 0 + diluteReagents: true + reagentDilutionStart: 4 + reagentDilutionFactor: 1 + reagentMaxConcentrationFactor: 2 + prototypeId: AluminiumMetalFoam + - type: reaction id: react.TableSalt reactants: @@ -100,3 +202,15 @@ amount: 1 products: chem.Water: 2 + +- type: reaction + id: react.Fluorosurfactant + reactants: + chem.Carbon: + amount: 2 + chem.Fluorine: + amount: 2 + chem.SulfuricAcid: + amount: 1 + products: + chem.Fluorosurfactant: 5 diff --git a/Resources/Prototypes/Recipes/Reactions/drinks.yml b/Resources/Prototypes/Recipes/Reactions/drinks.yml index efff2ca418..eed03ad522 100644 --- a/Resources/Prototypes/Recipes/Reactions/drinks.yml +++ b/Resources/Prototypes/Recipes/Reactions/drinks.yml @@ -65,7 +65,7 @@ reactants: chem.B52: amount: 10 - chem.U: + chem.Uranium: amount: 1 products: chem.AtomicBomb: 11 @@ -134,4 +134,4 @@ chem.Moonshine: amount: 1 products: - chem.LeanShine: 2 \ No newline at end of file + chem.LeanShine: 2 diff --git a/Resources/Prototypes/Recipes/Reactions/medicine.yml b/Resources/Prototypes/Recipes/Reactions/medicine.yml index 7675eae989..6d50158ee7 100644 --- a/Resources/Prototypes/Recipes/Reactions/medicine.yml +++ b/Resources/Prototypes/Recipes/Reactions/medicine.yml @@ -13,9 +13,9 @@ - type: reaction id: react.Alkysine reactants: - chem.Cl: + chem.Chlorine: amount: 1 - chem.N: + chem.Nitrogen: amount: 1 chem.Dylovene: amount: 1 @@ -25,11 +25,11 @@ - type: reaction id: react.Dylovene reactants: - chem.Si: + chem.Silicon: amount: 1 - chem.N: + chem.Nitrogen: amount: 1 - chem.K: + chem.Potassium: amount: 1 products: chem.Dylovene: 3 @@ -39,7 +39,7 @@ reactants: chem.Hyronalin: amount: 1 - chem.H: + chem.Hydrogen: amount: 1 products: chem.Arithrazine: 2 @@ -49,7 +49,7 @@ reactants: chem.Inaprovaline: amount: 1 - chem.C: + chem.Carbon: amount: 1 products: chem.Bicaridine: 2 @@ -59,9 +59,9 @@ reactants: chem.Dexalin: amount: 1 - chem.H2O: + chem.Water: amount: 1 - chem.O: + chem.Oxygen: amount: 1 products: chem.Cryoxadone: 3 @@ -71,9 +71,9 @@ reactants: chem.Cryoxadone: amount: 1 - chem.Na: + chem.Sodium: amount: 1 - chem.Plasma: + chem.Phoron: amount: 5 catalyst: true products: @@ -84,7 +84,7 @@ reactants: chem.MindbreakerToxin: amount: 5 - chem.C: + chem.Carbon: amount: 5 products: chem.Citalopram: 10 @@ -94,9 +94,9 @@ reactants: chem.Kelotane: amount: 1 - chem.O: + chem.Oxygen: amount: 1 - chem.P: + chem.Phosphorus: amount: 1 products: chem.Dermaline: 3 @@ -104,9 +104,9 @@ - type: reaction id: react.Dexalin reactants: - chem.O: + chem.Oxygen: amount: 2 - chem.Plasma: + chem.Phoron: amount: 5 catalyst: true products: @@ -117,9 +117,9 @@ reactants: chem.Dexalin: amount: 1 - chem.C: + chem.Carbon: amount: 1 - chem.Fe: + chem.Iron: amount: 1 products: chem.DexalinPlus: 3 @@ -127,11 +127,11 @@ - type: reaction id: react.Ethylredoxrazine reactants: - chem.O: + chem.Oxygen: amount: 1 chem.Dylovene: amount: 1 - chem.C: + chem.Carbon: amount: 1 products: chem.Ethylredoxrazine: 3 @@ -141,9 +141,9 @@ reactants: chem.Glucose: amount: 1 - chem.P: + chem.Phosphorus: amount: 1 - chem.S: + chem.Sulfur: amount: 1 products: chem.Hyperzine: 3 @@ -151,7 +151,7 @@ - type: reaction id: react.Hyronalin reactants: - chem.Ra: + chem.Radium: amount: 1 chem.Dylovene: amount: 1 @@ -161,9 +161,9 @@ - type: reaction id: react.Imidazoline reactants: - chem.H: + chem.Hydrogen: amount: 1 - chem.C: + chem.Carbon: amount: 1 chem.Dylovene: amount: 1 @@ -175,9 +175,9 @@ reactants: chem.Dylovene: amount: 1 - chem.C: + chem.Carbon: amount: 1 - chem.H2O: + chem.Water: amount: 1 products: chem.Inacusiate: 3 @@ -185,9 +185,9 @@ - type: reaction id: react.Inaprovaline reactants: - chem.O: + chem.Oxygen: amount: 1 - chem.C: + chem.Carbon: amount: 1 chem.Glucose: amount: 1 @@ -197,9 +197,9 @@ - type: reaction id: react.Kelotane reactants: - chem.Si: + chem.Silicon: amount: 1 - chem.C: + chem.Carbon: amount: 1 products: chem.Kelotane: 2 @@ -207,11 +207,11 @@ - type: reaction id: react.Leporazine reactants: - chem.Si: + chem.Silicon: amount: 1 - chem.Cu: + chem.Copper: amount: 1 - chem.Plasma: + chem.Phoron: amount: 5 catalyst: true products: @@ -220,13 +220,13 @@ - type: reaction id: react.Methylin reactants: - chem.H: + chem.Hydrogen: amount: 1 - chem.Cl: + chem.Chlorine: amount: 1 chem.Ethanol: amount: 1 - chem.F: + chem.Fluorine: amount: 5 catalyst: true products: @@ -239,7 +239,7 @@ amount: 1 chem.Tramadol: amount: 1 - chem.Plasma: + chem.Phoron: amount: 1 products: chem.Oxycodone: 3 @@ -261,7 +261,7 @@ reactants: chem.MindbreakerToxin: amount: 5 - chem.O: + chem.Oxygen: amount: 5 chem.Inaprovaline: amount: 5 @@ -273,7 +273,7 @@ reactants: chem.Arithrazine: amount: 1 - chem.C: + chem.Carbon: amount: 1 products: chem.Ryetalyn: 2 @@ -291,11 +291,11 @@ - type: reaction id: react.Synaptizine reactants: - chem.Li: + chem.Lithium: amount: 1 chem.Glucose: amount: 1 - chem.H2O: + chem.Water: amount: 1 products: chem.Synaptizine: 3 @@ -307,7 +307,7 @@ amount: 1 chem.Ethanol: amount: 1 - chem.O: + chem.Oxygen: amount: 1 products: chem.Tramadol: 3 @@ -325,11 +325,11 @@ - type: reaction id: react.Vaccine reactants: - chem.Al: + chem.Aluminium: amount: 1 chem.Glucose: amount: 1 - chem.H2O: + chem.Water: amount: 1 products: chem.Vaccine: 3 @@ -349,12 +349,12 @@ reactants: chem.Ethanol: amount: 1 - chem.Cl: + chem.Chlorine: amount: 3 - chem.H2O: + chem.Water: amount: 1 products: - chem.ChloralHydrate: 5 + chem.ChloralHydrate: 1 - type: reaction id: react.Creatine #Add nutriment as ingredient (amount = 1) once that's a thing @@ -371,9 +371,9 @@ - type: reaction id: react.Cryptobiolin reactants: - chem.K: + chem.Potassium: amount: 1 - chem.O: + chem.Oxygen: amount: 1 chem.Glucose: amount: 1 @@ -393,9 +393,9 @@ - type: reaction id: react.Impedrezene reactants: - chem.Hg: + chem.Mercury: amount: 1 - chem.O: + chem.Oxygen: amount: 1 chem.Glucose: amount: 1 @@ -407,7 +407,7 @@ reactants: chem.Ammonia: amount: 1 - chem.Plasma: + chem.Phoron: amount: 1 products: chem.Lexorin: 2 @@ -419,7 +419,7 @@ amount: 1 chem.Ethanol: amount: 1 - chem.Ra: + chem.Radium: amount: 1 products: chem.Lipozine: 3 @@ -427,9 +427,9 @@ - type: reaction id: react.MindbreakerToxin reactants: - chem.Si: + chem.Silicon: amount: 1 - chem.H: + chem.Hydrogen: amount: 1 chem.Dylovene: amount: 1 @@ -453,7 +453,7 @@ amount: 1 chem.Dylovene: amount: 1 - chem.Cl: + chem.Chlorine: amount: 1 products: chem.Sterilizine: 3 @@ -461,11 +461,11 @@ - type: reaction id: react.SpaceDrugs reactants: - chem.Hg: + chem.Mercury: amount: 1 chem.Glucose: amount: 1 - chem.Li: + chem.Lithium: amount: 1 products: chem.SpaceDrugs: 3 diff --git a/Resources/Prototypes/SoundCollections/storage_rustle.yml b/Resources/Prototypes/SoundCollections/storage_rustle.yml index d7f6c09586..3fbfc80535 100644 --- a/Resources/Prototypes/SoundCollections/storage_rustle.yml +++ b/Resources/Prototypes/SoundCollections/storage_rustle.yml @@ -6,3 +6,10 @@ - /Audio/Effects/rustle3.ogg - /Audio/Effects/rustle4.ogg - /Audio/Effects/rustle5.ogg + +- type: soundCollection + id: trashBagRustle + files: + - /Audio/Effects/trashbag1.ogg + - /Audio/Effects/trashbag2.ogg + - /Audio/Effects/trashbag3.ogg \ No newline at end of file diff --git a/Resources/Textures/Constructible/Atmos/gasgenerator.rsi/gasGenerator.png b/Resources/Textures/Constructible/Atmos/gasgenerator.rsi/gasGenerator.png new file mode 100644 index 0000000000..038cde0c9b Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/gasgenerator.rsi/gasGenerator.png differ diff --git a/Resources/Textures/Constructible/Atmos/gasgenerator.rsi/meta.json b/Resources/Textures/Constructible/Atmos/gasgenerator.rsi/meta.json new file mode 100644 index 0000000000..d202af0146 --- /dev/null +++ b/Resources/Textures/Constructible/Atmos/gasgenerator.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version":1, + "size":{ + "x":32, + "y":32 + }, + "license":"CC-BY-SA-3.0", + "copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da", + "states":[ + { + "name":"gasGenerator" + } + ] +} diff --git a/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/meta.json b/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/meta.json index 7c0496334f..8fd6d66a8e 100644 --- a/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/meta.json +++ b/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/meta.json @@ -1 +1 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA 3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 1dbcf389b0ec6b2c51b002df5fef8dd1519f8068", "states": [{"name": "claypot", "delays": [[1.0]]}, {"name": "claypot-item", "delays": [[1.0]]}, {"name": "claypot-large", "delays": [[1.0]]}, {"name": "cyan", "delays": [[1.0]]}, {"name": "cyan black stripe", "delays": [[1.0]]}, {"name": "cyan blue stripe", "delays": [[1.0]]}, {"name": "cyan lime stripe", "delays": [[1.0]]}, {"name": "cyan purple stripe", "delays": [[1.0]]}, {"name": "cyan red stripe", "delays": [[1.0]]}, {"name": "cyan white stripe", "delays": [[1.0]]}, {"name": "cyan yellow stripe", "delays": [[1.0]]}, {"name": "deathspray", "delays": [[1.0]]}, {"name": "disk", "delays": [[0.1, 0.1, 0.1]]}, {"name": "green black stripe", "delays": [[1.0]]}, {"name": "green blue stripe", "delays": [[1.0]]}, {"name": "green lime stripe", "delays": [[1.0]]}, {"name": "green purple stripe", "delays": [[1.0]]}, {"name": "green red stripe", "delays": [[1.0]]}, {"name": "green white stripe", "delays": [[1.0]]}, {"name": "green yellow stripe", "delays": [[1.0]]}, {"name": "hydrocover", "delays": [[1.0]]}, {"name": "hydrotray", "delays": [[1.0]]}, {"name": "hydrotray2", "delays": [[1.0]]}, {"name": "hydrotray3", "delays": [[1.0]]}, {"name": "moldcreep0", "delays": [[1.0]]}, {"name": "moldcreep1", "delays": [[1.0]]}, {"name": "moldcreep2", "delays": [[1.0]]}, {"name": "nolabelspray", "delays": [[1.0]]}, {"name": "over_alert3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "over_harvest3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "over_lowhealth3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "over_lownutri", "delays": [[1.0]]}, {"name": "over_lownutri3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "over_lowwater3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "pestspray", "delays": [[1.0]]}, {"name": "plantbag", "delays": [[1.0]]}, {"name": "plantbgone", "delays": [[1.0]]}, {"name": "portaseeder", "delays": [[1.0]]}, {"name": "seedbag", "delays": [[1.0]]}, {"name": "sextractor", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "soil", "delays": [[1.0]]}, {"name": "spaceworms", "delays": [[0.4, 0.4, 0.4, 0.4]]}, {"name": "spawner", "delays": [[1.0]]}, {"name": "sprayparts", "delays": [[1.0]]}, {"name": "traitcopier", "delays": [[1.0]]}, {"name": "traitgun", "delays": [[1.0]]}, {"name": "traitscanner", "delays": [[1.0]]}, {"name": "vine_flowers", "delays": [[1.0]]}, {"name": "vine_fruit", "delays": [[1.0]]}, {"name": "weedspray", "delays": [[1.0]]}, {"name": "scythe", "delays": [[1.0]]}, {"name": "hoe", "delays": [[1.0]]}, {"name": "hatchet", "delays": [[1.0]]}]} +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA 3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 1dbcf389b0ec6b2c51b002df5fef8dd1519f8068", "states": [{"name": "claypot", "delays": [[1.0]]}, {"name": "claypot-item", "delays": [[1.0]]}, {"name": "claypot-large", "delays": [[1.0]]}, {"name": "cyan", "delays": [[1.0]]}, {"name": "cyan black stripe", "delays": [[1.0]]}, {"name": "cyan blue stripe", "delays": [[1.0]]}, {"name": "cyan lime stripe", "delays": [[1.0]]}, {"name": "cyan purple stripe", "delays": [[1.0]]}, {"name": "cyan red stripe", "delays": [[1.0]]}, {"name": "cyan white stripe", "delays": [[1.0]]}, {"name": "cyan yellow stripe", "delays": [[1.0]]}, {"name": "deathspray", "delays": [[1.0]]}, {"name": "disk", "delays": [[0.1, 0.1, 0.1]]}, {"name": "green black stripe", "delays": [[1.0]]}, {"name": "green blue stripe", "delays": [[1.0]]}, {"name": "green lime stripe", "delays": [[1.0]]}, {"name": "green purple stripe", "delays": [[1.0]]}, {"name": "green red stripe", "delays": [[1.0]]}, {"name": "green white stripe", "delays": [[1.0]]}, {"name": "green yellow stripe", "delays": [[1.0]]}, {"name": "hydrocover", "delays": [[1.0]]}, {"name": "hydrotray", "delays": [[1.0]]}, {"name": "hydrotray2", "delays": [[1.0]]}, {"name": "hydrotray3", "delays": [[1.0]]}, {"name": "moldcreep0", "delays": [[1.0]]}, {"name": "moldcreep1", "delays": [[1.0]]}, {"name": "moldcreep2", "delays": [[1.0]]}, {"name": "nolabelspray", "delays": [[1.0]]}, {"name": "over_alert3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "over_harvest3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "over_lowhealth3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "over_lownutri", "delays": [[1.0]]}, {"name": "over_lownutri3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "over_lowwater3", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "pestspray", "delays": [[1.0]]}, {"name": "plantbag", "delays": [[1.0]]}, {"name": "plantbgone", "delays": [[1.0]]}, {"name": "portaseeder", "delays": [[1.0]]}, {"name": "seedbag", "delays": [[1.0]]}, {"name": "sextractor", "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "soil", "delays": [[1.0]]}, {"name": "spaceworms", "delays": [[0.4, 0.4, 0.4, 0.4]]}, {"name": "spawner", "delays": [[1.0]]}, {"name": "sprayparts", "delays": [[1.0]]}, {"name": "traitcopier", "delays": [[1.0]]}, {"name": "traitgun", "delays": [[1.0]]}, {"name": "traitscanner", "delays": [[1.0]]}, {"name": "vine_flowers", "delays": [[1.0]]}, {"name": "vine_fruit", "delays": [[1.0]]}, {"name": "weedspray", "delays": [[1.0]]}, {"name": "scythe", "delays": [[1.0]]}, {"name": "hoe", "delays": [[1.0]]}, {"name": "hatchet", "delays": [[1.0]]}, {"name": "shovel", "delays": [[1.0]]}, {"name": "spade", "delays": [[1.0]]}]} diff --git a/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/shovel.png b/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/shovel.png new file mode 100644 index 0000000000..c7eed38171 Binary files /dev/null and b/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/shovel.png differ diff --git a/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/spade.png b/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/spade.png new file mode 100644 index 0000000000..d76bc3de57 Binary files /dev/null and b/Resources/Textures/Constructible/Hydroponics/hydro_tools.rsi/spade.png differ diff --git a/Resources/Textures/Effects/chemsmoke.rsi/chemsmoke.png b/Resources/Textures/Effects/chemsmoke.rsi/chemsmoke.png new file mode 100644 index 0000000000..e85d446334 Binary files /dev/null and b/Resources/Textures/Effects/chemsmoke.rsi/chemsmoke.png differ diff --git a/Resources/Textures/Effects/chemsmoke.rsi/meta.json b/Resources/Textures/Effects/chemsmoke.rsi/meta.json new file mode 100644 index 0000000000..62514d1c2a --- /dev/null +++ b/Resources/Textures/Effects/chemsmoke.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 96, "y": 96}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/81b3a082ccdfb425f36bbed6e5bc1f0faed346ec/icons/effects/chemsmoke.dmi", "states": [{"name": "chemsmoke", "directions": 4, "delays": [[0.2, 0.2, 0.2], [0.2, 0.2, 0.2], [0.2, 0.2, 0.2], [0.2, 0.2, 0.2]]}]} \ No newline at end of file diff --git a/Resources/Textures/Effects/foam.rsi/foam-dissolve.png b/Resources/Textures/Effects/foam.rsi/foam-dissolve.png new file mode 100644 index 0000000000..a99f7e3b8f Binary files /dev/null and b/Resources/Textures/Effects/foam.rsi/foam-dissolve.png differ diff --git a/Resources/Textures/Effects/foam.rsi/foam.png b/Resources/Textures/Effects/foam.rsi/foam.png new file mode 100644 index 0000000000..5f34c726ae Binary files /dev/null and b/Resources/Textures/Effects/foam.rsi/foam.png differ diff --git a/Resources/Textures/Effects/foam.rsi/ironfoam.png b/Resources/Textures/Effects/foam.rsi/ironfoam.png new file mode 100644 index 0000000000..bf39c4ee80 Binary files /dev/null and b/Resources/Textures/Effects/foam.rsi/ironfoam.png differ diff --git a/Resources/Textures/Effects/foam.rsi/meta.json b/Resources/Textures/Effects/foam.rsi/meta.json new file mode 100644 index 0000000000..33d13b267b --- /dev/null +++ b/Resources/Textures/Effects/foam.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/81b3a082ccdfb425f36bbed6e5bc1f0faed346ec/icons/effects/effects.dmi", "states": [{"name": "foam", "directions": 1}, {"name": "foam-dissolve", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "ironfoam", "directions": 1}, {"name": "metalfoam", "directions": 1}, {"name": "mfoam", "directions": 1}, {"name": "mfoam-dissolve", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}]} \ No newline at end of file diff --git a/Resources/Textures/Effects/foam.rsi/metalfoam.png b/Resources/Textures/Effects/foam.rsi/metalfoam.png new file mode 100644 index 0000000000..cb4752a1bc Binary files /dev/null and b/Resources/Textures/Effects/foam.rsi/metalfoam.png differ diff --git a/Resources/Textures/Effects/foam.rsi/mfoam-dissolve.png b/Resources/Textures/Effects/foam.rsi/mfoam-dissolve.png new file mode 100644 index 0000000000..cd6d4a4cc1 Binary files /dev/null and b/Resources/Textures/Effects/foam.rsi/mfoam-dissolve.png differ diff --git a/Resources/Textures/Effects/foam.rsi/mfoam.png b/Resources/Textures/Effects/foam.rsi/mfoam.png new file mode 100644 index 0000000000..13ad9710e3 Binary files /dev/null and b/Resources/Textures/Effects/foam.rsi/mfoam.png differ diff --git a/Resources/Textures/Interface/Alerts/Human/human0.png b/Resources/Textures/Interface/Alerts/Human/human0.png deleted file mode 100644 index ca94b41e6e..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/human0.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/human1.png b/Resources/Textures/Interface/Alerts/Human/human1.png deleted file mode 100644 index 68b189bc6a..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/human1.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/human2.png b/Resources/Textures/Interface/Alerts/Human/human2.png deleted file mode 100644 index ad2acb4ad0..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/human2.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/human3.png b/Resources/Textures/Interface/Alerts/Human/human3.png deleted file mode 100644 index 0888dd79a7..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/human3.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/human4.png b/Resources/Textures/Interface/Alerts/Human/human4.png deleted file mode 100644 index 8eed659e97..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/human4.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/human5.png b/Resources/Textures/Interface/Alerts/Human/human5.png deleted file mode 100644 index 8b4e8a4b9e..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/human5.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/human6.png b/Resources/Textures/Interface/Alerts/Human/human6.png deleted file mode 100644 index 05f0233a73..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/human6.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/human7.png b/Resources/Textures/Interface/Alerts/Human/human7.png deleted file mode 100644 index 3eda7aaf1d..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/human7.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/humancrit-0.png b/Resources/Textures/Interface/Alerts/Human/humancrit-0.png deleted file mode 100644 index 252d22c750..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/humancrit-0.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/humancrit-1.png b/Resources/Textures/Interface/Alerts/Human/humancrit-1.png deleted file mode 100644 index c3102a638c..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/humancrit-1.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Human/humandead.png b/Resources/Textures/Interface/Alerts/Human/humandead.png deleted file mode 100644 index 75e6fb07af..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Human/humandead.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Pressure/highpressure1.png b/Resources/Textures/Interface/Alerts/Pressure/highpressure1.png deleted file mode 100644 index daebd742be..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Pressure/highpressure1.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Pressure/highpressure2.png b/Resources/Textures/Interface/Alerts/Pressure/highpressure2.png deleted file mode 100644 index 85f74289aa..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Pressure/highpressure2.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Pressure/lowpressure1.png b/Resources/Textures/Interface/Alerts/Pressure/lowpressure1.png deleted file mode 100644 index 27153cc542..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Pressure/lowpressure1.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Pressure/lowpressure2.png b/Resources/Textures/Interface/Alerts/Pressure/lowpressure2.png deleted file mode 100644 index d94b77ea1a..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Pressure/lowpressure2.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Pressure/meta.json b/Resources/Textures/Interface/Alerts/Pressure/meta.json deleted file mode 100644 index 6c4b44e058..0000000000 --- a/Resources/Textures/Interface/Alerts/Pressure/meta.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA 3.0", - "copyright": "Taken from https://github.com/tgstation/tgstation at 04e43d8c1d5097fdb697addd4395fb849dd341bd", - "states": [ - { - "name": "highpressure1", - - }, - { - "name": "highpressure2", - - }, - { - "name": "lowpressure1", - - }, - { - "name": "lowpressure2", - - } - ] -} \ No newline at end of file diff --git a/Resources/Textures/Interface/Alerts/Temperature/cold1.png b/Resources/Textures/Interface/Alerts/Temperature/cold1.png deleted file mode 100644 index a7408f8e7f..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Temperature/cold1.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Temperature/cold2.png b/Resources/Textures/Interface/Alerts/Temperature/cold2.png deleted file mode 100644 index e8599a3e91..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Temperature/cold2.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Temperature/cold3.png b/Resources/Textures/Interface/Alerts/Temperature/cold3.png deleted file mode 100644 index 4c6f07cf5a..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Temperature/cold3.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Temperature/hot1.png b/Resources/Textures/Interface/Alerts/Temperature/hot1.png deleted file mode 100644 index 2d3896f7b0..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Temperature/hot1.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Temperature/hot2.png b/Resources/Textures/Interface/Alerts/Temperature/hot2.png deleted file mode 100644 index 7408c204c8..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Temperature/hot2.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/Temperature/hot3.png b/Resources/Textures/Interface/Alerts/Temperature/hot3.png deleted file mode 100644 index d74178208f..0000000000 Binary files a/Resources/Textures/Interface/Alerts/Temperature/hot3.png and /dev/null differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health0.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health0.png new file mode 100644 index 0000000000..9330c49282 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health0.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health1.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health1.png new file mode 100644 index 0000000000..c6232e16c0 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health1.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health2.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health2.png new file mode 100644 index 0000000000..51cf805d9a Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health2.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health3.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health3.png new file mode 100644 index 0000000000..3165e8bce4 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health3.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health4.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health4.png new file mode 100644 index 0000000000..ca08aade24 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health4.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health5.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health5.png new file mode 100644 index 0000000000..fc96021bfe Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health5.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health6.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health6.png new file mode 100644 index 0000000000..b677960687 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health6.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health7.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health7.png new file mode 100644 index 0000000000..9fb45eca0b Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health7.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/health_numb.png b/Resources/Textures/Interface/Alerts/human_health.rsi/health_numb.png new file mode 100644 index 0000000000..9dc3a511d7 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/human_health.rsi/health_numb.png differ diff --git a/Resources/Textures/Interface/Alerts/human_health.rsi/meta.json b/Resources/Textures/Interface/Alerts/human_health.rsi/meta.json new file mode 100644 index 0000000000..e34c0728f1 --- /dev/null +++ b/Resources/Textures/Interface/Alerts/human_health.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA 3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 1d52615ca647d96583f5bc7a1017f3910194bed3", "states": [{"name": "health0", "directions": 1, "delays": [[1.0]]}, {"name": "health1", "directions": 1, "delays": [[1.0]]}, {"name": "health2", "directions": 1, "delays": [[1.0]]}, {"name": "health3", "directions": 1, "delays": [[1.0]]}, {"name": "health4", "directions": 1, "delays": [[1.0]]}, {"name": "health5", "directions": 1, "delays": [[0.5, 0.5]]}, {"name": "health6", "directions": 1, "delays": [[0.5, 0.5]]}, {"name": "health7", "directions": 1, "delays": [[1.0]]}, {"name": "health_numb", "directions": 1, "delays": [[1.0]]}]} \ No newline at end of file diff --git a/Resources/Textures/Interface/Alerts/pressure.rsi/highpressure1.png b/Resources/Textures/Interface/Alerts/pressure.rsi/highpressure1.png new file mode 100644 index 0000000000..92c8aa0eb2 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/pressure.rsi/highpressure1.png differ diff --git a/Resources/Textures/Interface/Alerts/pressure.rsi/highpressure2.png b/Resources/Textures/Interface/Alerts/pressure.rsi/highpressure2.png new file mode 100644 index 0000000000..34cc305c84 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/pressure.rsi/highpressure2.png differ diff --git a/Resources/Textures/Interface/Alerts/pressure.rsi/lowpressure1.png b/Resources/Textures/Interface/Alerts/pressure.rsi/lowpressure1.png new file mode 100644 index 0000000000..6cf5f379b9 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/pressure.rsi/lowpressure1.png differ diff --git a/Resources/Textures/Interface/Alerts/pressure.rsi/lowpressure2.png b/Resources/Textures/Interface/Alerts/pressure.rsi/lowpressure2.png new file mode 100644 index 0000000000..3c266180be Binary files /dev/null and b/Resources/Textures/Interface/Alerts/pressure.rsi/lowpressure2.png differ diff --git a/Resources/Textures/Interface/Alerts/pressure.rsi/meta.json b/Resources/Textures/Interface/Alerts/pressure.rsi/meta.json new file mode 100644 index 0000000000..1690b7a19b --- /dev/null +++ b/Resources/Textures/Interface/Alerts/pressure.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA 3.0", "copyright": "Taken from https://github.com/tgstation/tgstation at 04e43d8c1d5097fdb697addd4395fb849dd341bd", "states": [{"name": "highpressure1", "directions": 1, "delays": [[1.0]]}, {"name": "highpressure2", "directions": 1, "delays": [[0.5, 0.5]]}, {"name": "lowpressure1", "directions": 1, "delays": [[1.0]]}, {"name": "lowpressure2", "directions": 1, "delays": [[0.5, 0.5]]}]} \ No newline at end of file diff --git a/Resources/Textures/Interface/Alerts/temperature.rsi/cold1.png b/Resources/Textures/Interface/Alerts/temperature.rsi/cold1.png new file mode 100644 index 0000000000..b1c09293ba Binary files /dev/null and b/Resources/Textures/Interface/Alerts/temperature.rsi/cold1.png differ diff --git a/Resources/Textures/Interface/Alerts/temperature.rsi/cold2.png b/Resources/Textures/Interface/Alerts/temperature.rsi/cold2.png new file mode 100644 index 0000000000..3ba601625a Binary files /dev/null and b/Resources/Textures/Interface/Alerts/temperature.rsi/cold2.png differ diff --git a/Resources/Textures/Interface/Alerts/temperature.rsi/cold3.png b/Resources/Textures/Interface/Alerts/temperature.rsi/cold3.png new file mode 100644 index 0000000000..b20875afff Binary files /dev/null and b/Resources/Textures/Interface/Alerts/temperature.rsi/cold3.png differ diff --git a/Resources/Textures/Interface/Alerts/temperature.rsi/hot1.png b/Resources/Textures/Interface/Alerts/temperature.rsi/hot1.png new file mode 100644 index 0000000000..ee13775054 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/temperature.rsi/hot1.png differ diff --git a/Resources/Textures/Interface/Alerts/temperature.rsi/hot2.png b/Resources/Textures/Interface/Alerts/temperature.rsi/hot2.png new file mode 100644 index 0000000000..c23d5859b4 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/temperature.rsi/hot2.png differ diff --git a/Resources/Textures/Interface/Alerts/temperature.rsi/hot3.png b/Resources/Textures/Interface/Alerts/temperature.rsi/hot3.png new file mode 100644 index 0000000000..df70e373e8 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/temperature.rsi/hot3.png differ diff --git a/Resources/Textures/Interface/Alerts/temperature.rsi/meta.json b/Resources/Textures/Interface/Alerts/temperature.rsi/meta.json new file mode 100644 index 0000000000..e1cc97be28 --- /dev/null +++ b/Resources/Textures/Interface/Alerts/temperature.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA 3.0", "copyright": "Taken from https://github.com/tgstation/tgstation at 1c7401722f397d8ac8afdd10e550c5962e0f38d4", "states": [{"name": "cold1", "directions": 1, "delays": [[1.0]]}, {"name": "cold2", "directions": 1, "delays": [[1.0]]}, {"name": "cold3", "directions": 1, "delays": [[0.3, 0.3]]}, {"name": "hot1", "directions": 1, "delays": [[1.0]]}, {"name": "hot2", "directions": 1, "delays": [[1.0]]}, {"name": "hot3", "directions": 1, "delays": [[0.3, 0.3]]}]} \ No newline at end of file diff --git a/Resources/Textures/Interface/Nano/gear.svg b/Resources/Textures/Interface/Nano/gear.svg index ccb451d706..a4b4256d6e 100644 --- a/Resources/Textures/Interface/Nano/gear.svg +++ b/Resources/Textures/Interface/Nano/gear.svg @@ -1,3 +1,58 @@ - - + + + + + + image/svg+xml + + + + + + + diff --git a/Resources/Textures/Interface/Nano/gear.svg.192dpi.png b/Resources/Textures/Interface/Nano/gear.svg.192dpi.png new file mode 100644 index 0000000000..90d434da82 Binary files /dev/null and b/Resources/Textures/Interface/Nano/gear.svg.192dpi.png differ diff --git a/Resources/Textures/Interface/Nano/gear.svg.192dpi.png.yml b/Resources/Textures/Interface/Nano/gear.svg.192dpi.png.yml new file mode 100644 index 0000000000..5c43e23305 --- /dev/null +++ b/Resources/Textures/Interface/Nano/gear.svg.192dpi.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Interface/Nano/gear.svg.png b/Resources/Textures/Interface/Nano/gear.svg.png deleted file mode 100644 index 522472042c..0000000000 Binary files a/Resources/Textures/Interface/Nano/gear.svg.png and /dev/null differ diff --git a/Resources/Textures/Interface/Nano/left_arrow.svg b/Resources/Textures/Interface/Nano/left_arrow.svg index f3f1bb49b3..d86fe3fd58 100644 --- a/Resources/Textures/Interface/Nano/left_arrow.svg +++ b/Resources/Textures/Interface/Nano/left_arrow.svg @@ -1,3 +1,66 @@ - - + + + + + + image/svg+xml + + + + + + + + diff --git a/Resources/Textures/Interface/Nano/left_arrow.svg.192dpi.png b/Resources/Textures/Interface/Nano/left_arrow.svg.192dpi.png new file mode 100644 index 0000000000..6539a6cb7d Binary files /dev/null and b/Resources/Textures/Interface/Nano/left_arrow.svg.192dpi.png differ diff --git a/Resources/Textures/Interface/Nano/left_arrow.svg.192dpi.png.yml b/Resources/Textures/Interface/Nano/left_arrow.svg.192dpi.png.yml new file mode 100644 index 0000000000..5c43e23305 --- /dev/null +++ b/Resources/Textures/Interface/Nano/left_arrow.svg.192dpi.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Interface/Nano/left_arrow.svg.png b/Resources/Textures/Interface/Nano/left_arrow.svg.png deleted file mode 100644 index b606395f58..0000000000 Binary files a/Resources/Textures/Interface/Nano/left_arrow.svg.png and /dev/null differ diff --git a/Resources/Textures/Interface/Nano/lock.svg.192dpi.png b/Resources/Textures/Interface/Nano/lock.svg.192dpi.png new file mode 100644 index 0000000000..6e30dbb394 Binary files /dev/null and b/Resources/Textures/Interface/Nano/lock.svg.192dpi.png differ diff --git a/Resources/Textures/Interface/Nano/lock.svg.192dpi.png.yml b/Resources/Textures/Interface/Nano/lock.svg.192dpi.png.yml new file mode 100644 index 0000000000..5c43e23305 --- /dev/null +++ b/Resources/Textures/Interface/Nano/lock.svg.192dpi.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Interface/Nano/lock.svg.png b/Resources/Textures/Interface/Nano/lock.svg.png deleted file mode 100644 index 148cc20f5e..0000000000 Binary files a/Resources/Textures/Interface/Nano/lock.svg.png and /dev/null differ diff --git a/Resources/Textures/Interface/Nano/lock_open.svg.192dpi.png b/Resources/Textures/Interface/Nano/lock_open.svg.192dpi.png new file mode 100644 index 0000000000..729c820aa0 Binary files /dev/null and b/Resources/Textures/Interface/Nano/lock_open.svg.192dpi.png differ diff --git a/Resources/Textures/Interface/Nano/lock_open.svg.192dpi.png.yml b/Resources/Textures/Interface/Nano/lock_open.svg.192dpi.png.yml new file mode 100644 index 0000000000..5c43e23305 --- /dev/null +++ b/Resources/Textures/Interface/Nano/lock_open.svg.192dpi.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Interface/Nano/lock_open.svg.png b/Resources/Textures/Interface/Nano/lock_open.svg.png deleted file mode 100644 index d08584bc17..0000000000 Binary files a/Resources/Textures/Interface/Nano/lock_open.svg.png and /dev/null differ diff --git a/Resources/Textures/Interface/Nano/right_arrow.svg b/Resources/Textures/Interface/Nano/right_arrow.svg index eff5fdff21..b01f7192fb 100644 --- a/Resources/Textures/Interface/Nano/right_arrow.svg +++ b/Resources/Textures/Interface/Nano/right_arrow.svg @@ -1,3 +1,69 @@ - - + + + + + + image/svg+xml + + + + + + + + diff --git a/Resources/Textures/Interface/Nano/right_arrow.svg.192dpi.png b/Resources/Textures/Interface/Nano/right_arrow.svg.192dpi.png new file mode 100644 index 0000000000..00badb5550 Binary files /dev/null and b/Resources/Textures/Interface/Nano/right_arrow.svg.192dpi.png differ diff --git a/Resources/Textures/Interface/Nano/right_arrow.svg.192dpi.png.yml b/Resources/Textures/Interface/Nano/right_arrow.svg.192dpi.png.yml new file mode 100644 index 0000000000..5c43e23305 --- /dev/null +++ b/Resources/Textures/Interface/Nano/right_arrow.svg.192dpi.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Interface/Nano/right_arrow.svg.png b/Resources/Textures/Interface/Nano/right_arrow.svg.png deleted file mode 100644 index 4a75a88e76..0000000000 Binary files a/Resources/Textures/Interface/Nano/right_arrow.svg.png and /dev/null differ diff --git a/Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon-0.png b/Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon-0.png similarity index 100% rename from Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon-0.png rename to Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon-0.png diff --git a/Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon-1.png b/Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon-1.png similarity index 100% rename from Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon-1.png rename to Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon-1.png diff --git a/Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon-2.png b/Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon-2.png similarity index 100% rename from Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon-2.png rename to Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon-2.png diff --git a/Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon-3.png b/Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon-3.png similarity index 100% rename from Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon-3.png rename to Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon-3.png diff --git a/Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon.png b/Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon.png similarity index 100% rename from Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/icon.png rename to Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/icon.png diff --git a/Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/meta.json b/Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/meta.json similarity index 100% rename from Resources/Textures/Objects/Consumable/Trash/trashbag.rsi/meta.json rename to Resources/Textures/Objects/Specific/Janitorial/trashbag.rsi/meta.json diff --git a/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/hypo.png b/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/hypo.png new file mode 100644 index 0000000000..cab29e5b0a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/hypo.png differ diff --git a/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/inhand-left.png new file mode 100644 index 0000000000..e2007ee06a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/inhand-right.png new file mode 100644 index 0000000000..e2007ee06a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/meta.json new file mode 100644 index 0000000000..7f9678130e --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/hypospray.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "Taken from https://github.com/tgstation/tgstation/tree/727eb0a445bccbdc2d472e158e96b87fc0e997a1", "copyright": "CC-BY-SA-3.0", "states": [{"name": "hypo", "directions": 1, "delays": [[1.0]]}, {"name": "inhand-left", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}, {"name": "inhand-right", "directions": 4, "delays": [[1.0], [1.0], [1.0], [1.0]]}]} diff --git a/RobustToolbox b/RobustToolbox index b205a14f69..18fcab6f71 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit b205a14f69d585f04ff2b2eba27a76926b7ba51b +Subproject commit 18fcab6f710947b640b839c458b52193fad2acf7 diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index c8f876874b..6e80925829 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -89,6 +89,7 @@ True True True + True True True True