diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs index ffaa51467d..9f74eb6aec 100644 --- a/Content.Client/IgnoredComponents.cs +++ b/Content.Client/IgnoredComponents.cs @@ -190,7 +190,10 @@ "Hoe", "Seed", "BotanySharp", - "PlantSampleTaker" + "PlantSampleTaker", + "Internals", + "GasTank", + "BreathMask", }; } } diff --git a/Content.Client/UserInterface/Atmos/GasTank/GasTankBoundUserInterface.cs b/Content.Client/UserInterface/Atmos/GasTank/GasTankBoundUserInterface.cs new file mode 100644 index 0000000000..868aad1443 --- /dev/null +++ b/Content.Client/UserInterface/Atmos/GasTank/GasTankBoundUserInterface.cs @@ -0,0 +1,50 @@ +using Content.Shared.GameObjects.Components.Atmos.GasTank; +using JetBrains.Annotations; +using Robust.Client.GameObjects.Components.UserInterface; +using Robust.Shared.GameObjects.Components.UserInterface; + +namespace Content.Client.UserInterface.Atmos.GasTank +{ + [UsedImplicitly] + public class GasTankBoundUserInterface + : BoundUserInterface + { + public GasTankBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : + base(owner, uiKey) + { + } + + private GasTankWindow _window; + + public void SetOutputPressure(in float value) + { + SendMessage(new GasTankSetPressureMessage {Pressure = value}); + } + + public void ToggleInternals() + { + SendMessage(new GasTankToggleInternalsMessage()); + } + + protected override void Open() + { + base.Open(); + _window = new GasTankWindow(this); + _window.OnClose += Close; + _window.OpenCentered(); + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + _window.UpdateState((GasTankBoundUserInterfaceState) state); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _window.Close(); + } + } +} diff --git a/Content.Client/UserInterface/Atmos/GasTank/GasTankWindow.cs b/Content.Client/UserInterface/Atmos/GasTank/GasTankWindow.cs new file mode 100644 index 0000000000..49210c9464 --- /dev/null +++ b/Content.Client/UserInterface/Atmos/GasTank/GasTankWindow.cs @@ -0,0 +1,235 @@ +using Content.Client.UserInterface.Stylesheets; +using Content.Client.Utility; +using Content.Shared.GameObjects.Components.Atmos.GasTank; +using Robust.Client.Graphics.Drawing; +using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; + +namespace Content.Client.UserInterface.Atmos.GasTank +{ + public class GasTankWindow + : BaseWindow + { + private GasTankBoundUserInterface _owner; + private readonly Label _lblName; + private readonly VBoxContainer _topContainer; + private readonly Control _contentContainer; + + + private readonly IResourceCache _resourceCache = default!; + private readonly RichTextLabel _lblPressure; + private readonly FloatSpinBox _spbPressure; + private readonly RichTextLabel _lblInternals; + private readonly Button _btnInternals; + + public GasTankWindow(GasTankBoundUserInterface owner) + { + TextureButton btnClose; + _resourceCache = IoCManager.Resolve(); + _owner = owner; + var rootContainer = new LayoutContainer {Name = "GasTankRoot"}; + AddChild(rootContainer); + + MouseFilter = MouseFilterMode.Stop; + + var panelTex = _resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); + var back = new StyleBoxTexture + { + Texture = panelTex, + Modulate = Color.FromHex("#25252A"), + }; + + back.SetPatchMargin(StyleBox.Margin.All, 10); + + var topPanel = new PanelContainer + { + PanelOverride = back, + MouseFilter = MouseFilterMode.Pass + }; + + var bottomWrap = new LayoutContainer + { + Name = "BottomWrap" + }; + + rootContainer.AddChild(topPanel); + rootContainer.AddChild(bottomWrap); + + LayoutContainer.SetAnchorPreset(topPanel, LayoutContainer.LayoutPreset.Wide); + LayoutContainer.SetMarginBottom(topPanel, -85); + + LayoutContainer.SetAnchorPreset(bottomWrap, LayoutContainer.LayoutPreset.VerticalCenterWide); + LayoutContainer.SetGrowHorizontal(bottomWrap, LayoutContainer.GrowDirection.Both); + + + var topContainerWrap = new VBoxContainer + { + Children = + { + (_topContainer = new VBoxContainer()), + new Control {CustomMinimumSize = (0, 110)} + } + }; + + rootContainer.AddChild(topContainerWrap); + + LayoutContainer.SetAnchorPreset(topContainerWrap, LayoutContainer.LayoutPreset.Wide); + + var font = _resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); + + var topRow = new MarginContainer + { + MarginLeftOverride = 4, + MarginTopOverride = 2, + MarginRightOverride = 12, + MarginBottomOverride = 2, + Children = + { + new HBoxContainer + { + Children = + { + (_lblName = new Label + { + Text = Loc.GetString("Gas Tank"), + FontOverride = font, + FontColorOverride = StyleNano.NanoGold, + SizeFlagsVertical = SizeFlags.ShrinkCenter + }), + new Control + { + CustomMinimumSize = (20, 0), + SizeFlagsHorizontal = SizeFlags.Expand + }, + (btnClose = new TextureButton + { + StyleClasses = {SS14Window.StyleClassWindowCloseButton}, + SizeFlagsVertical = SizeFlags.ShrinkCenter + }) + } + } + } + }; + + var middle = new PanelContainer + { + PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#202025")}, + Children = + { + new MarginContainer + { + MarginLeftOverride = 8, + MarginRightOverride = 8, + MarginTopOverride = 4, + MarginBottomOverride = 4, + Children = + { + (_contentContainer = new VBoxContainer()) + } + } + } + }; + + _topContainer.AddChild(topRow); + _topContainer.AddChild(new PanelContainer + { + CustomMinimumSize = (0, 2), + PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")} + }); + _topContainer.AddChild(middle); + _topContainer.AddChild(new PanelContainer + { + CustomMinimumSize = (0, 2), + PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")} + }); + + + _lblPressure = new RichTextLabel(); + _contentContainer.AddChild(_lblPressure); + + //internals + _lblInternals = new RichTextLabel + {CustomMinimumSize = (200, 0), SizeFlagsVertical = SizeFlags.ShrinkCenter}; + _btnInternals = new Button {Text = Loc.GetString("Toggle")}; + + _contentContainer.AddChild( + new MarginContainer + { + MarginTopOverride = 7, + Children = + { + new HBoxContainer + { + Children = {_lblInternals, _btnInternals} + } + } + }); + + // Separator + _contentContainer.AddChild(new Control + { + CustomMinimumSize = new Vector2(0, 10) + }); + + _contentContainer.AddChild(new Label + { + Text = Loc.GetString("Output Pressure"), + Align = Label.AlignMode.Center + }); + _spbPressure = new FloatSpinBox {IsValid = f => f >= 0 || f <= 3000}; + _contentContainer.AddChild( + new MarginContainer + { + MarginRightOverride = 25, + MarginLeftOverride = 25, + MarginBottomOverride = 7, + Children = + { + _spbPressure + } + } + ); + + // Handlers + _spbPressure.OnValueChanged += args => + { + _owner.SetOutputPressure(args.Value); + }; + + _btnInternals.OnPressed += args => + { + _owner.ToggleInternals(); + }; + + btnClose.OnPressed += _ => Close(); + } + + public void UpdateState(GasTankBoundUserInterfaceState state) + { + _lblPressure.SetMarkup(Loc.GetString("Pressure: {0:0.##} kPa", state.TankPressure)); + _btnInternals.Disabled = !state.CanConnectInternals; + _lblInternals.SetMarkup(Loc.GetString("Internals: [color={0}]{1}[/color]", + state.InternalsConnected ? "green" : "red", + state.InternalsConnected ? "Connected" : "Disconnected")); + if (state.OutputPressure.HasValue) + { + _spbPressure.Value = state.OutputPressure.Value; + } + } + + protected override DragMode GetDragModeFor(Vector2 relativeMousePos) + { + return DragMode.Move; + } + + protected override bool HasPoint(Vector2 point) + { + return false; + } + } +} diff --git a/Content.IntegrationTests/Tests/Body/LungTest.cs b/Content.IntegrationTests/Tests/Body/LungTest.cs index 58becef26d..30c181e189 100644 --- a/Content.IntegrationTests/Tests/Body/LungTest.cs +++ b/Content.IntegrationTests/Tests/Body/LungTest.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Content.Server.Atmos; @@ -46,7 +47,7 @@ namespace Content.IntegrationTests.Tests.Body var originalOxygen = 2; var originalNitrogen = 8; - var breathedPercentage = Atmospherics.BreathPercentage; + var breathedPercentage = Atmospherics.BreathVolume / gas.Volume; gas.AdjustMoles(Gas.Oxygen, originalOxygen); gas.AdjustMoles(Gas.Nitrogen, originalNitrogen); @@ -76,7 +77,7 @@ namespace Content.IntegrationTests.Tests.Body lung.Exhale(1, gas); var lungOxygenAfterExhale = lung.Air.GetMoles(Gas.Oxygen); - var exhaledOxygen = lungOxygenBeforeExhale - lungOxygenAfterExhale; + var exhaledOxygen = Math.Abs(lungOxygenBeforeExhale - lungOxygenAfterExhale); // Not completely empty Assert.Positive(lung.Air.Gases.Sum()); diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs index 425c5da204..e9dca425ed 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Server/Atmos/GasMixture.cs @@ -65,6 +65,38 @@ namespace Content.Server.Atmos } } + /// + /// Heat capacity ratio of gas mixture + /// + [ViewVariables] + public float HeatCapacityRatio + { + get + { + var delimiterSum = 0f; + for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) + { + delimiterSum += _moles[i] / (_atmosphereSystem.GetGas(i).HeatCapacityRatio - 1); + } + return 1 + TotalMoles / delimiterSum; + } + } + + public float MolarMass + { + get + { + var molarMass = 0f; + var totalMoles = TotalMoles; + for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) + { + molarMass += _atmosphereSystem.GetGas(i).MolarMass * (_moles[i] / totalMoles); + } + + return molarMass; + } + } + [ViewVariables] public float HeatCapacityArchived { @@ -136,14 +168,15 @@ namespace Content.Server.Atmos public GasMixture(AtmosphereSystem? atmosphereSystem) { _atmosphereSystem = atmosphereSystem ?? EntitySystem.Get(); + _moles = new float[_atmosphereSystem.Gases.Count()]; + _molesArchived = new float[_moles.Length]; } - public GasMixture(float volume, AtmosphereSystem? atmosphereSystem = null) + public GasMixture(float volume, AtmosphereSystem? atmosphereSystem = null): this(atmosphereSystem) { if (volume < 0) volume = 0; Volume = volume; - _atmosphereSystem = atmosphereSystem ?? EntitySystem.Get(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs index d885790d26..6e5d91e5ec 100644 --- a/Content.Server/Atmos/TileAtmosphere.cs +++ b/Content.Server/Atmos/TileAtmosphere.cs @@ -1127,6 +1127,10 @@ namespace Content.Server.Atmos UpdateVisuals(); + if (!Excited) + { + _gridAtmosphereComponent.AddActiveTile(this); + } return true; } diff --git a/Content.Server/GameObjects/Components/Atmos/BreathToolComponent.cs b/Content.Server/GameObjects/Components/Atmos/BreathToolComponent.cs new file mode 100644 index 0000000000..b5228797ea --- /dev/null +++ b/Content.Server/GameObjects/Components/Atmos/BreathToolComponent.cs @@ -0,0 +1,70 @@ +#nullable enable +using Content.Server.GameObjects.Components.Body.Respiratory; +using Content.Shared.GameObjects.Components.Inventory; +using Content.Shared.Interfaces.GameObjects.Components; +using Npgsql.TypeHandlers; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.Atmos +{ + /// + /// Used in internals as breath tool. + /// + [RegisterComponent] + public class BreathToolComponent : Component, IEquipped, IUnequipped + { + /// + /// Tool is functional only in allowed slots + /// + private EquipmentSlotDefines.SlotFlags _allowedSlots; + + public override string Name => "BreathMask"; + public bool IsFunctional { get; private set; } + public IEntity? ConnectedInternalsEntity { get; private set; } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _allowedSlots, "allowedSlots", EquipmentSlotDefines.SlotFlags.MASK); + } + + protected override void Shutdown() + { + base.Shutdown(); + DisconnectInternals(); + } + + public void Equipped(EquippedEventArgs eventArgs) + { + if ((EquipmentSlotDefines.SlotMasks[eventArgs.Slot] & _allowedSlots) != _allowedSlots) return; + IsFunctional = true; + + if (eventArgs.User.TryGetComponent(out InternalsComponent? internals)) + { + ConnectedInternalsEntity = eventArgs.User; + internals.ConnectBreathTool(Owner); + } + } + + public void Unequipped(UnequippedEventArgs eventArgs) + { + DisconnectInternals(); + + } + + public void DisconnectInternals() + { + var old = ConnectedInternalsEntity; + ConnectedInternalsEntity = null; + + if (old != null && old.TryGetComponent(out var internalsComponent)) + { + internalsComponent.DisconnectBreathTool(); + } + + IsFunctional = false; + } + } +} diff --git a/Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs b/Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs index 5f2efb662a..3ef464f36c 100644 --- a/Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/GasMixtureHolderComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos; +using Content.Server.Interfaces; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -6,23 +7,19 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Atmos { [RegisterComponent] - public class GasMixtureHolderComponent : Component + public class GasMixtureHolderComponent : Component, IGasMixtureHolder { public override string Name => "GasMixtureHolder"; - [ViewVariables] public GasMixture GasMixture { get; set; } + [ViewVariables] public GasMixture Air { get; set; } public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); - GasMixture = new GasMixture(); + Air = new GasMixture(); - serializer.DataReadWriteFunction( - "volume", - 0f, - vol => GasMixture.Volume = vol, - () => GasMixture.Volume); + serializer.DataField(this, x => x.Air, "air", new GasMixture()); } } } diff --git a/Content.Server/GameObjects/Components/Atmos/GasTankComponent.cs b/Content.Server/GameObjects/Components/Atmos/GasTankComponent.cs index 47f96463e0..7962b56eab 100644 --- a/Content.Server/GameObjects/Components/Atmos/GasTankComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/GasTankComponent.cs @@ -1,10 +1,356 @@ -using Robust.Shared.GameObjects; +#nullable enable +using System; +using Content.Server.Atmos; +using Content.Server.Explosions; +using Content.Server.GameObjects.Components.Body.Respiratory; +using Content.Server.GameObjects.Components.GUI; +using Content.Server.Interfaces; +using Content.Server.Utility; +using Content.Shared.Atmos; +using Content.Shared.Audio; +using Content.Shared.GameObjects.Components.Atmos.GasTank; +using Content.Shared.GameObjects.Components.Inventory; +using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Verbs; +using Content.Shared.Interfaces.GameObjects.Components; +using Content.Shared.Utility; +using Robust.Server.GameObjects.Components.UserInterface; +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.EntitySystemMessages; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Map; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; +using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Atmos { [RegisterComponent] - public class GasTankComponent : Component + [ComponentReference(typeof(IActivate))] + public class GasTankComponent : SharedGasTankComponent, IExamine, IGasMixtureHolder, IUse, IDropped, IActivate { - public override string Name => "GasTank"; + private const float MaxExplosionRange = 14f; + private const float DefaultOutputPressure = Atmospherics.OneAtmosphere; + + private float _pressureResistance; + + private int _integrity = 3; + + [Dependency] private readonly IEntityManager _entityManager = default!; + [ViewVariables] private BoundUserInterface? _userInterface; + + [ViewVariables] public GasMixture? Air { get; set; } + + /// + /// Distributed pressure. + /// + [ViewVariables] public float OutputPressure { get; private set; } + + /// + /// Tank is connected to internals. + /// + [ViewVariables] public bool IsConnected { get; set; } + + /// + /// Represents that tank is functional and can be connected to internals. + /// + public bool IsFunctional => GetInternalsComponent() != null; + + /// + /// Pressure at which tanks start leaking. + /// + public float TankLeakPressure { get; set; } = 30 * Atmospherics.OneAtmosphere; + + /// + /// Pressure at which tank spills all contents into atmosphere. + /// + public float TankRupturePressure { get; set; } = 40 * Atmospherics.OneAtmosphere; + + /// + /// Base 3x3 explosion. + /// + public float TankFragmentPressure { get; set; } = 50 * Atmospherics.OneAtmosphere; + + /// + /// Increases explosion for each scale kPa above threshold. + /// + public float TankFragmentScale { get; set; } = 10 * Atmospherics.OneAtmosphere; + + public override void Initialize() + { + base.Initialize(); + _userInterface = Owner.GetUIOrNull(SharedGasTankUiKey.Key); + if (_userInterface != null) + { + _userInterface.OnReceiveMessage += UserInterfaceOnOnReceiveMessage; + } + } + + public void OpenInterface(IPlayerSession session) + { + _userInterface?.Open(session); + UpdateUserInterface(true); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(this, x => x.Air, "air", new GasMixture()); + serializer.DataField(this, x => x.OutputPressure, "outputPressure", DefaultOutputPressure); + serializer.DataField(this, x => x.TankLeakPressure, "tankLeakPressure", 30 * Atmospherics.OneAtmosphere); + serializer.DataField(this, x => x.TankRupturePressure, "tankRupturePressure", 40 * Atmospherics.OneAtmosphere); + serializer.DataField(this, x => x.TankFragmentPressure, "tankFragmentPressure", 50 * Atmospherics.OneAtmosphere); + serializer.DataField(this, x => x.TankFragmentScale, "tankFragmentScale", 10 * Atmospherics.OneAtmosphere); + serializer.DataField(ref _pressureResistance, "pressureResistance", Atmospherics.OneAtmosphere * 5f); + } + + public void Examine(FormattedMessage message, bool inDetailsRange) + { + message.AddMarkup(Loc.GetString("Pressure: [color=orange]{0}[/color] kPa.\n", + Math.Round(Air?.Pressure ?? 0))); + if (IsConnected) + { + message.AddMarkup(Loc.GetString("Connected to external component")); + } + } + + protected override void Shutdown() + { + base.Shutdown(); + DisconnectFromInternals(); + } + + public void Update() + { + Air?.React(this); + CheckStatus(); + UpdateUserInterface(); + } + + public GasMixture? RemoveAir(float amount) + { + var gas = Air?.Remove(amount); + CheckStatus(); + return gas; + } + + public GasMixture RemoveAirVolume(float volume) + { + if (Air == null) + return new GasMixture(volume); + + var tankPressure = Air.Pressure; + if (tankPressure < OutputPressure) + { + OutputPressure = tankPressure; + UpdateUserInterface(); + } + + var molesNeeded = OutputPressure * volume / (Atmospherics.R * Air.Temperature); + + var air = RemoveAir(molesNeeded); + + if (air != null) + air.Volume = volume; + else + return new GasMixture(volume); + + return air; + } + + public bool UseEntity(UseEntityEventArgs eventArgs) + { + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return false; + OpenInterface(actor.playerSession); + return true; + } + + public void Activate(ActivateEventArgs eventArgs) + { + if (!eventArgs.User.TryGetComponent(out IActorComponent? actor)) return; + OpenInterface(actor.playerSession); + } + + public void ConnectToInternals() + { + if (IsConnected || !IsFunctional) return; + var internals = GetInternalsComponent(); + if (internals == null) return; + IsConnected = internals.TryConnectTank(Owner); + UpdateUserInterface(); + } + + public void DisconnectFromInternals(IEntity? owner = null) + { + if (!IsConnected) return; + IsConnected = false; + GetInternalsComponent(owner)?.DisconnectTank(); + UpdateUserInterface(); + } + + private void UpdateUserInterface(bool initialUpdate = false) + { + _userInterface?.SetState( + new GasTankBoundUserInterfaceState + { + TankPressure = Air?.Pressure ?? 0, + OutputPressure = initialUpdate ? OutputPressure : (float?) null, + InternalsConnected = IsConnected, + CanConnectInternals = IsFunctional && GetInternalsComponent() != null + }); + } + + private void UserInterfaceOnOnReceiveMessage(ServerBoundUserInterfaceMessage message) + { + switch (message.Message) + { + case GasTankSetPressureMessage msg: + OutputPressure = msg.Pressure; + break; + case GasTankToggleInternalsMessage _: + ToggleInternals(); + break; + } + } + + private void ToggleInternals() + { + if (IsConnected) + { + DisconnectFromInternals(); + return; + } + + ConnectToInternals(); + } + + private InternalsComponent? GetInternalsComponent(IEntity? owner = null) + { + if (owner != null) return owner.GetComponentOrNull(); + return ContainerHelpers.TryGetContainer(Owner, out var container) + ? container.Owner.GetComponentOrNull() + : null; + } + + public void AssumeAir(GasMixture giver) + { + Air?.Merge(giver); + CheckStatus(); + } + + private void CheckStatus() + { + if (Air == null) + return; + + var pressure = Air.Pressure; + + if (pressure > TankFragmentPressure) + { + // Give the gas a chance to build up more pressure. + for (var i = 0; i < 3; i++) + { + Air.React(this); + } + + pressure = Air.Pressure; + var range = (pressure - TankFragmentPressure) / TankFragmentScale; + + // Let's cap the explosion, yeah? + if (range > MaxExplosionRange) + { + range = MaxExplosionRange; + } + + Owner.SpawnExplosion((int) (range * 0.25f), (int) (range * 0.5f), (int) (range * 1.5f), 1); + + Owner.Delete(); + return; + } + + if (pressure > TankRupturePressure) + { + if (_integrity <= 0) + { + var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(); + tileAtmos?.AssumeAir(Air); + + EntitySystem.Get().PlayAtCoords("Audio/Effects/spray.ogg", Owner.Transform.Coordinates, + AudioHelpers.WithVariation(0.125f)); + + Owner.Delete(); + return; + } + + _integrity--; + return; + } + + if (pressure > TankLeakPressure) + { + if (_integrity <= 0) + { + var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(); + if (tileAtmos == null) + return; + + var leakedGas = Air.RemoveRatio(0.25f); + tileAtmos.AssumeAir(leakedGas); + } + else + { + _integrity--; + } + + return; + } + + if (_integrity < 3) + _integrity++; + } + + /// + /// Open interaction window + /// + [Verb] + private sealed class ControlVerb : Verb + { + public override bool RequireInteractionRange => true; + + protected override void GetData(IEntity user, GasTankComponent component, VerbData data) + { + data.Visibility = VerbVisibility.Invisible; + if (!user.HasComponent()) + { + return; + } + + data.Visibility = VerbVisibility.Visible; + data.Text = "Open Control Panel"; + } + + protected override void Activate(IEntity user, GasTankComponent component) + { + if (!user.TryGetComponent(out var actor)) + { + return; + } + + component.OpenInterface(actor.playerSession); + } + } + + public void Dropped(DroppedEventArgs eventArgs) + { + DisconnectFromInternals(eventArgs.User); + } } } diff --git a/Content.Server/GameObjects/Components/Body/Behavior/LungBehaviorComponent.cs b/Content.Server/GameObjects/Components/Body/Behavior/LungBehaviorComponent.cs index 78375835a4..195733fe71 100644 --- a/Content.Server/GameObjects/Components/Body/Behavior/LungBehaviorComponent.cs +++ b/Content.Server/GameObjects/Components/Body/Behavior/LungBehaviorComponent.cs @@ -2,7 +2,9 @@ using System; using System.Linq; using Content.Server.Atmos; +using Content.Server.GameObjects.Components.Atmos; using Content.Server.GameObjects.Components.Body.Circulatory; +using Content.Server.GameObjects.Components.Body.Respiratory; using Content.Server.Utility; using Content.Shared.Atmos; using Content.Shared.GameObjects.Components.Body.Behavior; @@ -10,6 +12,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.Timing; using Robust.Shared.IoC; using Robust.Shared.Localization; +using Robust.Shared.Log; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -147,6 +150,16 @@ namespace Content.Server.GameObjects.Components.Body.Behavior public override void Inhale(float frameTime) { + if (Body != null && Body.Owner.TryGetComponent(out InternalsComponent? internals) + && internals.BreathToolEntity != null && internals.GasTankEntity != null + && internals.BreathToolEntity.TryGetComponent(out BreathToolComponent? breathTool) + && breathTool.IsFunctional && internals.GasTankEntity.TryGetComponent(out GasTankComponent? gasTank) + && gasTank.Air != null) + { + Inhale(frameTime, gasTank.RemoveAirVolume(Atmospherics.BreathVolume)); + return; + } + if (!Owner.Transform.Coordinates.TryGetTileAir(out var tileAir)) { return; @@ -157,8 +170,7 @@ namespace Content.Server.GameObjects.Components.Body.Behavior public void Inhale(float frameTime, GasMixture from) { - var ratio = Atmospherics.BreathPercentage * frameTime; - + var ratio = (Atmospherics.BreathVolume / from.Volume) * frameTime; Transfer(from, Air, ratio); ToBloodstream(Air); diff --git a/Content.Server/GameObjects/Components/Body/Respiratory/InternalsComponent.cs b/Content.Server/GameObjects/Components/Body/Respiratory/InternalsComponent.cs new file mode 100644 index 0000000000..6c3380da4e --- /dev/null +++ b/Content.Server/GameObjects/Components/Body/Respiratory/InternalsComponent.cs @@ -0,0 +1,63 @@ +#nullable enable +using Content.Server.GameObjects.Components.Atmos; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Body.Respiratory +{ + [RegisterComponent] + public class InternalsComponent : Component + { + public override string Name => "Internals"; + [ViewVariables] public IEntity? GasTankEntity { get; set; } + [ViewVariables] public IEntity? BreathToolEntity { get; set; } + + public void DisconnectBreathTool() + { + var old = BreathToolEntity; + BreathToolEntity = null; + + if (old != null && old.TryGetComponent(out BreathToolComponent? breathTool) ) + { + breathTool.DisconnectInternals(); + DisconnectTank(); + } + } + + public void ConnectBreathTool(IEntity toolEntity) + { + if (BreathToolEntity != null && BreathToolEntity.TryGetComponent(out BreathToolComponent? tool)) + { + tool.DisconnectInternals(); + } + + BreathToolEntity = toolEntity; + } + + public void DisconnectTank() + { + if (GasTankEntity != null && GasTankEntity.TryGetComponent(out GasTankComponent? tank)) + { + tank.DisconnectFromInternals(Owner); + } + + GasTankEntity = null; + } + + public bool TryConnectTank(IEntity tankEntity) + { + if (BreathToolEntity == null) + return false; + + if (GasTankEntity != null && GasTankEntity.TryGetComponent(out GasTankComponent? tank)) + { + tank.DisconnectFromInternals(Owner); + } + + GasTankEntity = tankEntity; + return true; + } + + } +} diff --git a/Content.Server/GameObjects/Components/GUI/HandsComponent.cs b/Content.Server/GameObjects/Components/GUI/HandsComponent.cs index f105d0278a..092076d26d 100644 --- a/Content.Server/GameObjects/Components/GUI/HandsComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/HandsComponent.cs @@ -245,7 +245,7 @@ namespace Content.Server.GameObjects.Components.GUI return false; } - public bool Drop(string slot, EntityCoordinates coords, bool doMobChecks = true) + public bool Drop(string slot, EntityCoordinates coords, bool doMobChecks = true, bool doDropInteraction = true) { var hand = GetHand(slot); if (!CanDrop(slot, doMobChecks) || hand?.Entity == null) @@ -260,7 +260,7 @@ namespace Content.Server.GameObjects.Components.GUI return false; } - if (!DroppedInteraction(item, false)) + if (doDropInteraction && !DroppedInteraction(item, false)) return false; item.RemovedFromSlot(); @@ -282,7 +282,7 @@ namespace Content.Server.GameObjects.Components.GUI return true; } - public bool Drop(IEntity entity, EntityCoordinates coords, bool doMobChecks = true) + public bool Drop(IEntity entity, EntityCoordinates coords, bool doMobChecks = true, bool doDropInteraction = true) { if (entity == null) { @@ -294,15 +294,15 @@ namespace Content.Server.GameObjects.Components.GUI throw new ArgumentException("Entity must be held in one of our hands.", nameof(entity)); } - return Drop(slot, coords, doMobChecks); + return Drop(slot, coords, doMobChecks, doDropInteraction); } - public bool Drop(string slot, bool mobChecks = true) + public bool Drop(string slot, bool mobChecks = true, bool doDropInteraction = true) { - return Drop(slot, Owner.Transform.Coordinates, mobChecks); + return Drop(slot, Owner.Transform.Coordinates, mobChecks, doDropInteraction); } - public bool Drop(IEntity entity, bool mobChecks = true) + public bool Drop(IEntity entity, bool mobChecks = true, bool doDropInteraction = true) { if (entity == null) { @@ -314,10 +314,10 @@ namespace Content.Server.GameObjects.Components.GUI throw new ArgumentException("Entity must be held in one of our hands.", nameof(entity)); } - return Drop(slot, Owner.Transform.Coordinates, mobChecks); + return Drop(slot, Owner.Transform.Coordinates, mobChecks, doDropInteraction); } - public bool Drop(string slot, BaseContainer targetContainer, bool doMobChecks = true) + public bool Drop(string slot, BaseContainer targetContainer, bool doMobChecks = true, bool doDropInteraction = true) { if (slot == null) { @@ -352,7 +352,7 @@ namespace Content.Server.GameObjects.Components.GUI throw new InvalidOperationException(); } - if (!DroppedInteraction(item, doMobChecks)) + if (doDropInteraction && !DroppedInteraction(item, doMobChecks)) return false; item.RemovedFromSlot(); @@ -368,7 +368,7 @@ namespace Content.Server.GameObjects.Components.GUI return true; } - public bool Drop(IEntity entity, BaseContainer targetContainer, bool doMobChecks = true) + public bool Drop(IEntity entity, BaseContainer targetContainer, bool doMobChecks = true, bool doDropInteraction = true) { if (entity == null) { @@ -380,7 +380,7 @@ namespace Content.Server.GameObjects.Components.GUI throw new ArgumentException("Entity must be held in one of our hands.", nameof(entity)); } - return Drop(slot, targetContainer, doMobChecks); + return Drop(slot, targetContainer, doMobChecks, doDropInteraction); } /// diff --git a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs index 8c8edaa9cc..27102390cf 100644 --- a/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs +++ b/Content.Server/GameObjects/Components/GUI/InventoryComponent.cs @@ -156,6 +156,13 @@ namespace Content.Server.GameObjects.Components.GUI { return GetSlotItem(slot); } + + public IEnumerable LookupItems() where T: Component + { + return _slotContainers.Values.SelectMany(x => x.ContainedEntities.Select(e => e.GetComponentOrNull())) + .Where(x => x != null); + } + public T GetSlotItem(Slots slot) where T : ItemComponent { if (!_slotContainers.ContainsKey(slot)) @@ -435,7 +442,7 @@ namespace Content.Server.GameObjects.Components.GUI var activeHand = hands.GetActiveHand; if (activeHand != null && activeHand.Owner.TryGetComponent(out ItemComponent clothing)) { - hands.Drop(hands.ActiveHand); + hands.Drop(hands.ActiveHand, doDropInteraction:false); if (!Equip(msg.Inventoryslot, clothing, true, out var reason)) { hands.PutInHand(clothing); diff --git a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs index b1c5648e07..9c88a9769a 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs @@ -58,12 +58,12 @@ namespace Content.Server.GameObjects.Components.Items.Storage } } - public void Equipped(EquippedEventArgs eventArgs) + public virtual void Equipped(EquippedEventArgs eventArgs) { EquippedToSlot(); } - public void Unequipped(UnequippedEventArgs eventArgs) + public virtual void Unequipped(UnequippedEventArgs eventArgs) { RemovedFromSlot(); } diff --git a/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs b/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs new file mode 100644 index 0000000000..fe88bc52f3 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/GasTankSystem.cs @@ -0,0 +1,32 @@ +using System; +using Content.Server.GameObjects.Components.Atmos; +using JetBrains.Annotations; +using Robust.Shared.GameObjects.EntitySystemMessages; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.Timing; +using Robust.Shared.IoC; + +namespace Content.Server.GameObjects.EntitySystems +{ + [UsedImplicitly] + public class GasTankSystem : EntitySystem + { + private float _timer = 0f; + private const float Interval = 0.5f; + + public override void Update(float frameTime) + { + base.Update(frameTime); + + _timer += frameTime; + + if (_timer < Interval) return; + _timer = 0f; + + foreach (var gasTank in EntityManager.ComponentManager.EntityQuery()) + { + gasTank.Update(); + } + } + } +} diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs index a840d589fb..d2da0870d0 100644 --- a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs +++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs @@ -109,14 +109,16 @@ namespace Content.Server.Interfaces.GameObjects.Components.Items /// /// The slot of which to drop to drop the item. /// Whether to check the for the mob or not. + /// Whether to perform Dropped interactions. /// True on success, false if something blocked the drop. - bool Drop(string slot, bool mobChecks = true); + bool Drop(string slot, bool mobChecks = true, bool doDropInteraction = true); /// /// Drops an item held by one of our hand slots to the same position as our owning entity. /// /// The item to drop. /// Whether to check the for the mob or not. + /// Whether to perform Dropped interactions. /// True on success, false if something blocked the drop. /// /// Thrown if is null. @@ -124,7 +126,7 @@ namespace Content.Server.Interfaces.GameObjects.Components.Items /// /// Thrown if is not actually held in any hand. /// - bool Drop(IEntity entity, bool mobChecks = true); + bool Drop(IEntity entity, bool mobChecks = true, bool doDropInteraction = true); /// /// Drops the item in a slot. @@ -132,8 +134,9 @@ namespace Content.Server.Interfaces.GameObjects.Components.Items /// The slot to drop the item from. /// /// Whether to check the for the mob or not. + /// Whether to perform Dropped interactions. /// True if an item was dropped, false otherwise. - bool Drop(string slot, EntityCoordinates coords, bool doMobChecks = true); + bool Drop(string slot, EntityCoordinates coords, bool doMobChecks = true, bool doDropInteraction = true); /// /// Drop the specified entity in our hands to a certain position. @@ -145,6 +148,7 @@ namespace Content.Server.Interfaces.GameObjects.Components.Items /// The entity to drop, must be held in one of the hands. /// The coordinates to drop the entity at. /// Whether to check the for the mob or not. + /// Whether to perform Dropped interactions. /// /// True if the drop succeeded, /// false if it failed (due to failing to eject from our hand slot, etc...) @@ -155,7 +159,7 @@ namespace Content.Server.Interfaces.GameObjects.Components.Items /// /// Thrown if is not actually held in any hand. /// - bool Drop(IEntity entity, EntityCoordinates coords, bool doMobChecks = true); + bool Drop(IEntity entity, EntityCoordinates coords, bool doMobChecks = true, bool doDropInteraction = true); /// /// Drop the item contained in a slot into another container. @@ -163,13 +167,14 @@ namespace Content.Server.Interfaces.GameObjects.Components.Items /// The slot of which to drop the entity. /// The container to drop into. /// Whether to check the for the mob or not. + /// Whether to perform Dropped interactions. /// True on success, false if something was blocked (insertion or removal). /// /// Thrown if dry-run checks reported OK to remove and insert, /// but practical remove or insert returned false anyways. /// This is an edge-case that is currently unhandled. /// - bool Drop(string slot, BaseContainer targetContainer, bool doMobChecks = true); + bool Drop(string slot, BaseContainer targetContainer, bool doMobChecks = true, bool doDropInteraction = true); /// /// Drops an item in one of the hands into a container. @@ -177,6 +182,7 @@ namespace Content.Server.Interfaces.GameObjects.Components.Items /// The item to drop. /// The container to drop into. /// Whether to check the for the mob or not. + /// Whether to perform Dropped interactions. /// True on success, false if something was blocked (insertion or removal). /// /// Thrown if dry-run checks reported OK to remove and insert, @@ -189,7 +195,7 @@ namespace Content.Server.Interfaces.GameObjects.Components.Items /// /// Thrown if is not actually held in any hand. /// - bool Drop(IEntity entity, BaseContainer targetContainer, bool doMobChecks = true); + bool Drop(IEntity entity, BaseContainer targetContainer, bool doMobChecks = true, bool doDropInteraction = true); /// /// Checks whether the item in the specified hand can be dropped. diff --git a/Content.Server/Interfaces/IGasMixtureHolder.cs b/Content.Server/Interfaces/IGasMixtureHolder.cs index ad7d035f88..d155f02bea 100644 --- a/Content.Server/Interfaces/IGasMixtureHolder.cs +++ b/Content.Server/Interfaces/IGasMixtureHolder.cs @@ -5,5 +5,20 @@ namespace Content.Server.Interfaces public interface IGasMixtureHolder { public GasMixture Air { get; set; } + + public void AssumeAir(GasMixture giver) + { + Air.Merge(giver); + } + + public GasMixture RemoveAir(float amount) + { + return Air.Remove(amount); + } + + public GasMixture RemoveAirVolume(float ratio) + { + return Air.RemoveRatio(ratio); + } } } diff --git a/Content.Shared/Atmos/GasPrototype.cs b/Content.Shared/Atmos/GasPrototype.cs index 064ec0139d..3186b09847 100644 --- a/Content.Shared/Atmos/GasPrototype.cs +++ b/Content.Shared/Atmos/GasPrototype.cs @@ -19,6 +19,17 @@ namespace Content.Shared.Atmos /// public float SpecificHeat { get; private set; } + /// + /// Heat capacity ratio for gas + /// + public float HeatCapacityRatio { get; private set; } + + /// + /// Molar mass of gas + /// + public float MolarMass { get; set; } + + /// /// Minimum amount of moles for this gas to be visible. /// @@ -49,6 +60,7 @@ namespace Content.Shared.Atmos /// public string OverlayPath { get; private set; } + public string Color { get; private set; } public void LoadFrom(YamlMappingNode mapping) @@ -59,6 +71,8 @@ namespace Content.Shared.Atmos serializer.DataField(this, x => Name, "name", string.Empty); serializer.DataField(this, x => OverlayPath, "overlayPath", string.Empty); serializer.DataField(this, x => SpecificHeat, "specificHeat", 0f); + serializer.DataField(this, x => HeatCapacityRatio, "heatCapacityRatio", 1.4f); + serializer.DataField(this, x => MolarMass, "molarMass", 1f); serializer.DataField(this, x => GasMolesVisible, "gasMolesVisible", 0.25f); serializer.DataField(this, x => GasOverlayTexture, "gasOverlayTexture", string.Empty); serializer.DataField(this, x => GasOverlaySprite, "gasOverlaySprite", string.Empty); diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankBoundUserInterfaceState.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankBoundUserInterfaceState.cs new file mode 100644 index 0000000000..4c5bf4b02d --- /dev/null +++ b/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankBoundUserInterfaceState.cs @@ -0,0 +1,16 @@ +using System; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Atmos.GasTank +{ + [Serializable, NetSerializable] + public class GasTankBoundUserInterfaceState : BoundUserInterfaceState + { + public float TankPressure { get; set; } + public float? OutputPressure { get; set; } + public bool InternalsConnected { get; set; } + public bool CanConnectInternals { get; set; } + + } +} diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankSetPressureMessage.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankSetPressureMessage.cs new file mode 100644 index 0000000000..4fbf2bfc84 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankSetPressureMessage.cs @@ -0,0 +1,12 @@ +using System; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Atmos.GasTank +{ + [Serializable, NetSerializable] + public class GasTankSetPressureMessage : BoundUserInterfaceMessage + { + public float Pressure { get; set; } + } +} diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankToggleInternalsMessage.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankToggleInternalsMessage.cs new file mode 100644 index 0000000000..d009450482 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Atmos/GasTank/GasTankToggleInternalsMessage.cs @@ -0,0 +1,11 @@ +using System; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Atmos.GasTank +{ + [Serializable, NetSerializable] + public class GasTankToggleInternalsMessage : BoundUserInterfaceMessage + { + } +} diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankComponent.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankComponent.cs new file mode 100644 index 0000000000..541d1ecbc2 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameObjects; + +namespace Content.Shared.GameObjects.Components.Atmos.GasTank +{ + public class SharedGasTankComponent : Component + { + public override string Name => "GasTank"; + public override uint? NetID => ContentNetIDs.GAS_TANK; + } +} diff --git a/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankUiKey.cs b/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankUiKey.cs new file mode 100644 index 0000000000..246aad545d --- /dev/null +++ b/Content.Shared/GameObjects/Components/Atmos/GasTank/SharedGasTankUiKey.cs @@ -0,0 +1,11 @@ +using System; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Atmos.GasTank +{ + [Serializable, NetSerializable] + public enum SharedGasTankUiKey + { + Key + } +} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index d6dc3fcafc..32ebc3ed06 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -82,6 +82,8 @@ public const uint PLACEABLE_SURFACE = 1076; public const uint STORABLE = 1077; public const uint PULLABLE = 1078; + public const uint GAS_TANK = 1079; + // Net IDs for integration tests. public const uint PREDICTION_TEST = 10001; diff --git a/Resources/Prototypes/Atmospherics/gases.yml b/Resources/Prototypes/Atmospherics/gases.yml index 0e414ec304..a337e11985 100644 --- a/Resources/Prototypes/Atmospherics/gases.yml +++ b/Resources/Prototypes/Atmospherics/gases.yml @@ -2,24 +2,32 @@ id: 0 name: Oxygen specificHeat: 20 + heatCapacityRatio: 1.4 + molarMass: 32 color: 2887E8 - type: gas id: 1 name: Nitrogen specificHeat: 30 + heatCapacityRatio: 1.4 + molarMass: 28 color: DA1010 - type: gas id: 2 name: Carbon Dioxide specificHeat: 30 + heatCapacityRatio: 1.3 + molarMass: 44 color: 4e4e4e - type: gas id: 3 name: Phoron specificHeat: 200 + heatCapacityRatio: 1.7 + molarMass: 120 #creadth: making it very heavy (x4 of oxygen), idk what the proper value should be gasOverlaySprite: /Textures/Effects/atmospherics.rsi gasOverlayState: phoron color: FF3300 @@ -28,6 +36,8 @@ id: 4 name: Tritium specificHeat: 10 + heatCapacityRatio: 1.3 + molarMass: 6 gasOverlaySprite: /Textures/Effects/atmospherics.rsi gasOverlayState: tritium color: 13FF4B @@ -36,6 +46,8 @@ id: 5 name: Water Vapor specificHeat: 40 + heatCapacityRatio: 1.33 + molarMass: 18 gasOverlaySprite: /Textures/Effects/atmospherics.rsi gasOverlayState: water_vapor color: bffffd diff --git a/Resources/Prototypes/Catalog/Fills/lockers.yml b/Resources/Prototypes/Catalog/Fills/lockers.yml index 1262d869a8..8001709552 100644 --- a/Resources/Prototypes/Catalog/Fills/lockers.yml +++ b/Resources/Prototypes/Catalog/Fills/lockers.yml @@ -62,15 +62,10 @@ prob: 0.4 - name: BreathMaskClothing prob: 0.25 - # TODO: uncomment when we actually have these items. - #- name: TankOxygenSmallFilled - # prob: 0.4s - #- name: TankOxygenSmallFilled - # prob: 0.25 - #- name: MedkitOxygenFilled - # prob: 0.25 - #- name: TankOxygenFilled - # prob: 0.2 + - name: EmergencyOxygenTankFilled + prob: 0.4 + - name: OxygenTankFilled + prob: 0.2 - type: entity id: LockerBoozeFilled @@ -291,6 +286,13 @@ id: LockerFireFilled parent: LockerFire suffix: Filled + components: + - type: StorageFill + contents: + - name: RedOxygenTankFilled + prob: 0.6 + - name: OuterclothingFiresuit + prob: 0.75 - type: entity id: WardrobePajama diff --git a/Resources/Prototypes/Entities/Clothing/Back/gas_tanks.yml b/Resources/Prototypes/Entities/Clothing/Back/gas_tanks.yml new file mode 100644 index 0000000000..489c820463 --- /dev/null +++ b/Resources/Prototypes/Entities/Clothing/Back/gas_tanks.yml @@ -0,0 +1,314 @@ +- type: entity + parent: BaseItem + abstract: true + id: GasTankBase + name: Gas Tank + description: It's a gas tank. It contains gas. + components: + - type: Sprite + sprite: Objects/Tanks/generic.rsi + state: icon + - type: UserInterface + interfaces: + - key: enum.SharedGasTankUiKey.Key + type: GasTankBoundUserInterface + - type: Clothing + sprite: Objects/Tanks/generic.rsi + QuickEquip: false + Slots: + - Back + - Belt + - type: GasTank + +- type: entity + id: OxygenTank + parent: GasTankBase + name: oxygen tank + description: A tank of oxygen. + suffix: Empty + components: + - type: Sprite + sprite: Objects/Tanks/oxygen.rsi + state: icon + - type: GasTank + outputPressure: 21.27825 + air: + volume: 70 + temperature: 293.15 + - type: Clothing + sprite: Objects/Tanks/oxygen.rsi + Slots: + - Back + - Belt + +- type: entity + id: OxygenTankFilled + parent: OxygenTank + name: oxygen tank + description: A tank of oxygen. + suffix: Filled + components: + - type: GasTank + outputPressure: 21.27825 + air: + volume: 70 + moles: + - 22.6293856 # oxygen + temperature: 293.15 + +- type: entity + id: YellowOxygenTank + parent: OxygenTank + name: oxygen tank + description: A tank of oxygen. This one is in yellow. + suffix: Empty + components: + - type: Sprite + sprite: Objects/Tanks/yellow.rsi + state: icon + - type: Clothing + sprite: Objects/Tanks/yellow.rsi + Slots: + - Back + - Belt + +- type: entity + id: YellowOxygenTankFilled + parent: OxygenTankFilled + name: oxygen tank + description: A tank of oxygen. This one is in yellow. + suffix: Filled + components: + - type: Sprite + sprite: Objects/Tanks/yellow.rsi + state: icon + - type: Clothing + sprite: Objects/Tanks/yellow.rsi + Slots: + - Back + - Belt + +- type: entity + id: RedOxygenTank + parent: OxygenTank + name: oxygen tank + description: A tank of oxygen. This one is in yellow. + suffix: Empty + components: + - type: Sprite + sprite: Objects/Tanks/red.rsi + state: icon + - type: Clothing + sprite: Objects/Tanks/red.rsi + Slots: + - Back + - Belt + +- type: entity + id: RedOxygenTankFilled + parent: OxygenTankFilled + name: oxygen tank + description: A tank of oxygen. This one is in yellow. + suffix: Filled + components: + - type: Sprite + sprite: Objects/Tanks/red.rsi + state: icon + - type: Clothing + sprite: Objects/Tanks/red.rsi + Slots: + - Back + - Belt + +- type: entity + id: EmergencyOxygenTank + parent: OxygenTank + name: emergency oxygen tank + description: Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it. + suffix: Empty + components: + - type: Sprite + sprite: Objects/Tanks/emergency.rsi + state: icon + - type: GasTank + outputPressure: 21.27825 + air: + volume: 2 + temperature: 293.15 + - type: Clothing + sprite: Objects/Tanks/emergency.rsi + Slots: + - Back + - Pocket + - Belt + +- type: entity + id: EmergencyOxygenTankFilled + parent: EmergencyOxygenTank + name: emergency oxygen tank + description: Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it. + suffix: Filled + components: + - type: GasTank + outputPressure: 21.27825 + air: + volume: 2 + moles: + - 0.323460326 # oxygen + temperature: 293.15 + +- type: entity + id: ExtendedEmergencyOxygenTank + parent: EmergencyOxygenTank + name: extended-capacity emergency oxygen tank + description: Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it. + suffix: Empty + components: + - type: Sprite + sprite: Objects/Tanks/emergency_yellow.rsi + state: icon + - type: GasTank + outputPressure: 21.27825 + air: + volume: 6 + temperature: 293.15 + - type: Clothing + sprite: Objects/Tanks/emergency_yellow.rsi + Slots: + - Back + - Pocket + - Belt + +- type: entity + id: ExtendedEmergencyOxygenTankFilled + parent: ExtendedEmergencyOxygenTank + name: extended-capacity emergency oxygen tank + description: Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it. + suffix: Filled + components: + - type: GasTank + outputPressure: 21.27825 + air: + volume: 6 + moles: + - 0.969830813 # oxygen + temperature: 293.15 + +- type: entity + id: DoubleEmergencyOxygenTank + parent: ExtendedEmergencyOxygenTank + name: double emergency oxygen tank + description: Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it. + suffix: Empty + components: + - type: Sprite + sprite: Objects/Tanks/emergency_double.rsi + state: icon + - type: GasTank + outputPressure: 21.27825 + air: + volume: 10 + temperature: 293.15 + - type: Clothing + sprite: Objects/Tanks/emergency_double.rsi + Slots: + - Back + - Pocket + - Belt + +- type: entity + id: DoubleEmergencyOxygenTankFilled + parent: DoubleEmergencyOxygenTank + name: double emergency oxygen tank + description: Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it. + suffix: Filled + components: + - type: GasTank + outputPressure: 21.27825 + air: + volume: 10 + moles: + - 1.61721219 # oxygen + temperature: 293.15 + +- type: entity + id: AirTank + parent: GasTankBase + name: air tank + description: Mixed anyone? + suffix: Empty + components: + - type: Sprite + sprite: Objects/Tanks/generic.rsi + state: icon + - type: GasTank + outputPressure: 101.325 + air: + volume: 70 + temperature: 293.15 + - type: Clothing + sprite: Objects/Tanks/generic.rsi + Slots: + - Back + - Belt + +- type: entity + id: AirTankFilled + parent: GasTankBase + name: air tank + description: Mixed anyone? + suffix: Filled + components: + - type: Sprite + sprite: Objects/Tanks/generic.rsi + state: icon + - type: GasTank + outputPressure: 101.325 + air: + volume: 70 + moles: + - 4.75217098 # oxygen + - 17.8772147 # nitrogen + temperature: 293.15 + - type: Clothing + sprite: Objects/Tanks/generic.rsi + Slots: + - Back + - Belt + +- type: entity + id: PhoronTank + parent: GasTankBase + name: phoron tank + suffix: Empty + description: "Contains dangerous phoron. Do not inhale. Warning: extremely flammable." + components: + - type: Sprite + sprite: Objects/Tanks/phoron.rsi + state: icon + - type: GasTank + outputPressure: 101.325 + air: + volume: 70 + temperature: 293.15 + - type: Clothing + sprite: Objects/Tanks/phoron.rsi + Slots: [] # no straps + +- type: entity + id: PhoronTankFilled + parent: PhoronTank + name: phoron tank + suffix: Filled + description: "Contains dangerous phoron. Do not inhale. Warning: extremely flammable." + components: + - type: GasTank + outputPressure: 101.325 + air: + volume: 70 + moles: + - 0 + - 0 + - 0 + - 11.3146928 # phoron + temperature: 293.15 diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml index 01166060d8..9767140b7c 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml @@ -15,7 +15,7 @@ - type: Sprite sprite: Clothing/Masks/mask_gasalt.rsi state: icon - + - type: BreathMask - type: Clothing sprite: Clothing/Masks/mask_gasalt.rsi @@ -28,7 +28,7 @@ - type: Sprite sprite: Clothing/Masks/mask_gas.rsi state: icon - + - type: BreathMask - type: Clothing sprite: Clothing/Masks/mask_gas.rsi @@ -41,7 +41,7 @@ - type: Sprite sprite: Clothing/Masks/mask_breath.rsi state: icon - + - type: BreathMask - type: Clothing sprite: Clothing/Masks/mask_breath.rsi @@ -54,7 +54,7 @@ - type: Sprite sprite: Clothing/Masks/mask_clown.rsi state: icon - + - type: BreathMask - type: Clothing sprite: Clothing/Masks/mask_clown.rsi @@ -67,7 +67,7 @@ - type: Sprite sprite: Clothing/Masks/mask_joy.rsi state: icon - + - type: BreathMask - type: Clothing sprite: Clothing/Masks/mask_joy.rsi @@ -80,7 +80,7 @@ - type: Sprite sprite: Clothing/Masks/mask_mime.rsi state: icon - + - type: BreathMask - type: Clothing sprite: Clothing/Masks/mask_mime.rsi @@ -93,6 +93,6 @@ - type: Sprite sprite: Clothing/Masks/mask_sterile.rsi state: icon - + - type: BreathMask - type: Clothing sprite: Clothing/Masks/mask_sterile.rsi diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml index 660f344337..4d310059a1 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml @@ -150,7 +150,9 @@ components: - type: Sprite sprite: Clothing/OuterClothing/firesuit.rsi - + - type: PressureProtection + highPressureMultiplier: 0.85 + lowPressureMultiplier: 25 - type: Clothing sprite: Clothing/OuterClothing/firesuit.rsi diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 26741a8d06..c72316ba55 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -160,6 +160,7 @@ producesGases: Oxygen: 0.00045572916 CarbonDioxide: 0.00015190972 + - type: Internals - type: MobStateManager - type: HeatResistance - type: Appearance diff --git a/Resources/Prototypes/Entities/Objects/Boxes/boxes_general.yml b/Resources/Prototypes/Entities/Objects/Boxes/boxes_general.yml index 824c5f345a..7d30fd762f 100644 --- a/Resources/Prototypes/Entities/Objects/Boxes/boxes_general.yml +++ b/Resources/Prototypes/Entities/Objects/Boxes/boxes_general.yml @@ -91,7 +91,7 @@ - type: StorageFill contents: - name: BreathMaskClothing - #- name: O2 Canister + - name: EmergencyOxygenTankFilled #- name: Injector - type: Sprite layers: diff --git a/Resources/Textures/Objects/Tanks/anesthetic.rsi/equipped-BACKPACK.png b/Resources/Textures/Objects/Tanks/anesthetic.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000..57675fec22 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/anesthetic.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Tanks/anesthetic.rsi/icon.png b/Resources/Textures/Objects/Tanks/anesthetic.rsi/icon.png new file mode 100644 index 0000000000..027abc289f Binary files /dev/null and b/Resources/Textures/Objects/Tanks/anesthetic.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/anesthetic.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/anesthetic.rsi/inhand-left.png new file mode 100644 index 0000000000..628e74edbd Binary files /dev/null and b/Resources/Textures/Objects/Tanks/anesthetic.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/anesthetic.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/anesthetic.rsi/inhand-right.png new file mode 100644 index 0000000000..f6e2438c9a Binary files /dev/null and b/Resources/Textures/Objects/Tanks/anesthetic.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/anesthetic.rsi/meta.json b/Resources/Textures/Objects/Tanks/anesthetic.rsi/meta.json new file mode 100644 index 0000000000..5fdc78ab33 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/anesthetic.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "directions": 1 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tanks/emergency.rsi/icon.png b/Resources/Textures/Objects/Tanks/emergency.rsi/icon.png new file mode 100644 index 0000000000..a1f124628b Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/emergency.rsi/inhand-left.png new file mode 100644 index 0000000000..4cb29ce56c Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/emergency.rsi/inhand-right.png new file mode 100644 index 0000000000..6703263be1 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency.rsi/meta.json new file mode 100644 index 0000000000..5123c111a0 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/emergency.rsi/meta.json @@ -0,0 +1,38 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "states": [ + { + "name": "icon", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-left", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-right", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Tanks/emergency_double.rsi/icon.png b/Resources/Textures/Objects/Tanks/emergency_double.rsi/icon.png new file mode 100644 index 0000000000..78f1677a2b Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_double.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_double.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/emergency_double.rsi/inhand-left.png new file mode 100644 index 0000000000..55ff15618f Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_double.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_double.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/emergency_double.rsi/inhand-right.png new file mode 100644 index 0000000000..e72d222b94 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_double.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_double.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_double.rsi/meta.json new file mode 100644 index 0000000000..5123c111a0 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/emergency_double.rsi/meta.json @@ -0,0 +1,38 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "states": [ + { + "name": "icon", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-left", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-right", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/icon.png b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/icon.png new file mode 100644 index 0000000000..ab8bebedb6 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/inhand-left.png new file mode 100644 index 0000000000..55ff15618f Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/inhand-right.png new file mode 100644 index 0000000000..e72d222b94 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/meta.json new file mode 100644 index 0000000000..5123c111a0 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/meta.json @@ -0,0 +1,38 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "states": [ + { + "name": "icon", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-left", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-right", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Tanks/generic.rsi/equipped-BACKPACK.png b/Resources/Textures/Objects/Tanks/generic.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000..332f1d08f3 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/generic.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Tanks/generic.rsi/icon.png b/Resources/Textures/Objects/Tanks/generic.rsi/icon.png new file mode 100644 index 0000000000..0202db50aa Binary files /dev/null and b/Resources/Textures/Objects/Tanks/generic.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/generic.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/generic.rsi/inhand-left.png new file mode 100644 index 0000000000..c590366755 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/generic.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/generic.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/generic.rsi/inhand-right.png new file mode 100644 index 0000000000..e8680785b6 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/generic.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/generic.rsi/meta.json b/Resources/Textures/Objects/Tanks/generic.rsi/meta.json new file mode 100644 index 0000000000..19e8d88681 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/generic.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "directions": 1 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tanks/oxygen.rsi/equipped-BACKPACK.png b/Resources/Textures/Objects/Tanks/oxygen.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000..d890d08c1a Binary files /dev/null and b/Resources/Textures/Objects/Tanks/oxygen.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Tanks/oxygen.rsi/icon.png b/Resources/Textures/Objects/Tanks/oxygen.rsi/icon.png new file mode 100644 index 0000000000..95c148e604 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/oxygen.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/oxygen.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/oxygen.rsi/inhand-left.png new file mode 100644 index 0000000000..33f244834b Binary files /dev/null and b/Resources/Textures/Objects/Tanks/oxygen.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/oxygen.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/oxygen.rsi/inhand-right.png new file mode 100644 index 0000000000..c6368e4f39 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/oxygen.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/oxygen.rsi/meta.json b/Resources/Textures/Objects/Tanks/oxygen.rsi/meta.json new file mode 100644 index 0000000000..19e8d88681 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/oxygen.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "directions": 1 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tanks/phoron.rsi/icon.png b/Resources/Textures/Objects/Tanks/phoron.rsi/icon.png new file mode 100644 index 0000000000..a7fdcf8f67 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/phoron.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/phoron.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/phoron.rsi/inhand-left.png new file mode 100644 index 0000000000..a8654c7d9c Binary files /dev/null and b/Resources/Textures/Objects/Tanks/phoron.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/phoron.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/phoron.rsi/inhand-right.png new file mode 100644 index 0000000000..7dd141ed66 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/phoron.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/phoron.rsi/meta.json b/Resources/Textures/Objects/Tanks/phoron.rsi/meta.json new file mode 100644 index 0000000000..5123c111a0 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/phoron.rsi/meta.json @@ -0,0 +1,38 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "states": [ + { + "name": "icon", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-left", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "inhand-right", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Tanks/plasmaman.rsi/equipped-BACKPACK.png b/Resources/Textures/Objects/Tanks/plasmaman.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000..2aee6424a8 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/plasmaman.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Tanks/plasmaman.rsi/icon.png b/Resources/Textures/Objects/Tanks/plasmaman.rsi/icon.png new file mode 100644 index 0000000000..3ceb604b4c Binary files /dev/null and b/Resources/Textures/Objects/Tanks/plasmaman.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/plasmaman.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/plasmaman.rsi/inhand-left.png new file mode 100644 index 0000000000..495c4f398d Binary files /dev/null and b/Resources/Textures/Objects/Tanks/plasmaman.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/plasmaman.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/plasmaman.rsi/inhand-right.png new file mode 100644 index 0000000000..f02675bccd Binary files /dev/null and b/Resources/Textures/Objects/Tanks/plasmaman.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/plasmaman.rsi/meta.json b/Resources/Textures/Objects/Tanks/plasmaman.rsi/meta.json new file mode 100644 index 0000000000..19e8d88681 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/plasmaman.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "directions": 1 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tanks/red.rsi/equipped-BACKPACK.png b/Resources/Textures/Objects/Tanks/red.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000..6c36a11d4d Binary files /dev/null and b/Resources/Textures/Objects/Tanks/red.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Tanks/red.rsi/icon.png b/Resources/Textures/Objects/Tanks/red.rsi/icon.png new file mode 100644 index 0000000000..eb8ed16dce Binary files /dev/null and b/Resources/Textures/Objects/Tanks/red.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/red.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/red.rsi/inhand-left.png new file mode 100644 index 0000000000..fe2a53b1ba Binary files /dev/null and b/Resources/Textures/Objects/Tanks/red.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/red.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/red.rsi/inhand-right.png new file mode 100644 index 0000000000..a81bd42a1a Binary files /dev/null and b/Resources/Textures/Objects/Tanks/red.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/red.rsi/meta.json b/Resources/Textures/Objects/Tanks/red.rsi/meta.json new file mode 100644 index 0000000000..5fdc78ab33 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/red.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "directions": 1 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Tanks/yellow.rsi/equipped-BACKPACK.png b/Resources/Textures/Objects/Tanks/yellow.rsi/equipped-BACKPACK.png new file mode 100644 index 0000000000..0ae5d0fe8b Binary files /dev/null and b/Resources/Textures/Objects/Tanks/yellow.rsi/equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Tanks/yellow.rsi/icon.png b/Resources/Textures/Objects/Tanks/yellow.rsi/icon.png new file mode 100644 index 0000000000..e290d453be Binary files /dev/null and b/Resources/Textures/Objects/Tanks/yellow.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/yellow.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/yellow.rsi/inhand-left.png new file mode 100644 index 0000000000..d9c79703ca Binary files /dev/null and b/Resources/Textures/Objects/Tanks/yellow.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/yellow.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/yellow.rsi/inhand-right.png new file mode 100644 index 0000000000..b79125ee7c Binary files /dev/null and b/Resources/Textures/Objects/Tanks/yellow.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/yellow.rsi/meta.json b/Resources/Textures/Objects/Tanks/yellow.rsi/meta.json new file mode 100644 index 0000000000..5fdc78ab33 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/yellow.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit e1142f20f5e4661cb6845cfcf2dd69f864d67432", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "directions": 1 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +}