diff --git a/ActionSequencer/ActionSequencer.csproj b/ActionSequencer/ActionSequencer.csproj
new file mode 100644
index 0000000..0f4379c
--- /dev/null
+++ b/ActionSequencer/ActionSequencer.csproj
@@ -0,0 +1,28 @@
+
+
+ netframework48
+ IngameScript
+ 6
+ false
+ Release;Debug
+ x64
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ActionSequencer/ActionSequencer.mdk.ini b/ActionSequencer/ActionSequencer.mdk.ini
new file mode 100644
index 0000000..5add8f4
--- /dev/null
+++ b/ActionSequencer/ActionSequencer.mdk.ini
@@ -0,0 +1,22 @@
+; This file is project specific and should be checked in to source control.
+
+[mdk]
+; This is a programmable block script project.
+; You should not change this.
+type=programmableblock
+
+; Toggle trace (on|off) (verbose output)
+trace=off
+
+; What type of minification to use (none|trim|stripcomments|lite|full)
+; none: No minification
+; trim: Removes unused types (NOT members).
+; stripcomments: trim + removes comments.
+; lite: stripcomments + removes leading/trailing whitespace.
+; full: lite + renames identifiers to shorter names.
+minify=none
+
+; A list of files and folder to ignore when creating the script.
+; This is a comma separated list of glob patterns.
+; See https://code.visualstudio.com/docs/editor/glob-patterns
+ignores=obj/**/*,MDK/**/*,**/*.debug.cs
diff --git a/ActionSequencer/ActionSequencer.mdk.local.ini b/ActionSequencer/ActionSequencer.mdk.local.ini
new file mode 100644
index 0000000..4b66820
--- /dev/null
+++ b/ActionSequencer/ActionSequencer.mdk.local.ini
@@ -0,0 +1,7 @@
+; This file is _local_ to your machine and should not be checked in to source control.
+
+[mdk]
+; Where to output the script to (auto|specific path)
+output=auto
+; Override the default binary path (auto|specific path)
+binarypath=auto
\ No newline at end of file
diff --git a/ActionSequencer/ActionSequencer.sln b/ActionSequencer/ActionSequencer.sln
new file mode 100644
index 0000000..2deb726
--- /dev/null
+++ b/ActionSequencer/ActionSequencer.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActionSequencer", "ActionSequencer.csproj", "{3E6FA78A-C1AD-444F-A36A-6A5CFD35A785}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3E6FA78A-C1AD-444F-A36A-6A5CFD35A785}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {3E6FA78A-C1AD-444F-A36A-6A5CFD35A785}.Debug|Any CPU.Build.0 = Debug|x64
+ {3E6FA78A-C1AD-444F-A36A-6A5CFD35A785}.Release|Any CPU.ActiveCfg = Release|x64
+ {3E6FA78A-C1AD-444F-A36A-6A5CFD35A785}.Release|Any CPU.Build.0 = Release|x64
+ EndGlobalSection
+EndGlobal
diff --git a/ActionSequencer/Instructions.readme b/ActionSequencer/Instructions.readme
new file mode 100644
index 0000000..ed30ab7
--- /dev/null
+++ b/ActionSequencer/Instructions.readme
@@ -0,0 +1,5 @@
+R e a d m e
+-----------
+
+In this file you can include any instructions or other comments you want to have injected onto the
+top of your final script. You can safely delete this file if you do not want any such comments.
diff --git a/ActionSequencer/Program.cs b/ActionSequencer/Program.cs
new file mode 100644
index 0000000..aad3513
--- /dev/null
+++ b/ActionSequencer/Program.cs
@@ -0,0 +1,121 @@
+using Sandbox.Game.EntityComponents;
+using Sandbox.ModAPI.Ingame;
+using Sandbox.ModAPI.Interfaces;
+using SpaceEngineers.Game.ModAPI.Ingame;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Text;
+using VRage;
+using VRage.Collections;
+using VRage.Game;
+using VRage.Game.Components;
+using VRage.Game.GUI.TextPanel;
+using VRage.Game.ModAPI.Ingame;
+using VRage.Game.ModAPI.Ingame.Utilities;
+using VRage.Game.ObjectBuilders.Definitions;
+using VRageMath;
+
+namespace IngameScript
+{
+ public partial class Program : MyGridProgram, IConsoleProgram
+ {
+ public MyIni Ini { get; } = new MyIni();
+ public IConsole Console { get; private set; }
+
+ private MyCommandLine _cli = new MyCommandLine();
+ private List> _jobs = new List>();
+ private Dictionary _sequences = new Dictionary();
+
+ public Program()
+ {
+ Console = new MainConsole(this, "Action Sequencer");
+
+ // initialize all the sequencers
+ List blocks = new List();
+ GridTerminalSystem.GetBlocksOfType(blocks, block => MyIni.HasSection(block.CustomData, "sequence"));
+ foreach (IMyTerminalBlock block in blocks)
+ {
+ Ini.TryParse(block.CustomData);
+ string id = Ini.Get("sequence", "id").ToString();
+
+ if (id == "")
+ {
+ Console.Print($"No id found for '{block.CustomName}'. Skipping.");
+ continue;
+ }
+ if (id == "all")
+ {
+ Console.Print($"'All' is a reserved keyword. Skipping '{block.CustomName}'.");
+ continue;
+ }
+
+ if (!_sequences.ContainsKey(id)) _sequences[id] = new Sequencer(this, id);
+
+ ISequenceable wrapped = SequenceableFactory.MakeSequenceable(block, Ini, id);
+ if (wrapped == null)
+ {
+ Console.Print($"Skipping incompatible block '{block.CustomName}'.");
+ continue;
+ }
+
+ _sequences[id].AddBlock(wrapped);
+ }
+
+ Console.Print($"Found {_sequences.Count} sequences.");
+ }
+
+ public void Main(string argument, UpdateType updateSource)
+ {
+ Console.UpdateTickCount();
+
+ if (argument != "")
+ {
+ _cli.TryParse(argument);
+
+ List sequencesToRun = new List();
+ bool deploy = !_cli.Switch("stow");
+
+ if (_cli.ArgumentCount > 0 && _cli.Argument(0) == "all")
+ {
+ sequencesToRun = _sequences.Values.ToList();
+ }
+ for (int i = 0; i < _cli.ArgumentCount; i++)
+ {
+ string id = _cli.Argument(i);
+ if (!_sequences.ContainsKey(id))
+ {
+ Console.Print($"Ignoring non-existent sequence '{id}'");
+ continue;
+ }
+ sequencesToRun.Add(_sequences[id]);
+ }
+
+ foreach (Sequencer sequence in sequencesToRun)
+ {
+ Console.Print($"Activating sequence '{sequence.Name}'");
+ _jobs.Add(sequence.RunSequence(deploy));
+ }
+ if (_jobs.Count > 0) Runtime.UpdateFrequency = UpdateFrequency.Update10;
+ }
+
+ // Process running jobs
+ for (int i = 0; i < _jobs.Count; i++)
+ {
+ if (_jobs[i].MoveNext()) continue;
+
+ _jobs[i].Dispose();
+ _jobs.Remove(_jobs[i]);
+ i--;
+ Console.Print("Operation Complete.");
+ }
+
+ if (_jobs.Count == 0)
+ {
+ Runtime.UpdateFrequency = UpdateFrequency.None;
+ }
+ }
+ }
+}
diff --git a/ActionSequencer/thumb.png b/ActionSequencer/thumb.png
new file mode 100644
index 0000000..a8dc2ef
Binary files /dev/null and b/ActionSequencer/thumb.png differ
diff --git a/SpaceEngineers.sln b/SpaceEngineers.sln
index 47c3ade..2c4992d 100644
--- a/SpaceEngineers.sln
+++ b/SpaceEngineers.sln
@@ -7,6 +7,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Airlock", "Airlock\Airlock.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MechanicalDoor", "MechanicalDoor\MechanicalDoor.csproj", "{67FE627E-176A-4973-9FB7-FA5133CC8288}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ActionSequencer", "ActionSequencer\ActionSequencer.csproj", "{1F5CCD1E-028F-4C08-B2FE-43C0670028DB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AirMonitor", "AirMonitor\AirMonitor.csproj", "{40B352CD-100E-4F87-A7A0-FF00F4B8846C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -24,5 +28,13 @@ Global
{67FE627E-176A-4973-9FB7-FA5133CC8288}.Debug|Any CPU.Build.0 = Debug|x64
{67FE627E-176A-4973-9FB7-FA5133CC8288}.Release|Any CPU.ActiveCfg = Release|x64
{67FE627E-176A-4973-9FB7-FA5133CC8288}.Release|Any CPU.Build.0 = Release|x64
+ {1F5CCD1E-028F-4C08-B2FE-43C0670028DB}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {1F5CCD1E-028F-4C08-B2FE-43C0670028DB}.Debug|Any CPU.Build.0 = Debug|x64
+ {1F5CCD1E-028F-4C08-B2FE-43C0670028DB}.Release|Any CPU.ActiveCfg = Release|x64
+ {1F5CCD1E-028F-4C08-B2FE-43C0670028DB}.Release|Any CPU.Build.0 = Release|x64
+ {40B352CD-100E-4F87-A7A0-FF00F4B8846C}.Debug|Any CPU.ActiveCfg = Debug|x64
+ {40B352CD-100E-4F87-A7A0-FF00F4B8846C}.Debug|Any CPU.Build.0 = Debug|x64
+ {40B352CD-100E-4F87-A7A0-FF00F4B8846C}.Release|Any CPU.ActiveCfg = Release|x64
+ {40B352CD-100E-4F87-A7A0-FF00F4B8846C}.Release|Any CPU.Build.0 = Release|x64
EndGlobalSection
EndGlobal