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:
Flipp Syder
2022-01-01 20:56:24 -08:00
committed by GitHub
parent 903f796b0f
commit b1584793bf
71 changed files with 4340 additions and 29 deletions

View 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
}
}

View 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?
}
}

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
using Robust.Shared.Serialization;
namespace Content.Shared.Atmos.Monitor.Components
{
[Serializable, NetSerializable]
public enum FireAlarmWireStatus
{
Power,
Alarm
}
}

View File

@@ -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,
}
}

View File

@@ -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,
}
}