using Sandbox.ModAPI.Ingame; using SpaceEngineers.Game.ModAPI.Ingame; using System.Collections.Generic; using VRageMath; namespace IngameScript { partial class Program { public class Airlock { enum AirlockLightState { Off, Cycling, Cooldown, Error, } public bool DoorsClosed { get { return innerDoor.Status == DoorStatus.Closed && outerDoor.Status == DoorStatus.Closed; } } // TODO: this should check for depressurizing to the *reference* amount public bool PressureStabilized { get { return ((airVent.Depressurize && airVent.GetOxygenLevel() <= targetOxygenLevel) || (!airVent.Depressurize && airVent.Status == VentStatus.Pressurized)); } } public bool OxygenBalanced { get { return oxygenTank.FilledRatio > 0.25; } } public bool Functional { get { return (innerDoor != null && outerDoor != null && airVent != null && oxygenTank != null); } } public bool Cycling { get; private set; } = false; private bool DoorOpened { get { return innerDoor.Status == DoorStatus.Open || outerDoor.Status == DoorStatus.Open; } } // Returns false if we are in a state where we can't or don't need to balance private bool balanceOxygen() { if (innerDoor.Status == DoorStatus.Closed || outerDoor.Status == DoorStatus.Open || OxygenBalanced) { return false; } _console.Print($"{_name}: Balancing Oxygen Tank"); // Configure the vent to suck in Oxygen. airVent.Depressurize = true; airVent.Enabled = true; return true; } private string _name; private PrefixedConsole _console; private MyGridProgram _p; private float targetOxygenLevel = 0.0F; private IMyDoor innerDoor; private IMyDoor outerDoor; private List lights; private IMyGasTank oxygenTank; private IMyAirVent airVent; private IMyAirVent airSensor; private const int CooldownTicks = 120; public Airlock(MyGridProgram program, Console console, string name) { _p = program; _name = name; _console = console.CreatePrefixedConsole(_name); lights = new List(); // Find the appropriate blocks given the airlock name // initDoors(); // initLights(); // initVents(); // initOxygen(); } public void AddBlock(IMyTerminalBlock block) { if (block is IMyDoor) { addDoor(block as IMyDoor); return; } if (block is IMyLightingBlock) { lights.Add(block as IMyLightingBlock); return; } if (block is IMyAirVent) { addVent(block as IMyAirVent); return; } if (block is IMyGasTank) { addOxygenTank(block as IMyGasTank); return; } _console.Print($"Tried to add invalid block '{block.CustomName}'"); } private void addDoor(IMyDoor door) { if (door.CustomName.Contains("Inner") && innerDoor == null) { innerDoor = door; return; } if (door.CustomName.Contains("Outer") && outerDoor == null) { outerDoor = door; return; } _console.Print($"Couldn't add door '{door.CustomName}'"); } private void addVent(IMyAirVent vent) { if (vent.CustomName.Contains("Main") && airVent == null) { airVent = vent; return; } if (vent.CustomName.Contains("Reference") && airSensor == null) { airSensor = vent; return; } _console.Print($"Couldn't add air vent '{vent.CustomName}'"); } private void addOxygenTank(IMyGasTank tank) { if (oxygenTank == null) { oxygenTank = tank; return; } _console.Print($"Couldn't add oxygen tank '{tank.CustomName}'"); } // private void initDoors() // { // List onlyDoors = new List(); // _p.GridTerminalSystem.GetBlocksOfType(onlyDoors); // foreach (IMyDoor door in onlyDoors) // { // if (!door.CustomName.StartsWith(_name)) continue; // if (door.CustomName.Contains("Inner")) // { // innerDoor = door; // } // else if (door.CustomName.Contains("Outer")) // { // outerDoor = door; // } // if (innerDoor != null && outerDoor != null) // { // return; // } // } // Functional = false; // } // private void initVents() // { // List onlyFans = new List(); // _p.GridTerminalSystem.GetBlocksOfType(onlyFans); // foreach (IMyAirVent vent in onlyFans) // { // if (!vent.CustomName.StartsWith(_name)) continue; // if (vent.CustomName.StartsWith(_name)) // { // if (vent.CustomName.Contains("Main")) // { // airVent = vent; // continue; // } // else if (vent.CustomName.Contains("Reference")) // { // airSensor = vent; // continue; // } // } // // A global reference vent will be used if we don't have one specific to our airlock. // // A specific vent found later will overwrite this assignment. // if (vent.CustomName.StartsWith("Airlock Reference") && airSensor == null) // { // airSensor = vent; // } // } // if (airVent == null) Functional = false; // } // private void initLights() // { // lights = new List(); // List allLights = new List(); // _p.GridTerminalSystem.GetBlocksOfType(allLights); // foreach (IMyLightingBlock light in allLights) // { // if (!light.CustomName.StartsWith(_name)) continue; // lights.Add(light); // } // } // private void initOxygen() // { // List allTanks = new List(); // _p.GridTerminalSystem.GetBlocksOfType(allTanks); // foreach (IMyGasTank tank in allTanks) // { // if (!tank.CustomName.StartsWith(_name)) continue; // oxygenTank = tank; // return; // } // Functional = false; // } public IEnumerator CycleAirlock() { Cycling = true; setLights(AirlockLightState.Cycling); closeDoors(); while (!DoorsClosed) { yield return true; } lockDoors(); if (!airVent.CanPressurize) { error("Airlock is not airtight."); Cycling = false; yield break; } pressurizeDepressurize(); while (!PressureStabilized) { yield return true; } airVent.Enabled = false; openDoor(); while (!DoorOpened) { yield return true; } lockDoors(); // Balance oxygen storage setLights(AirlockLightState.Cooldown); if (balanceOxygen()) { while (!OxygenBalanced) { yield return true; } } airVent.Enabled = false; // Cooldown period int cooldown = 0; while (cooldown < CooldownTicks) { cooldown++; yield return true; } setLights(AirlockLightState.Off); _console.Print("Cycling Complete."); Cycling = false; } private void closeDoors() { _console.Print("Closing Doors"); // close the doors innerDoor.Enabled = true; outerDoor.Enabled = true; innerDoor.CloseDoor(); outerDoor.CloseDoor(); } private void pressurizeDepressurize() { _console.Print("Cycling"); // toggle the current state airVent.Depressurize = !airVent.Depressurize; airVent.Enabled = true; // When depressurizing, check the external pressure and only depressurize to that value. // TODO: test this for floating point errors if (airVent.Depressurize && airSensor != null) { targetOxygenLevel = airSensor.GetOxygenLevel(); _console.Print($"Set depressurization target to {targetOxygenLevel}"); } } // Open the appropriate door based on pressure state. private void openDoor() { _console.Print($"Opening Door"); if (airVent.Status == VentStatus.Pressurized) { innerDoor.Enabled = true; innerDoor.OpenDoor(); } else { outerDoor.Enabled = true; outerDoor.OpenDoor(); } } // TODO: blinkenlights are unsatisfying right now... private void setLights(AirlockLightState lightState) { float blinkLength = 1.0F; float blinkInterval = 0.0F; Color color = Color.Red; switch (lightState) { case AirlockLightState.Off: color = Color.Green; break; case AirlockLightState.Cycling: blinkInterval = 1.0F; blinkLength = 0.75F; break; case AirlockLightState.Cooldown: color = Color.Yellow; break; case AirlockLightState.Error: // the defaults already set this correctly break; } foreach (IMyLightingBlock light in lights) { light.Enabled = true; light.BlinkIntervalSeconds = blinkInterval; light.BlinkLength = blinkLength; light.Color = color; } } private void lockDoors() { innerDoor.Enabled = false; outerDoor.Enabled = false; } private void error(string error) { _console.Print(error); setLights(AirlockLightState.Error); } } } }