Adds fire/air alarms (#5018)
Co-authored-by: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com> Co-authored-by: E F R <602406+Efruit@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
257
Content.Shared/Atmos/Monitor/AtmosAlarmThresholdPrototype.cs
Normal file
257
Content.Shared/Atmos/Monitor/AtmosAlarmThresholdPrototype.cs
Normal file
@@ -0,0 +1,257 @@
|
||||
using System;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Shared.Atmos.Monitor
|
||||
{
|
||||
// mostly based around floats and percentages, no literals
|
||||
// except for the range boundaries
|
||||
[Prototype("alarmThreshold")]
|
||||
[Serializable, NetSerializable]
|
||||
public class AtmosAlarmThreshold : IPrototype, ISerializationHooks
|
||||
{
|
||||
[DataField("id", required: true)]
|
||||
public string ID { get; } = default!;
|
||||
[ViewVariables]
|
||||
[DataField("ignore")]
|
||||
public bool Ignore = false;
|
||||
|
||||
// zero bounds are not allowed - just
|
||||
// set the bound to null if you want
|
||||
// to disable it
|
||||
[ViewVariables]
|
||||
[DataField("upperBound")]
|
||||
public float? UpperBound { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("lowerBound")]
|
||||
public float? LowerBound { get; private set; }
|
||||
|
||||
// upper warning percentage
|
||||
// must always cause UpperWarningBound
|
||||
// to be smaller
|
||||
[ViewVariables]
|
||||
[DataField("upperWarnAround")]
|
||||
public float? UpperWarningPercentage { get; private set; }
|
||||
|
||||
// lower warning percentage
|
||||
// must always cause LowerWarningBound
|
||||
// to be larger
|
||||
[ViewVariables]
|
||||
[DataField("lowerWarnAround")]
|
||||
public float? LowerWarningPercentage { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public float? UpperWarningBound
|
||||
{
|
||||
get => CalculateWarningBound(AtmosMonitorThresholdBound.Upper);
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
public float? LowerWarningBound
|
||||
{
|
||||
get => CalculateWarningBound(AtmosMonitorThresholdBound.Lower);
|
||||
}
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
if (UpperBound <= LowerBound)
|
||||
UpperBound = null;
|
||||
|
||||
if (LowerBound >= UpperBound)
|
||||
LowerBound = null;
|
||||
|
||||
if (UpperWarningPercentage != null)
|
||||
TrySetWarningBound(AtmosMonitorThresholdBound.Upper, UpperBound * UpperWarningPercentage);
|
||||
|
||||
if (LowerWarningPercentage != null)
|
||||
TrySetWarningBound(AtmosMonitorThresholdBound.Lower, LowerBound * LowerWarningPercentage);
|
||||
}
|
||||
|
||||
// utility function to check a threshold against some calculated value
|
||||
public bool CheckThreshold(float value, out AtmosMonitorAlarmType state)
|
||||
{
|
||||
state = AtmosMonitorAlarmType.Normal;
|
||||
if (Ignore) return false;
|
||||
|
||||
if (value >= UpperBound || value <= LowerBound)
|
||||
{
|
||||
state = AtmosMonitorAlarmType.Danger;
|
||||
return true;
|
||||
}
|
||||
if (value >= UpperWarningBound || value <= LowerWarningBound)
|
||||
{
|
||||
state = AtmosMonitorAlarmType.Warning;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the primary bound, takes a hard value
|
||||
public bool TrySetPrimaryBound(AtmosMonitorThresholdBound bound, float? input)
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
switch (bound)
|
||||
{
|
||||
case AtmosMonitorThresholdBound.Upper:
|
||||
UpperBound = null;
|
||||
break;
|
||||
case AtmosMonitorThresholdBound.Lower:
|
||||
LowerBound = null;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float value = (float) input;
|
||||
|
||||
if (value <= 0f || float.IsNaN(value))
|
||||
return false;
|
||||
|
||||
(float target, int compare)? targetValue = null;
|
||||
switch (bound)
|
||||
{
|
||||
case AtmosMonitorThresholdBound.Upper:
|
||||
if (float.IsPositiveInfinity(value))
|
||||
return false;
|
||||
|
||||
if (LowerBound != null)
|
||||
targetValue = ((float) LowerBound, -1);
|
||||
break;
|
||||
case AtmosMonitorThresholdBound.Lower:
|
||||
if (float.IsNegativeInfinity(value))
|
||||
return false;
|
||||
|
||||
if (UpperBound != null)
|
||||
targetValue = ((float) UpperBound, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
bool isValid = true;
|
||||
if (targetValue != null)
|
||||
{
|
||||
var result = targetValue.Value.target.CompareTo(value);
|
||||
isValid = targetValue.Value.compare == result;
|
||||
}
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
switch (bound)
|
||||
{
|
||||
case AtmosMonitorThresholdBound.Upper:
|
||||
UpperBound = value;
|
||||
return true;
|
||||
case AtmosMonitorThresholdBound.Lower:
|
||||
LowerBound = value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the warning bound, takes a hard value
|
||||
//
|
||||
// this will always set the percentage and
|
||||
// the raw value at the same time
|
||||
public bool TrySetWarningBound(AtmosMonitorThresholdBound bound, float? input)
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
switch (bound)
|
||||
{
|
||||
case AtmosMonitorThresholdBound.Upper:
|
||||
UpperWarningPercentage = null;
|
||||
break;
|
||||
case AtmosMonitorThresholdBound.Lower:
|
||||
LowerWarningPercentage = null;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (bound)
|
||||
{
|
||||
case AtmosMonitorThresholdBound.Upper:
|
||||
if (UpperBound == null)
|
||||
return false;
|
||||
|
||||
float upperWarning = (float) (input / UpperBound);
|
||||
float upperTestValue = (upperWarning * (float) UpperBound);
|
||||
|
||||
if (upperWarning > 1f
|
||||
|| upperTestValue < LowerWarningBound
|
||||
|| upperTestValue < LowerBound)
|
||||
return false;
|
||||
|
||||
UpperWarningPercentage = upperWarning;
|
||||
|
||||
return true;
|
||||
case AtmosMonitorThresholdBound.Lower:
|
||||
if (LowerBound == null)
|
||||
return false;
|
||||
|
||||
float lowerWarning = (float) (input / LowerBound);
|
||||
float testValue = (lowerWarning * (float) LowerBound);
|
||||
|
||||
if (lowerWarning < 1f
|
||||
|| testValue > UpperWarningBound
|
||||
|| testValue > UpperBound)
|
||||
return false;
|
||||
|
||||
LowerWarningPercentage = lowerWarning;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public float? CalculateWarningBound(AtmosMonitorThresholdBound bound)
|
||||
{
|
||||
float? value = null;
|
||||
|
||||
switch (bound)
|
||||
{
|
||||
case AtmosMonitorThresholdBound.Upper:
|
||||
if (UpperBound == null || UpperWarningPercentage == null)
|
||||
break;
|
||||
|
||||
value = UpperBound * UpperWarningPercentage;
|
||||
break;
|
||||
case AtmosMonitorThresholdBound.Lower:
|
||||
if (LowerBound == null || LowerWarningPercentage == null)
|
||||
break;
|
||||
|
||||
value = LowerBound * LowerWarningPercentage;
|
||||
break;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public enum AtmosMonitorThresholdBound
|
||||
{
|
||||
Upper,
|
||||
Lower
|
||||
}
|
||||
|
||||
// not really used in the prototype but in code,
|
||||
// to differentiate between the different
|
||||
// fields you can find this prototype in
|
||||
public enum AtmosMonitorThresholdType
|
||||
{
|
||||
Temperature,
|
||||
Pressure,
|
||||
Gas
|
||||
}
|
||||
}
|
||||
13
Content.Shared/Atmos/Monitor/AtmosMonitorAlarmType.cs
Normal file
13
Content.Shared/Atmos/Monitor/AtmosMonitorAlarmType.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Atmos.Monitor
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public enum AtmosMonitorAlarmType : sbyte
|
||||
{
|
||||
Normal = 0,
|
||||
Warning = 1,
|
||||
Danger = 2 // 1 << 1 is the exact same thing and we're not really doing **bitmasking** are we?
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Atmos.Monitor;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Atmos.Monitor.Components
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public enum SharedAirAlarmInterfaceKey
|
||||
{
|
||||
Key
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum AirAlarmMode
|
||||
{
|
||||
None,
|
||||
Filtering,
|
||||
Fill,
|
||||
Panic,
|
||||
Replace
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum AirAlarmWireStatus
|
||||
{
|
||||
Power,
|
||||
Access,
|
||||
Panic,
|
||||
DeviceSync
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public readonly struct AirAlarmAirData
|
||||
{
|
||||
public readonly float? Pressure { get; }
|
||||
public readonly float? Temperature { get; }
|
||||
public readonly float? TotalMoles { get; }
|
||||
public readonly AtmosMonitorAlarmType AlarmState { get; }
|
||||
|
||||
private readonly Dictionary<Gas, float>? _gases;
|
||||
public readonly IReadOnlyDictionary<Gas, float>? Gases { get => _gases; }
|
||||
|
||||
public AirAlarmAirData(float? pressure, float? temperature, float? moles, AtmosMonitorAlarmType state, Dictionary<Gas, float>? gases)
|
||||
{
|
||||
Pressure = pressure;
|
||||
Temperature = temperature;
|
||||
TotalMoles = moles;
|
||||
AlarmState = state;
|
||||
_gases = gases;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAtmosDeviceData
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public bool Dirty { get; set; }
|
||||
public bool IgnoreAlarms { get; set; }
|
||||
}
|
||||
|
||||
// would be nice to include the entire state here
|
||||
// but it's already handled by messages
|
||||
[Serializable, NetSerializable]
|
||||
public class AirAlarmUIState : BoundUserInterfaceState
|
||||
{}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class AirAlarmResyncAllDevicesMessage : BoundUserInterfaceMessage
|
||||
{}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class AirAlarmSetAddressMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public string Address { get; }
|
||||
|
||||
public AirAlarmSetAddressMessage(string address)
|
||||
{
|
||||
Address = address;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class AirAlarmUpdateAirDataMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public AirAlarmAirData AirData;
|
||||
|
||||
public AirAlarmUpdateAirDataMessage(AirAlarmAirData airData)
|
||||
{
|
||||
AirData = airData;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class AirAlarmUpdateAlarmModeMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public AirAlarmMode Mode { get; }
|
||||
|
||||
public AirAlarmUpdateAlarmModeMessage(AirAlarmMode mode)
|
||||
{
|
||||
Mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class AirAlarmUpdateDeviceDataMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public string Address { get; }
|
||||
public IAtmosDeviceData Data { get; }
|
||||
|
||||
public AirAlarmUpdateDeviceDataMessage(string addr, IAtmosDeviceData data)
|
||||
{
|
||||
Address = addr;
|
||||
Data = data;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class AirAlarmUpdateAlarmThresholdMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public AtmosAlarmThreshold Threshold { get; }
|
||||
public AtmosMonitorThresholdType Type { get; }
|
||||
public Gas? Gas { get; }
|
||||
|
||||
public AirAlarmUpdateAlarmThresholdMessage(AtmosMonitorThresholdType type, AtmosAlarmThreshold threshold, Gas? gas = null)
|
||||
{
|
||||
Threshold = threshold;
|
||||
Type = type;
|
||||
Gas = gas;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Atmos.Monitor.Components
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public enum FireAlarmWireStatus
|
||||
{
|
||||
Power,
|
||||
Alarm
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Atmos.Piping.Unary.Components
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public class GasVentPumpData : IAtmosDeviceData
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public bool Dirty { get; set; }
|
||||
public bool IgnoreAlarms { get; set; } = false;
|
||||
public VentPumpDirection? PumpDirection { get; set; }
|
||||
public VentPressureBound? PressureChecks { get; set; }
|
||||
public float? ExternalPressureBound { get; set; }
|
||||
public float? InternalPressureBound { get; set; }
|
||||
|
||||
// Presets for 'dumb' air alarm modes
|
||||
|
||||
public static GasVentPumpData FilterModePreset = new GasVentPumpData
|
||||
{
|
||||
Enabled = true,
|
||||
PumpDirection = VentPumpDirection.Releasing,
|
||||
PressureChecks = VentPressureBound.ExternalBound,
|
||||
ExternalPressureBound = Atmospherics.OneAtmosphere,
|
||||
InternalPressureBound = 0f
|
||||
};
|
||||
|
||||
public static GasVentPumpData FillModePreset = new GasVentPumpData
|
||||
{
|
||||
Enabled = true,
|
||||
Dirty = true,
|
||||
PumpDirection = VentPumpDirection.Releasing,
|
||||
PressureChecks = VentPressureBound.ExternalBound,
|
||||
ExternalPressureBound = Atmospherics.OneAtmosphere * 50,
|
||||
InternalPressureBound = 0f
|
||||
};
|
||||
|
||||
public static GasVentPumpData PanicModePreset = new GasVentPumpData
|
||||
{
|
||||
Enabled = false,
|
||||
Dirty = true,
|
||||
PumpDirection = VentPumpDirection.Releasing,
|
||||
PressureChecks = VentPressureBound.ExternalBound,
|
||||
ExternalPressureBound = Atmospherics.OneAtmosphere,
|
||||
InternalPressureBound = 0f
|
||||
};
|
||||
|
||||
public static GasVentPumpData Default()
|
||||
{
|
||||
return new GasVentPumpData
|
||||
{
|
||||
Enabled = true,
|
||||
PumpDirection = VentPumpDirection.Releasing,
|
||||
PressureChecks = VentPressureBound.ExternalBound,
|
||||
ExternalPressureBound = Atmospherics.OneAtmosphere,
|
||||
InternalPressureBound = 0f
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum VentPumpDirection : sbyte
|
||||
{
|
||||
Siphoning = 0,
|
||||
Releasing = 1,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[Serializable, NetSerializable]
|
||||
public enum VentPressureBound : sbyte
|
||||
{
|
||||
NoBound = 0,
|
||||
InternalBound = 1,
|
||||
ExternalBound = 2,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Atmos.Monitor.Components;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Atmos.Piping.Unary.Components
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public class GasVentScrubberData : IAtmosDeviceData
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public bool Dirty { get; set; }
|
||||
public bool IgnoreAlarms { get; set; } = false;
|
||||
public HashSet<Gas>? FilterGases { get; set; }
|
||||
public ScrubberPumpDirection? PumpDirection { get; set; }
|
||||
public float? VolumeRate { get; set; }
|
||||
public bool WideNet { get; set; }
|
||||
|
||||
public static HashSet<Gas> DefaultFilterGases = new()
|
||||
{
|
||||
Gas.CarbonDioxide,
|
||||
Gas.Plasma,
|
||||
Gas.Tritium,
|
||||
Gas.WaterVapor,
|
||||
};
|
||||
|
||||
// Presets for 'dumb' air alarm modes
|
||||
|
||||
public static GasVentScrubberData FilterModePreset = new GasVentScrubberData
|
||||
{
|
||||
Enabled = true,
|
||||
FilterGases = GasVentScrubberData.DefaultFilterGases,
|
||||
PumpDirection = ScrubberPumpDirection.Scrubbing,
|
||||
VolumeRate = 200f,
|
||||
WideNet = false
|
||||
};
|
||||
|
||||
public static GasVentScrubberData FillModePreset = new GasVentScrubberData
|
||||
{
|
||||
Enabled = false,
|
||||
Dirty = true,
|
||||
FilterGases = GasVentScrubberData.DefaultFilterGases,
|
||||
PumpDirection = ScrubberPumpDirection.Scrubbing,
|
||||
VolumeRate = 200f,
|
||||
WideNet = false
|
||||
};
|
||||
|
||||
public static GasVentScrubberData PanicModePreset = new GasVentScrubberData
|
||||
{
|
||||
Enabled = true,
|
||||
Dirty = true,
|
||||
FilterGases = GasVentScrubberData.DefaultFilterGases,
|
||||
PumpDirection = ScrubberPumpDirection.Siphoning,
|
||||
VolumeRate = 200f,
|
||||
WideNet = false
|
||||
};
|
||||
|
||||
public static GasVentScrubberData Default()
|
||||
{
|
||||
return new GasVentScrubberData
|
||||
{
|
||||
Enabled = true,
|
||||
FilterGases = GasVentScrubberData.DefaultFilterGases,
|
||||
PumpDirection = ScrubberPumpDirection.Scrubbing,
|
||||
VolumeRate = 200f,
|
||||
WideNet = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum ScrubberPumpDirection : sbyte
|
||||
{
|
||||
Siphoning = 0,
|
||||
Scrubbing = 1,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user