using Sandbox.Game.Entities.Cube; using Sandbox.Game.EntityComponents; using Sandbox.Game.GameSystems; using Sandbox.ModAPI.Ingame; using Sandbox.ModAPI.Interfaces; using SpaceEngineers.Game.Entities.Blocks; 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 VRage.GameServices; using VRageMath; // using static VRageRender.Utils.MyWingedEdgeMesh; namespace IngameScript { class Missile { //string prefix; //readonly string tankName = "Hydrogen Tank"; //readonly string connectorName = "Connector"; //readonly string mergeBlockName = "Merge Block"; //readonly string programmableBlockName = "Programmable Block"; //State currentState = State.NOMINAL; //IMyGridTerminalSystem gridTerminalSystem; public IMyGasTank Tank { get; } public IMyShipConnector Connector { get; } public IMyShipMergeBlock MergeBlock { get; } public IMyProgrammableBlock ProgrammableBlock { get; } public Missile(IMyGasTank tank, IMyShipConnector connector, IMyShipMergeBlock mergeBlock, IMyProgrammableBlock programmableBlock) { this.Tank = tank; this.Connector = connector; this.MergeBlock = mergeBlock; this.ProgrammableBlock = programmableBlock; } } class Launcher { enum State { NOMINAL, STARTING_SEQUENCE, FILLING_TANK, LAUNCHING, } int number; IMyCubeGrid grid; Output output; Missile missile; State currentState = State.NOMINAL; IMyGridTerminalSystem gridTerminal; IMyShipConnector connector; //IReadOnlyList welders; /// /// /// /// /// /// /// To output some text /// Connector of the launcher (not the missile) public Launcher(int number, IMyGridTerminalSystem gridTerminal, IMyCubeGrid grid, Output output, IMyShipConnector connector) { this.number = number; this.grid = grid; this.gridTerminal = gridTerminal; this.output = output; this.connector = connector; //this.connector = this.gridTerminal.GetBlockWithName(String.Format("{0} {1}", Program.GRID_PREFIX, String.Format(LAUNCHER_SMALL_CONNECTOR_NAME, number))) as IMyShipConnector; //output.Print($"{this.connector}"); } public void Launch() { if (this.currentState == State.NOMINAL) this.currentState = State.STARTING_SEQUENCE; } void Print(string message) { this.output.Print(String.Format("{0:00} {1}", this.number, message)); } public void UpdateState() { switch (this.currentState) { case State.STARTING_SEQUENCE: var missileConnector = this.connector.OtherConnector; if (missileConnector == null) { this.Print("Cannot find the missile connector"); break; } var missileGrid = missileConnector.CubeGrid; IMyGasTank tank = this.gridTerminal.GetBlock("[PM] Hydrogen Tank", missileGrid); //Utils.GetBlock( this.gridTerminal.GetBlockWithName("[PM] Hydrogen Tank") as IMyGasTank; this.output.Print($"tank: {tank}"); if (tank == null) { this.Print("Cannot find the missile hydrogen tank"); break; } IMyShipMergeBlock mergeBlock = this.gridTerminal.GetBlock("[PM] Merge Block", missileGrid); if (mergeBlock == null) { this.Print("Cannot find the missile merge block"); break; } IMyProgrammableBlock programmableBlock = this.gridTerminal.GetBlock("[PM] Programmable Block", missileGrid); if (programmableBlock == null) { this.Print("Cannot find the missile programmable block"); break; } tank.Stockpile = true; this.missile = new Missile(tank, connector, mergeBlock, programmableBlock); this.currentState = State.FILLING_TANK; break; case State.FILLING_TANK: this.Print("Waiting missile tank filled..."); if (this.missile.Tank.FilledRatio >= Program.HYDRO_TANK_FILLED_PERCENT / 100) { this.missile.Tank.Stockpile = false; this.currentState = State.LAUNCHING; } break; case State.LAUNCHING: this.Print("Launching missile..."); if (this.missile.ProgrammableBlock.TryRun("START")) this.Print("Missile launched!"); else this.Print("ERROR: Can't send START command to missile"); this.missile.MergeBlock.Enabled = false; this.connector.Disconnect(); this.currentState = State.NOMINAL; break; case State.NOMINAL: break; // Nothing; } } } partial class Program : MyGridProgram { enum State { NOMINAL, LAUNCHING_ONE, LAUNCHING_ALL, LAUNCHING_CONTINUOUS, } public const string GRID_PREFIX = "[PML]"; public const string MISSILE_GRID_PREFIX = "[PM]"; public const double HYDRO_TANK_FILLED_PERCENT = 20; const string LAUNCHER_GRID_NAME = "Launcher"; // Following by a number: "01", "02", etc. const string LAUNCHER_SMALL_CONNECTOR_NAME = "Connector Launcher"; // Following by a number: "01", "02", etc. //const string WELDER_NAME_GROUP = "Welder {0:00}"; // Example for group 1: ["Welder 01A", "Welder 01B", "Welder 01C"]. const float EPSILON = 0.05f; readonly Output output; IMyCubeGrid grid; List launchers = new List(); int nbLaunched = 0; int nextToLaunch = 0; State currentState = State.NOMINAL; //bool continuous_launching = false; public Program() { var output = this.Me.GetSurface(0); this.output = new Output(output); this.output.Print("Missile launcher system starting..."); this.grid = this.Me.CubeGrid; var connectorNamePrefix = String.Format("{0} {1} ", GRID_PREFIX, LAUNCHER_SMALL_CONNECTOR_NAME); // Find all launcher sub-grid and create the associated launcher. var launcherConnectors = new List(); this.GridTerminalSystem.GetBlocksOfType( launcherConnectors, (IMyShipConnector connector) => connector.CustomName.StartsWith(connectorNamePrefix) ); this.output.Print($"launcherConnectors.Count = {launcherConnectors.Count}"); foreach (var connector in launcherConnectors) //for (int i = 0; i < launcherConnectors.Count; i++) { var n = int.Parse(connector.CustomName.Substring(connectorNamePrefix.Length)); this.output.Print($"n = {n}"); //var n = i + 1; //var connector = launcherConnectors[i]; // Find associated welders. //var welders = new List(); //this.GridTerminalSystem.GetBlocksOfType( // welders, // (IMyShipWelder welder) => welder.CustomName.StartsWith(String.Format("{0} {1}", GRID_PREFIX, String.Format(WELDER_NAME_GROUP, n))) //); this.launchers.Add(new Launcher(n, this.GridTerminalSystem, connector.CubeGrid, this.output, connector)); } this.Runtime.UpdateFrequency = UpdateFrequency.Update100; this.output.Print("Missile launcher system started"); } void LaunchNext() { if (this.launchers.Count > 0) { this.launchers[this.nextToLaunch].Launch(); this.nextToLaunch = (this.nextToLaunch + 1) % this.launchers.Count; } } void Reset() { this.nbLaunched = 0; this.currentState = State.NOMINAL; } void UpdateState() { switch (this.currentState) { case State.LAUNCHING_ONE: this.LaunchNext(); this.Reset(); break; case State.LAUNCHING_ALL: if (this.nbLaunched >= launchers.Count) { this.Reset(); } else { this.LaunchNext(); } break; case State.LAUNCHING_CONTINUOUS: this.LaunchNext(); break; } foreach (var launcher in this.launchers) launcher.UpdateState(); } public void Save() { } public void Main(string argument, UpdateType updateSource) { if ((updateSource & UpdateType.Update100) != 0) { this.UpdateState(); } else if ((updateSource & (UpdateType.Terminal | UpdateType.Trigger)) != 0) { switch (argument) { case "LAUNCH ONE": this.output.Print("Launching one missile..."); this.currentState = State.LAUNCHING_ONE; break; case "LAUNCH ALL": this.output.Print("Launching all missiles..."); this.currentState = State.LAUNCHING_ALL; break; case "LAUNCH CONTINUOUS": this.output.Print("Launching missiles in continous..."); this.currentState = State.LAUNCHING_CONTINUOUS; break; case "STOP": this.output.Print("Stopping lauching..."); this.currentState = State.NOMINAL; break; default: this.output.Print($"Uknown command: {argument}"); break; } } } } }