Add space heaters (#25250)
This commit is contained in:
90
Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs
Normal file
90
Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using Content.Shared.Atmos.Piping.Portable.Components;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
|
||||||
|
namespace Content.Client.Atmos.UI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a <see cref="SpaceHeaterWindow"/> and updates it when new server messages are received.
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed class SpaceHeaterBoundUserInterface : BoundUserInterface
|
||||||
|
{
|
||||||
|
[ViewVariables]
|
||||||
|
private SpaceHeaterWindow? _window;
|
||||||
|
|
||||||
|
public SpaceHeaterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Open()
|
||||||
|
{
|
||||||
|
base.Open();
|
||||||
|
|
||||||
|
_window = new SpaceHeaterWindow();
|
||||||
|
|
||||||
|
if (State != null)
|
||||||
|
UpdateState(State);
|
||||||
|
|
||||||
|
_window.OpenCentered();
|
||||||
|
|
||||||
|
_window.OnClose += Close;
|
||||||
|
|
||||||
|
_window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed();
|
||||||
|
_window.IncreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(_window.TemperatureChangeDelta);
|
||||||
|
_window.DecreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(-_window.TemperatureChangeDelta);
|
||||||
|
_window.ModeSelector.OnItemSelected += OnModeChanged;
|
||||||
|
|
||||||
|
_window.PowerLevelSelector.OnItemSelected += OnPowerLevelChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnToggleStatusButtonPressed()
|
||||||
|
{
|
||||||
|
_window?.SetActive(!_window.Active);
|
||||||
|
SendMessage(new SpaceHeaterToggleMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTemperatureRangeChanged(float changeAmount)
|
||||||
|
{
|
||||||
|
SendMessage(new SpaceHeaterChangeTemperatureMessage(changeAmount));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnModeChanged(OptionButton.ItemSelectedEventArgs args)
|
||||||
|
{
|
||||||
|
_window?.ModeSelector.SelectId(args.Id);
|
||||||
|
SendMessage(new SpaceHeaterChangeModeMessage((SpaceHeaterMode)args.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPowerLevelChange(RadioOptionItemSelectedEventArgs<int> args)
|
||||||
|
{
|
||||||
|
_window?.PowerLevelSelector.Select(args.Id);
|
||||||
|
SendMessage(new SpaceHeaterChangePowerLevelMessage((SpaceHeaterPowerLevel)args.Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the UI state based on server-sent info
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="state"></param>
|
||||||
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
|
{
|
||||||
|
base.UpdateState(state);
|
||||||
|
if (_window == null || state is not SpaceHeaterBoundUserInterfaceState cast)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_window.SetActive(cast.Enabled);
|
||||||
|
_window.ModeSelector.SelectId((int)cast.Mode);
|
||||||
|
_window.PowerLevelSelector.Select((int)cast.PowerLevel);
|
||||||
|
|
||||||
|
_window.MinTemp = cast.MinTemperature;
|
||||||
|
_window.MaxTemp = cast.MaxTemperature;
|
||||||
|
_window.SetTemperature(cast.TargetTemperature);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
if (!disposing)
|
||||||
|
return;
|
||||||
|
_window?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
34
Content.Client/Atmos/UI/SpaceHeaterWindow.xaml
Normal file
34
Content.Client/Atmos/UI/SpaceHeaterWindow.xaml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
MinSize="280 160" Title="Temperature Control Unit">
|
||||||
|
|
||||||
|
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||||
|
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
|
<Button Text="{Loc comp-space-heater-ui-status-disabled}" Access="Public" Name="ToggleStatusButton"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" SeparationOverride="5">
|
||||||
|
<Label Text="{Loc comp-space-heater-ui-mode}"/>
|
||||||
|
<OptionButton Access="Public" Name="ModeSelector"/>
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" SeparationOverride="5">
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
|
<Label Text="{Loc comp-space-heater-ui-thermostat}"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" HorizontalAlignment="Right">
|
||||||
|
<Button Text="{Loc comp-space-heater-ui-decrease-temperature-range}" Access="Public" Name="DecreaseTempRange" StyleClasses="OpenRight"/>
|
||||||
|
<LineEdit Name ="Thermostat" MinSize="55 0"></LineEdit>
|
||||||
|
<Button Text="{Loc comp-space-heater-ui-increase-temperature-range}" Access="Public" Name="IncreaseTempRange" StyleClasses="OpenLeft"/>
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
|
||||||
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" SeparationOverride="5">
|
||||||
|
<Label Text="{Loc comp-space-heater-ui-power-consumption}"/>
|
||||||
|
<BoxContainer Name="PowerLevelSelectorHBox" Access="Public" SeparationOverride="2"/>
|
||||||
|
</BoxContainer>
|
||||||
|
|
||||||
|
</BoxContainer>
|
||||||
|
</DefaultWindow>
|
||||||
73
Content.Client/Atmos/UI/SpaceHeaterWindow.xaml.cs
Normal file
73
Content.Client/Atmos/UI/SpaceHeaterWindow.xaml.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using Robust.Client.AutoGenerated;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Atmos.Piping.Portable.Components;
|
||||||
|
|
||||||
|
namespace Content.Client.Atmos.UI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Client-side UI used to control a space heater.
|
||||||
|
/// </summary>
|
||||||
|
[GenerateTypedNameReferences]
|
||||||
|
public sealed partial class SpaceHeaterWindow : DefaultWindow
|
||||||
|
{
|
||||||
|
// To account for a minimum delta temperature for atmos equalization to trigger we use a fixed step for target temperature increment/decrement
|
||||||
|
public int TemperatureChangeDelta = 5;
|
||||||
|
public bool Active;
|
||||||
|
|
||||||
|
// Temperatures range bounds in Kelvin (K)
|
||||||
|
public float MinTemp;
|
||||||
|
public float MaxTemp;
|
||||||
|
|
||||||
|
public RadioOptions<int> PowerLevelSelector;
|
||||||
|
|
||||||
|
public SpaceHeaterWindow()
|
||||||
|
{
|
||||||
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
|
// Add the Mode selector list
|
||||||
|
foreach (var value in Enum.GetValues<SpaceHeaterMode>())
|
||||||
|
{
|
||||||
|
ModeSelector.AddItem(Loc.GetString($"comp-space-heater-mode-{value}"), (int)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Power level radio buttons
|
||||||
|
PowerLevelSelectorHBox.AddChild(PowerLevelSelector = new RadioOptions<int>(RadioOptionsLayout.Horizontal));
|
||||||
|
PowerLevelSelector.FirstButtonStyle = "OpenRight";
|
||||||
|
PowerLevelSelector.LastButtonStyle = "OpenLeft";
|
||||||
|
PowerLevelSelector.ButtonStyle = "OpenBoth";
|
||||||
|
foreach (var value in Enum.GetValues<SpaceHeaterPowerLevel>())
|
||||||
|
{
|
||||||
|
PowerLevelSelector.AddItem(Loc.GetString($"comp-space-heater-ui-{value}-power-consumption"), (int)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only allow temperature increment/decrement of TemperatureChangeDelta
|
||||||
|
Thermostat.Editable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetActive(bool active)
|
||||||
|
{
|
||||||
|
Active = active;
|
||||||
|
ToggleStatusButton.Pressed = active;
|
||||||
|
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-space-heater-ui-status-enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-space-heater-ui-status-disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetTemperature(float targetTemperature)
|
||||||
|
{
|
||||||
|
Thermostat.SetText($"{targetTemperature - Atmospherics.T0C} °C");
|
||||||
|
|
||||||
|
IncreaseTempRange.Disabled = targetTemperature + TemperatureChangeDelta > MaxTemp;
|
||||||
|
DecreaseTempRange.Disabled = targetTemperature - TemperatureChangeDelta < MinTemp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -55,6 +55,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
|||||||
|
|
||||||
private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, ref AtmosDeviceUpdateEvent args)
|
private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, ref AtmosDeviceUpdateEvent args)
|
||||||
{
|
{
|
||||||
|
thermoMachine.LastEnergyDelta = 0f;
|
||||||
if (!(_power.IsPowered(uid) && TryComp<ApcPowerReceiverComponent>(uid, out var receiver)))
|
if (!(_power.IsPowered(uid) && TryComp<ApcPowerReceiverComponent>(uid, out var receiver)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -100,12 +101,14 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
|
|||||||
if (thermoMachine.Atmospheric)
|
if (thermoMachine.Atmospheric)
|
||||||
{
|
{
|
||||||
_atmosphereSystem.AddHeat(heatExchangeGasMixture, dQActual);
|
_atmosphereSystem.AddHeat(heatExchangeGasMixture, dQActual);
|
||||||
|
thermoMachine.LastEnergyDelta = dQActual;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float dQLeak = dQActual * thermoMachine.EnergyLeakPercentage;
|
float dQLeak = dQActual * thermoMachine.EnergyLeakPercentage;
|
||||||
float dQPipe = dQActual - dQLeak;
|
float dQPipe = dQActual - dQLeak;
|
||||||
_atmosphereSystem.AddHeat(heatExchangeGasMixture, dQPipe);
|
_atmosphereSystem.AddHeat(heatExchangeGasMixture, dQPipe);
|
||||||
|
thermoMachine.LastEnergyDelta = dQPipe;
|
||||||
|
|
||||||
if (dQLeak != 0f && _atmosphereSystem.GetContainingMixture(uid) is { } containingMixture)
|
if (dQLeak != 0f && _atmosphereSystem.GetContainingMixture(uid) is { } containingMixture)
|
||||||
_atmosphereSystem.AddHeat(containingMixture, dQLeak);
|
_atmosphereSystem.AddHeat(containingMixture, dQLeak);
|
||||||
|
|||||||
58
Content.Server/Atmos/Portable/SpaceHeaterComponent.cs
Normal file
58
Content.Server/Atmos/Portable/SpaceHeaterComponent.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Atmos.Piping.Portable.Components;
|
||||||
|
using Content.Shared.Atmos.Visuals;
|
||||||
|
|
||||||
|
namespace Content.Server.Atmos.Portable;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class SpaceHeaterComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Current mode the space heater is in. Possible values : Auto, Heat and Cool
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public SpaceHeaterMode Mode = SpaceHeaterMode.Auto;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The power level the space heater is currently set to. Possible values : Low, Medium, High
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public SpaceHeaterPowerLevel PowerLevel = SpaceHeaterPowerLevel.Medium;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum target temperature the device can be set to
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float MaxTemperature = Atmospherics.T20C + 20;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimal target temperature the device can be set to
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float MinTemperature = Atmospherics.T0C - 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Coefficient of performance. Output power / input power.
|
||||||
|
/// Positive for heaters, negative for freezers.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("heatingCoefficientOfPerformance")]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float HeatingCp = 1f;
|
||||||
|
|
||||||
|
[DataField("coolingCoefficientOfPerformance")]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float CoolingCp = -0.9f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The delta from the target temperature after which the space heater switch mode while in Auto. Value should account for the thermomachine temperature tolerance.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float AutoModeSwitchThreshold = 0.8f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current electrical power consumption, in watts, of the space heater at medium power level. Passed to the thermomachine component.
|
||||||
|
/// </summary>
|
||||||
|
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public float PowerConsumption = 3500f;
|
||||||
|
}
|
||||||
191
Content.Server/Atmos/Portable/SpaceHeaterSystem.cs
Normal file
191
Content.Server/Atmos/Portable/SpaceHeaterSystem.cs
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
using Content.Server.Atmos.EntitySystems;
|
||||||
|
using Content.Server.Atmos.Piping.Components;
|
||||||
|
using Content.Server.Atmos.Piping.Unary.Components;
|
||||||
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.Power.Components;
|
||||||
|
using Content.Server.Power.EntitySystems;
|
||||||
|
using Content.Shared.Atmos.Piping.Portable.Components;
|
||||||
|
using Content.Shared.Atmos.Visuals;
|
||||||
|
using Content.Shared.UserInterface;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Atmos.Portable;
|
||||||
|
|
||||||
|
public sealed class SpaceHeaterSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||||
|
[Dependency] private readonly PopupSystem _popup = default!;
|
||||||
|
[Dependency] private readonly PowerReceiverSystem _power = default!;
|
||||||
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
|
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, ActivatableUIOpenAttemptEvent>(OnUIActivationAttempt);
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, BeforeActivatableUIOpenEvent>(OnBeforeOpened);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, AtmosDeviceUpdateEvent>(OnDeviceUpdated);
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, MapInitEvent>(OnInit);
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, PowerChangedEvent>(OnPowerChanged);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, SpaceHeaterChangeModeMessage>(OnModeChanged);
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, SpaceHeaterChangePowerLevelMessage>(OnPowerLevelChanged);
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, SpaceHeaterChangeTemperatureMessage>(OnTemperatureChanged);
|
||||||
|
SubscribeLocalEvent<SpaceHeaterComponent, SpaceHeaterToggleMessage>(OnToggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInit(EntityUid uid, SpaceHeaterComponent spaceHeater, MapInitEvent args)
|
||||||
|
{
|
||||||
|
if (!TryComp<GasThermoMachineComponent>(uid, out var thermoMachine))
|
||||||
|
return;
|
||||||
|
thermoMachine.Cp = spaceHeater.HeatingCp;
|
||||||
|
thermoMachine.HeatCapacity = spaceHeater.PowerConsumption;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBeforeOpened(EntityUid uid, SpaceHeaterComponent spaceHeater, BeforeActivatableUIOpenEvent args)
|
||||||
|
{
|
||||||
|
DirtyUI(uid, spaceHeater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUIActivationAttempt(EntityUid uid, SpaceHeaterComponent spaceHeater, ActivatableUIOpenAttemptEvent args)
|
||||||
|
{
|
||||||
|
if (!Comp<TransformComponent>(uid).Anchored)
|
||||||
|
{
|
||||||
|
_popup.PopupEntity(Loc.GetString("comp-space-heater-unanchored", ("device", Loc.GetString("comp-space-heater-device-name"))), uid, args.User);
|
||||||
|
args.Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDeviceUpdated(EntityUid uid, SpaceHeaterComponent spaceHeater, ref AtmosDeviceUpdateEvent args)
|
||||||
|
{
|
||||||
|
if (!_power.IsPowered(uid)
|
||||||
|
|| !TryComp<GasThermoMachineComponent>(uid, out var thermoMachine))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAppearance(uid);
|
||||||
|
|
||||||
|
// If in automatic temperature mode, check if we need to adjust the heat exchange direction
|
||||||
|
if (spaceHeater.Mode == SpaceHeaterMode.Auto)
|
||||||
|
{
|
||||||
|
var environment = _atmosphereSystem.GetContainingMixture(uid);
|
||||||
|
if (environment == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (environment.Temperature <= thermoMachine.TargetTemperature - (thermoMachine.TemperatureTolerance + spaceHeater.AutoModeSwitchThreshold))
|
||||||
|
{
|
||||||
|
thermoMachine.Cp = spaceHeater.HeatingCp;
|
||||||
|
}
|
||||||
|
else if (environment.Temperature >= thermoMachine.TargetTemperature + (thermoMachine.TemperatureTolerance + spaceHeater.AutoModeSwitchThreshold))
|
||||||
|
{
|
||||||
|
thermoMachine.Cp = spaceHeater.CoolingCp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPowerChanged(EntityUid uid, SpaceHeaterComponent spaceHeater, ref PowerChangedEvent args)
|
||||||
|
{
|
||||||
|
UpdateAppearance(uid);
|
||||||
|
DirtyUI(uid, spaceHeater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnToggle(EntityUid uid, SpaceHeaterComponent spaceHeater, SpaceHeaterToggleMessage args)
|
||||||
|
{
|
||||||
|
ApcPowerReceiverComponent? powerReceiver = null;
|
||||||
|
if (!Resolve(uid, ref powerReceiver))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_power.TogglePower(uid);
|
||||||
|
|
||||||
|
UpdateAppearance(uid);
|
||||||
|
DirtyUI(uid, spaceHeater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTemperatureChanged(EntityUid uid, SpaceHeaterComponent spaceHeater, SpaceHeaterChangeTemperatureMessage args)
|
||||||
|
{
|
||||||
|
if (!TryComp<GasThermoMachineComponent>(uid, out var thermoMachine))
|
||||||
|
return;
|
||||||
|
|
||||||
|
thermoMachine.TargetTemperature += args.Temperature;
|
||||||
|
|
||||||
|
UpdateAppearance(uid);
|
||||||
|
DirtyUI(uid, spaceHeater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnModeChanged(EntityUid uid, SpaceHeaterComponent spaceHeater, SpaceHeaterChangeModeMessage args)
|
||||||
|
{
|
||||||
|
if (!TryComp<GasThermoMachineComponent>(uid, out var thermoMachine))
|
||||||
|
return;
|
||||||
|
|
||||||
|
spaceHeater.Mode = args.Mode;
|
||||||
|
|
||||||
|
if (spaceHeater.Mode == SpaceHeaterMode.Heat)
|
||||||
|
thermoMachine.Cp = spaceHeater.HeatingCp;
|
||||||
|
else if (spaceHeater.Mode == SpaceHeaterMode.Cool)
|
||||||
|
thermoMachine.Cp = spaceHeater.CoolingCp;
|
||||||
|
|
||||||
|
DirtyUI(uid, spaceHeater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPowerLevelChanged(EntityUid uid, SpaceHeaterComponent spaceHeater, SpaceHeaterChangePowerLevelMessage args)
|
||||||
|
{
|
||||||
|
if (!TryComp<GasThermoMachineComponent>(uid, out var thermoMachine))
|
||||||
|
return;
|
||||||
|
|
||||||
|
spaceHeater.PowerLevel = args.PowerLevel;
|
||||||
|
|
||||||
|
switch (spaceHeater.PowerLevel)
|
||||||
|
{
|
||||||
|
case SpaceHeaterPowerLevel.Low:
|
||||||
|
thermoMachine.HeatCapacity = spaceHeater.PowerConsumption / 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpaceHeaterPowerLevel.Medium:
|
||||||
|
thermoMachine.HeatCapacity = spaceHeater.PowerConsumption;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpaceHeaterPowerLevel.High:
|
||||||
|
thermoMachine.HeatCapacity = spaceHeater.PowerConsumption * 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirtyUI(uid, spaceHeater);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DirtyUI(EntityUid uid, SpaceHeaterComponent? spaceHeater)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref spaceHeater)
|
||||||
|
|| !TryComp<GasThermoMachineComponent>(uid, out var thermoMachine)
|
||||||
|
|| !TryComp<ApcPowerReceiverComponent>(uid, out var powerReceiver))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_userInterfaceSystem.TrySetUiState(uid, SpaceHeaterUiKey.Key,
|
||||||
|
new SpaceHeaterBoundUserInterfaceState(spaceHeater.MinTemperature, spaceHeater.MaxTemperature, thermoMachine.TargetTemperature, !powerReceiver.PowerDisabled, spaceHeater.Mode, spaceHeater.PowerLevel));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAppearance(EntityUid uid)
|
||||||
|
{
|
||||||
|
if (!_power.IsPowered(uid) || !TryComp<GasThermoMachineComponent>(uid, out var thermoMachine))
|
||||||
|
{
|
||||||
|
_appearance.SetData(uid, SpaceHeaterVisuals.State, SpaceHeaterState.Off);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thermoMachine.LastEnergyDelta > 0)
|
||||||
|
{
|
||||||
|
_appearance.SetData(uid, SpaceHeaterVisuals.State, SpaceHeaterState.Heating);
|
||||||
|
}
|
||||||
|
else if (thermoMachine.LastEnergyDelta < 0)
|
||||||
|
{
|
||||||
|
_appearance.SetData(uid, SpaceHeaterVisuals.State, SpaceHeaterState.Cooling);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_appearance.SetData(uid, SpaceHeaterVisuals.State, SpaceHeaterState.StandBy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Atmos.Piping.Portable.Components;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[NetSerializable]
|
||||||
|
public enum SpaceHeaterUiKey
|
||||||
|
{
|
||||||
|
Key
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[NetSerializable]
|
||||||
|
public sealed class SpaceHeaterToggleMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[NetSerializable]
|
||||||
|
public sealed class SpaceHeaterChangeTemperatureMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public float Temperature { get; }
|
||||||
|
|
||||||
|
public SpaceHeaterChangeTemperatureMessage(float temperature)
|
||||||
|
{
|
||||||
|
Temperature = temperature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[NetSerializable]
|
||||||
|
public sealed class SpaceHeaterChangePowerLevelMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public SpaceHeaterPowerLevel PowerLevel { get; }
|
||||||
|
|
||||||
|
public SpaceHeaterChangePowerLevelMessage(SpaceHeaterPowerLevel powerLevel)
|
||||||
|
{
|
||||||
|
PowerLevel = powerLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[NetSerializable]
|
||||||
|
public sealed class SpaceHeaterChangeModeMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public SpaceHeaterMode Mode { get; }
|
||||||
|
|
||||||
|
public SpaceHeaterChangeModeMessage(SpaceHeaterMode mode)
|
||||||
|
{
|
||||||
|
Mode = mode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[NetSerializable]
|
||||||
|
public sealed class SpaceHeaterBoundUserInterfaceState : BoundUserInterfaceState
|
||||||
|
{
|
||||||
|
public float MinTemperature { get; }
|
||||||
|
public float MaxTemperature { get; }
|
||||||
|
public float TargetTemperature { get; }
|
||||||
|
public bool Enabled { get; }
|
||||||
|
public SpaceHeaterMode Mode { get; }
|
||||||
|
public SpaceHeaterPowerLevel PowerLevel { get; }
|
||||||
|
|
||||||
|
public SpaceHeaterBoundUserInterfaceState(float minTemperature, float maxTemperature, float temperature, bool enabled, SpaceHeaterMode mode, SpaceHeaterPowerLevel powerLevel)
|
||||||
|
{
|
||||||
|
MinTemperature = minTemperature;
|
||||||
|
MaxTemperature = maxTemperature;
|
||||||
|
TargetTemperature = temperature;
|
||||||
|
Enabled = enabled;
|
||||||
|
Mode = mode;
|
||||||
|
PowerLevel = powerLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum SpaceHeaterMode : byte
|
||||||
|
{
|
||||||
|
Auto,
|
||||||
|
Heat,
|
||||||
|
Cool
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum SpaceHeaterPowerLevel : byte
|
||||||
|
{
|
||||||
|
Low,
|
||||||
|
Medium,
|
||||||
|
High
|
||||||
|
}
|
||||||
27
Content.Shared/Atmos/Visuals/SpaceHeaterVisuals.cs
Normal file
27
Content.Shared/Atmos/Visuals/SpaceHeaterVisuals.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Atmos.Visuals;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used for the visualizer
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum SpaceHeaterVisualLayers : byte
|
||||||
|
{
|
||||||
|
Main
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum SpaceHeaterVisuals : byte
|
||||||
|
{
|
||||||
|
State,
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum SpaceHeaterState : byte
|
||||||
|
{
|
||||||
|
Off,
|
||||||
|
StandBy,
|
||||||
|
Heating,
|
||||||
|
Cooling,
|
||||||
|
}
|
||||||
18
Resources/Locale/en-US/components/space-heater-component.ftl
Normal file
18
Resources/Locale/en-US/components/space-heater-component.ftl
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
comp-space-heater-ui-thermostat = Thermostat:
|
||||||
|
comp-space-heater-ui-mode = Mode
|
||||||
|
comp-space-heater-ui-status-disabled = Off
|
||||||
|
comp-space-heater-ui-status-enabled = On
|
||||||
|
comp-space-heater-ui-increase-temperature-range = +
|
||||||
|
comp-space-heater-ui-decrease-temperature-range = -
|
||||||
|
|
||||||
|
comp-space-heater-mode-Auto = Auto
|
||||||
|
comp-space-heater-mode-Heat = Heat
|
||||||
|
comp-space-heater-mode-Cool = Cool
|
||||||
|
|
||||||
|
comp-space-heater-ui-power-consumption = Power level:
|
||||||
|
comp-space-heater-ui-Low-power-consumption = Low
|
||||||
|
comp-space-heater-ui-Medium-power-consumption = Medium
|
||||||
|
comp-space-heater-ui-High-power-consumption = High
|
||||||
|
|
||||||
|
comp-space-heater-device-name = space heater
|
||||||
|
comp-space-heater-unanchored = The {$device} is not anchored.
|
||||||
@@ -38,6 +38,7 @@ wires-board-name-windoor = Windoor Control
|
|||||||
wires-board-name-mech = Mech
|
wires-board-name-mech = Mech
|
||||||
wires-board-name-fatextractor = FatExtractor
|
wires-board-name-fatextractor = FatExtractor
|
||||||
wires-board-name-flatpacker = Flatpacker
|
wires-board-name-flatpacker = Flatpacker
|
||||||
|
wires-board-name-spaceheater = Space Heater
|
||||||
|
|
||||||
# names that get displayed in the wire hacking hud & admin logs.
|
# names that get displayed in the wire hacking hud & admin logs.
|
||||||
|
|
||||||
|
|||||||
@@ -451,7 +451,7 @@
|
|||||||
id: PortableScrubberMachineCircuitBoard
|
id: PortableScrubberMachineCircuitBoard
|
||||||
parent: BaseMachineCircuitboard
|
parent: BaseMachineCircuitboard
|
||||||
name: portable scrubber machine board
|
name: portable scrubber machine board
|
||||||
description: A PCB for a portable scrubber.
|
description: A machine printed circuit board for a portable scrubber.
|
||||||
components:
|
components:
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
state: engineering
|
state: engineering
|
||||||
@@ -464,6 +464,22 @@
|
|||||||
Cable: 5
|
Cable: 5
|
||||||
Glass: 2
|
Glass: 2
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: SpaceHeaterMachineCircuitBoard
|
||||||
|
parent: BaseMachineCircuitboard
|
||||||
|
name: space heater machine board
|
||||||
|
description: A machine printed circuit board for a space heater.
|
||||||
|
components:
|
||||||
|
- type: Sprite
|
||||||
|
state: engineering
|
||||||
|
- type: MachineBoard
|
||||||
|
prototype: SpaceHeater
|
||||||
|
requirements:
|
||||||
|
MatterBin: 1
|
||||||
|
Capacitor: 2
|
||||||
|
materialRequirements:
|
||||||
|
Cable: 5
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: CloningPodMachineCircuitboard
|
id: CloningPodMachineCircuitboard
|
||||||
parent: BaseMachineCircuitboard
|
parent: BaseMachineCircuitboard
|
||||||
|
|||||||
@@ -390,6 +390,7 @@
|
|||||||
- ThermomachineFreezerMachineCircuitBoard
|
- ThermomachineFreezerMachineCircuitBoard
|
||||||
- HellfireFreezerMachineCircuitBoard
|
- HellfireFreezerMachineCircuitBoard
|
||||||
- PortableScrubberMachineCircuitBoard
|
- PortableScrubberMachineCircuitBoard
|
||||||
|
- SpaceHeaterMachineCircuitBoard
|
||||||
- CloningPodMachineCircuitboard
|
- CloningPodMachineCircuitboard
|
||||||
- MedicalScannerMachineCircuitboard
|
- MedicalScannerMachineCircuitboard
|
||||||
- CryoPodMachineCircuitboard
|
- CryoPodMachineCircuitboard
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
id: PortableScrubber
|
id: PortableScrubber
|
||||||
parent: BaseStructureDynamic
|
parent: [BaseMachinePowered, ConstructibleMachine]
|
||||||
name: portable scrubber
|
name: portable scrubber
|
||||||
description: It scrubs, portably!
|
description: It scrubs, portably!
|
||||||
components:
|
components:
|
||||||
- type: Transform
|
- type: Transform
|
||||||
noRot: true
|
anchored: false
|
||||||
- type: InteractionOutline
|
|
||||||
- type: Physics
|
- type: Physics
|
||||||
bodyType: Dynamic
|
bodyType: Dynamic
|
||||||
canCollide: false
|
- type: AtmosDevice
|
||||||
|
joinSystem: true
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
fix1:
|
fix1:
|
||||||
@@ -34,9 +34,6 @@
|
|||||||
shader: unshaded
|
shader: unshaded
|
||||||
visible: false
|
visible: false
|
||||||
map: ["enum.PortableScrubberVisualLayers.IsDraining"]
|
map: ["enum.PortableScrubberVisualLayers.IsDraining"]
|
||||||
- type: Pullable
|
|
||||||
- type: AtmosDevice
|
|
||||||
joinSystem: true
|
|
||||||
- type: PortableScrubber
|
- type: PortableScrubber
|
||||||
gasMixture:
|
gasMixture:
|
||||||
volume: 1250
|
volume: 1250
|
||||||
@@ -49,7 +46,6 @@
|
|||||||
volume: 1
|
volume: 1
|
||||||
- type: ApcPowerReceiver
|
- type: ApcPowerReceiver
|
||||||
powerLoad: 2000
|
powerLoad: 2000
|
||||||
- type: ExtensionCableReceiver
|
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
- type: GenericVisualizer
|
- type: GenericVisualizer
|
||||||
visuals:
|
visuals:
|
||||||
@@ -94,13 +90,109 @@
|
|||||||
min: 1
|
min: 1
|
||||||
max: 3
|
max: 3
|
||||||
SheetGlass1:
|
SheetGlass1:
|
||||||
|
min: 1
|
||||||
|
max: 2
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: [ "Destruction" ]
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: SpaceHeater
|
||||||
|
parent: [BaseMachinePowered, ConstructibleMachine]
|
||||||
|
name: space heater
|
||||||
|
description: A bluespace technology device that alters local temperature. Commonly referred to as a "Space Heater".
|
||||||
|
suffix: Unanchored
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
anchored: false
|
||||||
|
- type: Physics
|
||||||
|
bodyType: Dynamic
|
||||||
|
- type: AtmosDevice
|
||||||
|
joinSystem: true
|
||||||
|
- type: Fixtures
|
||||||
|
fixtures:
|
||||||
|
fix1:
|
||||||
|
shape:
|
||||||
|
!type:PhysShapeAabb
|
||||||
|
bounds: "-0.15,-0.35,0.15,0.5"
|
||||||
|
density: 100
|
||||||
|
mask:
|
||||||
|
- MachineMask
|
||||||
|
layer:
|
||||||
|
- MachineLayer
|
||||||
|
- type: ApcPowerReceiver
|
||||||
|
powerDisabled: true #starts off
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Structures/Piping/Atmospherics/Portable/portable_sheater.rsi
|
||||||
|
noRot: true
|
||||||
|
layers:
|
||||||
|
- state: sheaterOff
|
||||||
|
map: ["enum.SpaceHeaterVisualLayers.Main"]
|
||||||
|
- state: sheaterPanelOpen
|
||||||
|
map: [ "enum.WiresVisualLayers.MaintenancePanel" ]
|
||||||
|
- type: Appearance
|
||||||
|
- type: GenericVisualizer
|
||||||
|
visuals:
|
||||||
|
enum.SpaceHeaterVisuals.State:
|
||||||
|
SpaceHeaterVisualLayers.Main:
|
||||||
|
Off: { state: sheaterOff }
|
||||||
|
StandBy: { state: sheaterStandby }
|
||||||
|
Heating: { state: sheaterHeat }
|
||||||
|
Cooling: { state: sheaterCool }
|
||||||
|
- type: Machine
|
||||||
|
board: SpaceHeaterMachineCircuitBoard
|
||||||
|
- type: WiresPanel
|
||||||
|
- type: WiresVisuals
|
||||||
|
- type: UserInterface
|
||||||
|
interfaces:
|
||||||
|
- key: enum.SpaceHeaterUiKey.Key
|
||||||
|
type: SpaceHeaterBoundUserInterface
|
||||||
|
- type: ActivatableUI
|
||||||
|
inHandsOnly: false
|
||||||
|
key: enum.SpaceHeaterUiKey.Key
|
||||||
|
- type: SpaceHeater
|
||||||
|
- type: GasThermoMachine
|
||||||
|
temperatureTolerance: 0.2
|
||||||
|
atmospheric: true
|
||||||
|
- type: Damageable
|
||||||
|
damageContainer: Inorganic
|
||||||
|
damageModifierSet: Metallic
|
||||||
|
- type: Destructible
|
||||||
|
thresholds:
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 600
|
||||||
|
behaviors:
|
||||||
|
- !type:DoActsBehavior
|
||||||
|
acts: [ "Destruction" ]
|
||||||
|
- trigger:
|
||||||
|
!type:DamageTrigger
|
||||||
|
damage: 300
|
||||||
|
behaviors:
|
||||||
|
- !type:PlaySoundBehavior
|
||||||
|
sound:
|
||||||
|
collection: MetalBreak
|
||||||
|
- !type:SpawnEntitiesBehavior
|
||||||
|
spawn:
|
||||||
|
SheetSteel1:
|
||||||
min: 1
|
min: 1
|
||||||
max: 3
|
max: 3
|
||||||
- !type:DoActsBehavior
|
- !type:DoActsBehavior
|
||||||
acts: [ "Destruction" ]
|
acts: [ "Destruction" ]
|
||||||
- type: CollideOnAnchor
|
|
||||||
enable: true
|
- type: entity
|
||||||
- type: ContainerContainer
|
parent: SpaceHeater
|
||||||
containers:
|
id: SpaceHeaterAnchored
|
||||||
machine_board: !type:Container
|
suffix: Anchored
|
||||||
machine_parts: !type:Container
|
components:
|
||||||
|
- type: Transform
|
||||||
|
anchored: true
|
||||||
|
- type: Physics
|
||||||
|
bodyType: Static
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: SpaceHeaterAnchored
|
||||||
|
id: SpaceHeaterEnabled
|
||||||
|
suffix: Anchored, Enabled
|
||||||
|
components:
|
||||||
|
- type: ApcPowerReceiver
|
||||||
|
powerDisabled: false
|
||||||
@@ -156,6 +156,16 @@
|
|||||||
Glass: 900
|
Glass: 900
|
||||||
Gold: 50
|
Gold: 50
|
||||||
|
|
||||||
|
- type: latheRecipe
|
||||||
|
id: SpaceHeaterMachineCircuitBoard
|
||||||
|
result: SpaceHeaterMachineCircuitBoard
|
||||||
|
category: Circuitry
|
||||||
|
completetime: 4
|
||||||
|
materials:
|
||||||
|
Steel: 150
|
||||||
|
Glass: 900
|
||||||
|
Gold: 50
|
||||||
|
|
||||||
- type: latheRecipe
|
- type: latheRecipe
|
||||||
id: MedicalScannerMachineCircuitboard
|
id: MedicalScannerMachineCircuitboard
|
||||||
result: MedicalScannerMachineCircuitboard
|
result: MedicalScannerMachineCircuitboard
|
||||||
|
|||||||
@@ -160,6 +160,7 @@
|
|||||||
recipeUnlocks:
|
recipeUnlocks:
|
||||||
- HellfireFreezerMachineCircuitBoard
|
- HellfireFreezerMachineCircuitBoard
|
||||||
- PortableScrubberMachineCircuitBoard
|
- PortableScrubberMachineCircuitBoard
|
||||||
|
- SpaceHeaterMachineCircuitBoard
|
||||||
- HolofanProjector
|
- HolofanProjector
|
||||||
|
|
||||||
- type: technology
|
- type: technology
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/ead7e05f990de05b7f5f93d39f9671498cb0aa01",
|
||||||
|
"size": {
|
||||||
|
"x": 32,
|
||||||
|
"y": 32
|
||||||
|
},
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "sheaterOff"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sheaterCool",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sheaterHeat",
|
||||||
|
"delays": [
|
||||||
|
[
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2,
|
||||||
|
0.2
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sheaterPanelOpen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sheaterStandby"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 994 B |
Binary file not shown.
|
After Width: | Height: | Size: 911 B |
Binary file not shown.
|
After Width: | Height: | Size: 5.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 187 B |
Binary file not shown.
|
After Width: | Height: | Size: 338 B |
Reference in New Issue
Block a user