Add gas tank valve (#19830)
This commit is contained in:
@@ -32,24 +32,26 @@ namespace Content.Server.Atmos.Components
|
|||||||
public IPlayingAudioStream? ConnectStream;
|
public IPlayingAudioStream? ConnectStream;
|
||||||
public IPlayingAudioStream? DisconnectStream;
|
public IPlayingAudioStream? DisconnectStream;
|
||||||
|
|
||||||
[DataField("air")] public GasMixture Air { get; set; } = new();
|
[DataField("air"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public GasMixture Air { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pressure at which tank should be considered 'low' such as for internals.
|
/// Pressure at which tank should be considered 'low' such as for internals.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("tankLowPressure")]
|
[DataField("tankLowPressure"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float TankLowPressure { get; set; } = DefaultLowPressure;
|
public float TankLowPressure = DefaultLowPressure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Distributed pressure.
|
/// Distributed pressure.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("outputPressure")]
|
[DataField("outputPressure"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float OutputPressure { get; set; } = DefaultOutputPressure;
|
public float OutputPressure = DefaultOutputPressure;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tank is connected to internals.
|
/// Tank is connected to internals.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables] public bool IsConnected => User != null;
|
[ViewVariables]
|
||||||
|
public bool IsConnected => User != null;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public EntityUid? User;
|
public EntityUid? User;
|
||||||
@@ -64,28 +66,47 @@ namespace Content.Server.Atmos.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pressure at which tanks start leaking.
|
/// Pressure at which tanks start leaking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("tankLeakPressure")]
|
[DataField("tankLeakPressure"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float TankLeakPressure { get; set; } = 30 * Atmospherics.OneAtmosphere;
|
public float TankLeakPressure = 30 * Atmospherics.OneAtmosphere;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pressure at which tank spills all contents into atmosphere.
|
/// Pressure at which tank spills all contents into atmosphere.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("tankRupturePressure")]
|
[DataField("tankRupturePressure"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float TankRupturePressure { get; set; } = 40 * Atmospherics.OneAtmosphere;
|
public float TankRupturePressure = 40 * Atmospherics.OneAtmosphere;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base 3x3 explosion.
|
/// Base 3x3 explosion.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("tankFragmentPressure")]
|
[DataField("tankFragmentPressure"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float TankFragmentPressure { get; set; } = 50 * Atmospherics.OneAtmosphere;
|
public float TankFragmentPressure = 50 * Atmospherics.OneAtmosphere;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Increases explosion for each scale kPa above threshold.
|
/// Increases explosion for each scale kPa above threshold.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("tankFragmentScale")]
|
[DataField("tankFragmentScale"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float TankFragmentScale { get; set; } = 2 * Atmospherics.OneAtmosphere;
|
public float TankFragmentScale = 2 * Atmospherics.OneAtmosphere;
|
||||||
|
|
||||||
[DataField("toggleAction", required: true)]
|
[DataField("toggleAction", required: true)]
|
||||||
public InstantAction ToggleAction = new();
|
public InstantAction ToggleAction = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Valve to release gas from tank
|
||||||
|
/// </summary>
|
||||||
|
[DataField("isValveOpen"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public bool IsValveOpen = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gas release rate in L/s
|
||||||
|
/// </summary>
|
||||||
|
[DataField("valveOutputRate"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float ValveOutputRate = 100f;
|
||||||
|
|
||||||
|
[DataField("valveSound"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public SoundSpecifier ValveSound =
|
||||||
|
new SoundCollectionSpecifier("valveSqueak")
|
||||||
|
{
|
||||||
|
Params = AudioParams.Default.WithVolume(-5f),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Numerics;
|
||||||
using Content.Server.Atmos.Components;
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Body.Components;
|
using Content.Server.Body.Components;
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
@@ -15,6 +16,9 @@ using Robust.Server.Player;
|
|||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Random;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Robust.Shared.Physics.Systems;
|
||||||
|
|
||||||
namespace Content.Server.Atmos.EntitySystems
|
namespace Content.Server.Atmos.EntitySystems
|
||||||
{
|
{
|
||||||
@@ -28,6 +32,8 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
[Dependency] private readonly SharedContainerSystem _containers = default!;
|
[Dependency] private readonly SharedContainerSystem _containers = default!;
|
||||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||||
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
[Dependency] private readonly UserInterfaceSystem _ui = default!;
|
||||||
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
|
||||||
private const float TimerDelay = 0.5f;
|
private const float TimerDelay = 0.5f;
|
||||||
private float _timer = 0f;
|
private float _timer = 0f;
|
||||||
@@ -45,6 +51,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
SubscribeLocalEvent<GasTankComponent, GasTankToggleInternalsMessage>(OnGasTankToggleInternals);
|
SubscribeLocalEvent<GasTankComponent, GasTankToggleInternalsMessage>(OnGasTankToggleInternals);
|
||||||
SubscribeLocalEvent<GasTankComponent, GasAnalyzerScanEvent>(OnAnalyzed);
|
SubscribeLocalEvent<GasTankComponent, GasAnalyzerScanEvent>(OnAnalyzed);
|
||||||
SubscribeLocalEvent<GasTankComponent, PriceCalculationEvent>(OnGasTankPrice);
|
SubscribeLocalEvent<GasTankComponent, PriceCalculationEvent>(OnGasTankPrice);
|
||||||
|
SubscribeLocalEvent<GasTankComponent, GetVerbsEvent<AlternativeVerb>>(OnGetAlternativeVerb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGasShutdown(EntityUid uid, GasTankComponent component, ComponentShutdown args)
|
private void OnGasShutdown(EntityUid uid, GasTankComponent component, ComponentShutdown args)
|
||||||
@@ -103,6 +110,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
args.PushMarkup(Loc.GetString("comp-gas-tank-examine", ("pressure", Math.Round(component.Air?.Pressure ?? 0))));
|
args.PushMarkup(Loc.GetString("comp-gas-tank-examine", ("pressure", Math.Round(component.Air?.Pressure ?? 0))));
|
||||||
if (component.IsConnected)
|
if (component.IsConnected)
|
||||||
args.PushMarkup(Loc.GetString("comp-gas-tank-connected"));
|
args.PushMarkup(Loc.GetString("comp-gas-tank-connected"));
|
||||||
|
args.PushMarkup(Loc.GetString(component.IsValveOpen ? "comp-gas-tank-examine-open-valve" : "comp-gas-tank-examine-closed-valve"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnActionToggle(EntityUid uid, GasTankComponent component, ToggleActionEvent args)
|
private void OnActionToggle(EntityUid uid, GasTankComponent component, ToggleActionEvent args)
|
||||||
@@ -123,27 +131,50 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
if (_timer < TimerDelay) return;
|
if (_timer < TimerDelay) return;
|
||||||
_timer -= TimerDelay;
|
_timer -= TimerDelay;
|
||||||
|
|
||||||
foreach (var gasTank in EntityManager.EntityQuery<GasTankComponent>())
|
var query = EntityQueryEnumerator<GasTankComponent>();
|
||||||
|
while (query.MoveNext(out var uid, out var gasTank))
|
||||||
{
|
{
|
||||||
|
if (gasTank.IsValveOpen && !gasTank.IsLowPressure)
|
||||||
|
{
|
||||||
|
ReleaseGas(uid, gasTank);
|
||||||
|
}
|
||||||
|
|
||||||
if (gasTank.CheckUser)
|
if (gasTank.CheckUser)
|
||||||
{
|
{
|
||||||
gasTank.CheckUser = false;
|
gasTank.CheckUser = false;
|
||||||
if (Transform(gasTank.Owner).ParentUid != gasTank.User)
|
if (Transform(uid).ParentUid != gasTank.User)
|
||||||
{
|
{
|
||||||
DisconnectFromInternals(gasTank);
|
DisconnectFromInternals(gasTank);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_atmosphereSystem.React(gasTank.Air, gasTank);
|
if (gasTank.Air != null)
|
||||||
|
{
|
||||||
|
_atmosphereSystem.React(gasTank.Air, gasTank);
|
||||||
|
}
|
||||||
CheckStatus(gasTank);
|
CheckStatus(gasTank);
|
||||||
if (_ui.IsUiOpen(gasTank.Owner, SharedGasTankUiKey.Key))
|
if (_ui.IsUiOpen(uid, SharedGasTankUiKey.Key))
|
||||||
{
|
{
|
||||||
UpdateUserInterface(gasTank);
|
UpdateUserInterface(gasTank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReleaseGas(EntityUid uid, GasTankComponent component)
|
||||||
|
{
|
||||||
|
var removed = RemoveAirVolume(component, component.ValveOutputRate * TimerDelay);
|
||||||
|
var environment = _atmosphereSystem.GetContainingMixture(uid, false, true);
|
||||||
|
if (environment != null)
|
||||||
|
{
|
||||||
|
_atmosphereSystem.Merge(environment, removed);
|
||||||
|
}
|
||||||
|
var impulse = removed.TotalMoles * removed.Temperature;
|
||||||
|
_physics.ApplyLinearImpulse(uid, _random.NextAngle().ToWorldVec() * impulse);
|
||||||
|
_physics.ApplyAngularImpulse(uid, _random.NextFloat(-3f, 3f));
|
||||||
|
_audioSys.PlayPvs(component.RuptureSound, uid);
|
||||||
|
}
|
||||||
|
|
||||||
private void ToggleInternals(GasTankComponent component)
|
private void ToggleInternals(GasTankComponent component)
|
||||||
{
|
{
|
||||||
if (component.IsConnected)
|
if (component.IsConnected)
|
||||||
@@ -183,7 +214,7 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
public bool CanConnectToInternals(GasTankComponent component)
|
public bool CanConnectToInternals(GasTankComponent component)
|
||||||
{
|
{
|
||||||
var internals = GetInternalsComponent(component);
|
var internals = GetInternalsComponent(component);
|
||||||
return internals != null && internals.BreathToolEntity != null;
|
return internals != null && internals.BreathToolEntity != null && !component.IsValveOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConnectToInternals(GasTankComponent component)
|
public void ConnectToInternals(GasTankComponent component)
|
||||||
@@ -330,5 +361,21 @@ namespace Content.Server.Atmos.EntitySystems
|
|||||||
{
|
{
|
||||||
args.Price += _atmosphereSystem.GetPrice(component.Air);
|
args.Price += _atmosphereSystem.GetPrice(component.Air);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnGetAlternativeVerb(EntityUid uid, GasTankComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
|
||||||
|
return;
|
||||||
|
args.Verbs.Add(new AlternativeVerb()
|
||||||
|
{
|
||||||
|
Text = component.IsValveOpen ? Loc.GetString("comp-gas-tank-close-valve") : Loc.GetString("comp-gas-tank-open-valve"),
|
||||||
|
Act = () =>
|
||||||
|
{
|
||||||
|
component.IsValveOpen = !component.IsValveOpen;
|
||||||
|
_audioSys.PlayPvs(component.ValveSound, uid);
|
||||||
|
},
|
||||||
|
Disabled = component.IsConnected,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ public sealed class GasCanisterSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Check the used item is valid...
|
// Check the used item is valid...
|
||||||
if (!HasComp<GasTankComponent>(args.Used))
|
if (!TryComp<GasTankComponent>(args.Used, out var gasTank) || gasTank.IsValveOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Preventing inserting a tank since if its locked you cant remove it.
|
// Preventing inserting a tank since if its locked you cant remove it.
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ comp-gas-tank-examine = Pressure: [color=orange]{PRESSURE($pressure)}[/color].
|
|||||||
# Examine text when internals are active.
|
# Examine text when internals are active.
|
||||||
comp-gas-tank-connected = It's connected to an external component.
|
comp-gas-tank-connected = It's connected to an external component.
|
||||||
|
|
||||||
|
# Examine text when valve is open or closed.
|
||||||
|
comp-gas-tank-examine-open-valve = Gas release valve is [color=red]open[/color].
|
||||||
|
comp-gas-tank-examine-closed-valve = Gas release valve is [color=green]closed[/color].
|
||||||
|
|
||||||
## ControlVerb
|
## ControlVerb
|
||||||
control-verb-open-control-panel-text = Open Control Panel
|
control-verb-open-control-panel-text = Open Control Panel
|
||||||
|
|
||||||
@@ -17,3 +21,7 @@ gas-tank-window-tank-pressure-text = Pressure: {$tankPressure} kPA
|
|||||||
gas-tank-window-internal-text = Internals: {$status}
|
gas-tank-window-internal-text = Internals: {$status}
|
||||||
gas-tank-window-internal-connected = [color=green]Connected[/color]
|
gas-tank-window-internal-connected = [color=green]Connected[/color]
|
||||||
gas-tank-window-internal-disconnected = [color=red]Disconnected[/color]
|
gas-tank-window-internal-disconnected = [color=red]Disconnected[/color]
|
||||||
|
|
||||||
|
## Valve
|
||||||
|
comp-gas-tank-open-valve = Open Valve
|
||||||
|
comp-gas-tank-close-valve = Close Valve
|
||||||
|
|||||||
Reference in New Issue
Block a user