space_engineers/AirMonitor/AirZone.cs

130 lines
4.5 KiB
C#

using Sandbox.ModAPI.Ingame;
using SpaceEngineers.Game.ModAPI.Ingame;
using System.Collections.Generic;
using VRageMath;
namespace IngameScript
{
partial class Program
{
public class AirZone
{
public string Name { get; private set; }
public bool Triggered
{
get
{
foreach (IMyAirVent vent in Vents)
{
if (vent.GetOxygenLevel() < TriggerLevel || vent.Status == VentStatus.Depressurized) return true;
}
return false;
}
}
public float OxygenLevel
{
get
{
float ret = 100F;
foreach (IMyAirVent vent in Vents)
{
if (vent.GetOxygenLevel() < ret) ret = vent.GetOxygenLevel();
}
return ret;
}
}
public List<IMyAirVent> Vents { get; } = new List<IMyAirVent>();
private IConsoleProgram _program;
// private List<IMyTextSurface> _displays = new List<IMyTextSurface>(); // TODO: add single-zone displays
private List<IMyLightingBlock> _lights = new List<IMyLightingBlock>();
private List<AirDoor> _doors = new List<AirDoor>();
private PrefixedConsole _console;
private Sequencer _sequencer;
private const float TriggerLevel = 0.75F;
public AirZone(IConsoleProgram program, string zoneName)
{
Name = zoneName;
_program = program;
_console = new PrefixedConsole(_program.Console, Name);
_sequencer = new Sequencer(_program, Name);
}
public void AddDoor(AirDoor door)
{
_doors.Add(door);
IMyDoor doorBlock = door.Door;
SequenceableDoor wrapped = SequenceableFactory.MakeSequenceable(
_program,
doorBlock as IMyDoor,
"airMonitor") as SequenceableDoor;
wrapped.Step = 0;
wrapped.DeployOpen = false;
wrapped.LockOpen = false;
wrapped.LockClosed = true;
_sequencer.AddBlock(wrapped);
}
public void AddBlock(IMyTerminalBlock block)
{
if (block is IMyAirVent)
{
Vents.Add(block as IMyAirVent);
}
else if (block is IMyLightingBlock)
{
_lights.Add(block as IMyLightingBlock);
}
else
{
_console.Print("Tried to add incompatible block '{block.CustomName}'");
}
// TODO: support for arbitrary (sub-)sequences here could be powerful
}
// This enumerator should run forever.
public IEnumerator<bool> Monitor()
{
while (true)
{
if (Triggered == true)
{
_console.Print($"Low pressure alarm triggered.");
// close the doors
IEnumerator<bool> job = _sequencer.RunSequence(true);
while (job.MoveNext())
{
// It would be nice if the API had UpdateFrequency.Once10, e.g. "re-run in 10 ticks and then clear the flag"
// We'll just monitor every tick instead.
setTriggeredStates();
_program.Runtime.UpdateFrequency |= UpdateFrequency.Once;
yield return true;
}
job.Dispose();
while (Triggered)
{
setTriggeredStates();
yield return true;
}
_console.Print("Air pressure returned to safe levels.");
}
yield return true;
}
}
private void setTriggeredStates()
{
foreach (IMyLightingBlock light in _lights) light.Color = Color.Red;
foreach (AirDoor door in _doors) door.Triggered = true;
}
}
}
}