Refactor missile launch system and add abort functionality

- Updated `State` enum to remove `FILLING_TANK` and add `ABORTING`.
- Modified `Launcher` constructor to include `IMyProjector`.
- Added `AbortLaunching` method to handle abort state.
- Enhanced `UpdateState` to manage the new `ABORTING` state.
- Introduced `CheckMissileBuilt` method for missile readiness checks.
- Increased `HYDRO_TANK_FILLED_PERCENT` from 40 to 60.
- Changed `GRID_PREFIX` from `[PML]` to `[Mimine]`.
- Updated program's frequency from `Update10` to `Update100`.
- Adjusted `ResetToNominal` to call `AbortLaunching` for all launchers.
This commit is contained in:
Greg Burri 2025-09-14 17:25:14 +02:00
parent b1ac491186
commit 16040e5f5a

View file

@ -50,8 +50,8 @@ namespace IngameScript
{
NOMINAL,
STARTING_SEQUENCE,
FILLING_TANK,
LAUNCHING,
ABORTING,
}
readonly int number;
@ -59,6 +59,7 @@ namespace IngameScript
readonly IMyGridTerminalSystem gridTerminal;
readonly IMyShipConnector connector;
readonly IMyProjector projector;
Missile missile;
State currentState = State.NOMINAL;
@ -71,12 +72,13 @@ namespace IngameScript
/// <param name="grid"></param>
/// <param name="output">To output some text</param>
/// <param name="connector">Connector of the launcher (not the missile)</param>
public Launcher(int number, IMyGridTerminalSystem gridTerminal, Output output, IMyShipConnector connector)
public Launcher(int number, IMyGridTerminalSystem gridTerminal, Output output, IMyShipConnector connector, IMyProjector projector)
{
this.number = number;
this.gridTerminal = gridTerminal;
this.output = output;
this.connector = connector;
this.projector = projector;
}
public void Launch()
@ -85,6 +87,11 @@ namespace IngameScript
this.currentState = State.STARTING_SEQUENCE;
}
public void AbortLaunching()
{
this.currentState = State.ABORTING;
}
void Print(string message)
{
this.output.Print(String.Format("{0:00}: {1}", this.number, message));
@ -92,92 +99,119 @@ namespace IngameScript
public void UpdateState()
{
this.CheckMissileBuilt();
switch (this.currentState)
{
case State.STARTING_SEQUENCE:
var missileConnector = this.connector.OtherConnector;
if (missileConnector == null)
if (!this.CheckMissileBuilt())
{
this.Print("Cannot find the missile connector");
this.Print("Can't launch missile: Not built, waiting...");
break;
}
var missileGrid = missileConnector.CubeGrid;
if (missileGrid == null)
{
this.Print("Cannot find the missile grid");
break;
}
IMyGasTank tank = this.gridTerminal.GetBlock<IMyGasTank>("[PM] Hydrogen Tank", missileGrid);
if (tank == null)
{
this.Print("Cannot find the missile hydrogen tank");
break;
}
IMyShipMergeBlock mergeBlock = this.gridTerminal.GetBlock<IMyShipMergeBlock>("[PM] Merge Block", missileGrid);
if (mergeBlock == null)
{
this.Print("Cannot find the missile merge block");
break;
}
IMyProgrammableBlock programmableBlock = this.gridTerminal.GetBlock<IMyProgrammableBlock>("[PM] Programmable Block", missileGrid);
if (programmableBlock == null)
{
this.Print("Cannot find the missile programmable block");
break;
}
IEnumerable<IMyThrust> thrusters = this.gridTerminal.GetBlocksFromGroup<IMyThrust>("[PM] Thrusters", missileGrid);
if (thrusters.Count() == 0)
{
this.Print("Cannot find missile thrusters");
break;
}
// When launched the missile will enabled itself its thrusters.
foreach (var thruster in thrusters)
thruster.Enabled = false;
tank.Stockpile = true;
connector.Connect();
this.missile = new Missile(tank, connector, mergeBlock, programmableBlock);
this.currentState = State.FILLING_TANK;
break;
case State.FILLING_TANK:
this.Print($"Waiting missile tank filled... ({this.missile.Tank.FilledRatio * 100:.0}%)");
if (this.missile.Tank.FilledRatio >= Program.HYDRO_TANK_FILLED_PERCENT / 100)
{
this.missile.Tank.Stockpile = false;
this.currentState = State.LAUNCHING;
}
else
{
this.Print($"Waiting missile tank filled... ({this.missile.Tank.FilledRatio * 100:.0}%)");
}
break;
case State.LAUNCHING:
this.Print("Launching missile...");
this.missile.MergeBlock.Enabled = false;
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;
this.missile = null;
break;
case State.ABORTING:
this.missile = null;
this.currentState = State.NOMINAL;
break;
case State.NOMINAL:
break; // Nothing;
}
}
/// <summary>
/// Returns true if missile ready.
/// </summary>
/// <returns></returns>
bool CheckMissileBuilt()
{
if (this.missile != null)
return true;
var missileConnector = this.connector.OtherConnector;
if (missileConnector == null)
{
//this.Print("Cannot find the missile connector");
return false;
}
var missileGrid = missileConnector.CubeGrid;
if (missileGrid == null)
{
//this.Print("Cannot find the missile grid");
return false;
}
IMyGasTank tank = this.gridTerminal.GetBlock<IMyGasTank>("[PM] Hydrogen Tank", missileGrid);
if (tank == null)
{
//this.Print("Cannot find the missile hydrogen tank");
return false;
}
IMyShipMergeBlock mergeBlock = this.gridTerminal.GetBlock<IMyShipMergeBlock>("[PM] Merge Block", missileGrid);
if (mergeBlock == null)
{
//this.Print("Cannot find the missile merge block");
return false;
}
IMyProgrammableBlock programmableBlock = this.gridTerminal.GetBlock<IMyProgrammableBlock>("[PM] Programmable Block", missileGrid);
if (programmableBlock == null)
{
//this.Print("Cannot find the missile programmable block");
return false;
}
IEnumerable<IMyThrust> thrusters = this.gridTerminal.GetBlocksFromGroup<IMyThrust>("[PM] Thrusters", missileGrid);
if (thrusters.Count() == 0)
{
//this.Print("Cannot find missile thrusters");
return false;
}
if (this.projector.RemainingBlocks > 0)
return false;
// When launched the missile will enabled itself its thrusters.
foreach (var thruster in thrusters)
thruster.Enabled = false;
tank.Stockpile = true;
connector.Connect();
this.missile = new Missile(tank, connector, mergeBlock, programmableBlock);
return true;
}
}
partial class Program : MyGridProgram
@ -190,11 +224,12 @@ namespace IngameScript
LAUNCHING_CONTINUOUS,
}
public const string GRID_PREFIX = "[PML]";
public const string GRID_PREFIX = "[Mimine]";
public const string MISSILE_GRID_PREFIX = "[PM]";
public const double HYDRO_TANK_FILLED_PERCENT = 40;
public const double HYDRO_TANK_FILLED_PERCENT = 60;
const string LAUNCHER_SMALL_CONNECTOR_NAME = "Connector Launcher"; // Following by a number: "01", "02", etc.
const string PROJECTOR_NAME = "Projector Missile"; // Following by a number: "01", "02", etc.
const string DOORS_MISSILES_GROUP = "Doors Missiles";
const float EPSILON = 0.05f;
@ -234,10 +269,12 @@ namespace IngameScript
foreach (var connector in launcherConnectors)
{
var n = int.Parse(connector.CustomName.Substring(connectorNamePrefix.Length));
this.launchers.Add(new Launcher(n, this.GridTerminalSystem, this.output, connector));
var projector = this.GridTerminalSystem.GetBlock<IMyProjector>($"{GRID_PREFIX} {PROJECTOR_NAME} {n:0,0}");
this.launchers.Add(new Launcher(n, this.GridTerminalSystem, this.output, connector, projector));
}
this.Runtime.UpdateFrequency = UpdateFrequency.Update10;
this.Runtime.UpdateFrequency = UpdateFrequency.Update100;
this.output.Print($"Missile launcher system started ({this.launchers.Count} launcher(s))");
}
@ -264,6 +301,9 @@ namespace IngameScript
void ResetToNominal()
{
foreach (var launcher in this.launchers)
launcher.AbortLaunching();
this.nbLaunched = 0;
this.currentState = State.NOMINAL;
}
@ -303,7 +343,7 @@ namespace IngameScript
public void Main(string argument, UpdateType updateSource)
{
if ((updateSource & UpdateType.Update10) != 0)
if ((updateSource & UpdateType.Update100) != 0)
{
this.UpdateState();
}