Files
zfxaction26_2/tests/ReactorMaintenance.Simulation.Tests/SimulationEngineTests.cs

618 lines
26 KiB
C#

namespace ReactorMaintenance.Simulation.Tests;
public sealed class SimulationEngineTests
{
[Fact]
public void NetworkPropagationSuppliesConsumerServicesAndReadiesReactor()
{
var level = BuildReadyLevel();
var next = m_Engine.AdvancePulseForDebug(level);
var consumer = next.GetProp(new(3, 3));
Assert.Equal(EConsumerServiceState.Producing, consumer.FuelServiceState);
Assert.Equal(EConsumerServiceState.Producing, consumer.WaterServiceState);
Assert.Equal(EConsumerServiceState.Producing, consumer.ElectricityServiceState);
Assert.Equal(ELevelState.Ready, next.Global.LevelState);
Assert.Empty(next.Forecasts);
}
[Fact]
public void ReactorNeedsPositiveFlowOnlyForNetworksBeneathControl()
{
var level = BuildReadyLevel();
level = level.SetUnderground(new(5, 3), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
var next = m_Engine.AdvancePulseForDebug(level);
Assert.NotEqual(ELevelState.Ready, next.Global.LevelState);
}
[Fact]
public void ReactorActivatesOnlyAtReadyControl()
{
var level = m_Engine.AdvancePulseForDebug(BuildReadyLevel()) with {
Robot = new() { Position = new(5, 3) }
};
var activated = m_Engine.ActivateReactor(level);
Assert.Equal(ELevelState.Won, activated.Global.LevelState);
Assert.True(activated.Reactors[0].Activated);
}
[Fact]
public void DisabledConsumerReportsDisabledOnlyForNetworksBeneathIt()
{
var level = LevelState.Create("Disabled", 6, 6);
level = level.SetUnderground(new(2, 2), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
level = level.SetProp(new(2, 2), new() { Type = EPropType.Consumer, SwitchState = EPropSwitchState.Disabled });
var next = m_Engine.AdvancePulseForDebug(level);
var consumer = next.GetProp(new(2, 2));
Assert.Equal(EConsumerServiceState.Disabled, consumer.FuelServiceState);
Assert.Equal(EConsumerServiceState.Unknown, consumer.WaterServiceState);
Assert.Equal(EConsumerServiceState.Unknown, consumer.ElectricityServiceState);
Assert.Equal(EConsumerServiceState.Disabled, consumer.ServiceState);
}
[Fact]
public void MovementIsQuickAndDoesNotResolveSimulationStep()
{
var level = LevelState.Create("Quick", 6, 6) with {
Robot = new() { Position = new(1, 1) }
};
var next = m_Engine.MoveRobot(level, new(2, 1));
Assert.Equal(new(2, 1), next.Robot.Position);
Assert.Equal(0, next.Global.Pulse);
}
[Fact]
public void DoorInteractionIsLengthyAndResolvesSimulationStep()
{
var level = DoorLevel();
level = level with { Robot = new() { Position = new(3, 2) } };
var next = m_Engine.InteractProp(level);
Assert.Equal(EDoorState.Open, next.GetProp(new(3, 2)).DoorState);
Assert.Equal(1, next.Global.Pulse);
Assert.Equal(Balancing.Current.StepsPerPulse, next.Global.Step);
}
[Fact]
public void UnpoweredDoorInteractionChangesNoDoorStateButStillPulses()
{
var level = DoorLevel(powered: false) with { Robot = new() { Position = new(3, 2) } };
var next = m_Engine.InteractProp(level);
Assert.Equal(EDoorState.Closed, next.GetProp(new(3, 2)).DoorState);
Assert.Equal(1, next.Global.Pulse);
}
[Fact]
public void PoweredTerminalInteractionEnablesLocalForecastsUntilRobotLeaves()
{
var level = TerminalLevel();
var activated = m_Engine.InteractProp(level);
var moved = m_Engine.MoveRobot(activated, new(2, 1));
Assert.True(activated.GetProp(new(1, 1)).Active);
Assert.NotEmpty(activated.Forecasts);
Assert.Empty(moved.Forecasts);
}
[Fact]
public void UnpoweredTerminalInteractionRevealsNothingButStillPulses()
{
var level = TerminalLevel(false);
var next = m_Engine.InteractProp(level);
Assert.False(next.GetProp(new(1, 1)).Active);
Assert.Empty(next.Forecasts);
Assert.Equal(1, next.Global.Pulse);
}
[Fact]
public void EveryAcceptedLengthyActionAdvancesOneFixedPulse()
{
var level = DoorLevel() with { Robot = new() { Position = new(3, 2) } };
var next = m_Engine.InteractProp(level);
Assert.Equal(1, next.Global.Pulse);
Assert.Equal(Balancing.Current.StepsPerPulse, next.Global.Step);
}
[Fact]
public void DebugStepAdvancementDoesNotAdvancePulse()
{
var level = BuildReadyLevel();
var next = m_Engine.AdvanceStepForDebug(level);
Assert.Equal(0, next.Global.Pulse);
Assert.Equal(1, next.Global.Step);
}
[Fact]
public void IsolationValveOpenAllowsPropagationAndClosedBlocksDownstreamFeed()
{
var open = IsolationValveLevel(EPropSwitchState.Enabled);
var closed = IsolationValveLevel(EPropSwitchState.Disabled);
var openResult = m_Engine.AdvancePulseForDebug(open);
var closedResult = m_Engine.AdvancePulseForDebug(closed);
Assert.True(openResult.GetUnderground(new(3, 2), ECarrierType.Fuel).Amount > 0);
Assert.Equal(ELevelState.Ready, openResult.Global.LevelState);
Assert.Equal(0, closedResult.GetUnderground(new(3, 2), ECarrierType.Fuel).Amount);
Assert.NotEqual(ELevelState.Ready, closedResult.Global.LevelState);
}
[Fact]
public void TogglingIsolationValveIsLengthyAndAdvancesOneFixedPulse()
{
var level = IsolationValveLevel(EPropSwitchState.Enabled) with { Robot = new() { Position = new(2, 2) } };
var next = m_Engine.InteractProp(level);
Assert.Equal(EPropSwitchState.Disabled, next.GetProp(new(2, 2)).SwitchState);
Assert.Equal(1, next.Global.Pulse);
Assert.Equal(Balancing.Current.StepsPerPulse, next.Global.Step);
}
[Fact]
public void ClosedInferredDoorBlocksAdjacentHeatFlow()
{
var level = DoorLevel();
level = level.SetSurface(new(3, 2), new() { Heat = 8 });
var next = m_Engine.AdvancePulseForDebug(level);
Assert.Equal(0, next.GetSurface(new(4, 2)).Heat);
}
[Fact]
public void StructuralIntegrityCreatesLeakWhenWeakCellHasPositivePressure()
{
var level = LevelState.Create("Integrity leak", 6, 6);
level = AddLine(level, ECarrierType.Fuel, new(1, 2), new(2, 2));
level = level.SetProp(new(1, 2), new() { Type = EPropType.Flow, Carrier = ECarrierType.Fuel });
level = level.SetUnderground(new(2, 2), ECarrierType.Fuel, level.GetUnderground(new(2, 2), ECarrierType.Fuel) with {
StructuralIntegrity = Balancing.Current.StructuralIntegrityLeakThreshold
});
var next = m_Engine.AdvancePulseForDebug(level);
Assert.Equal(EUndergroundState.Leaking, next.GetUnderground(new(2, 2), ECarrierType.Fuel).State);
Assert.Contains(next.Leaks, leak => leak.Carrier == ECarrierType.Fuel && leak.UndergroundPosition == new GridPosition(2, 2));
Assert.True(next.GetSurface(new(2, 2)).Fuel > 0);
}
[Fact]
public void HighPressureWorsensNonMaxStructuralIntegrity()
{
var level = LevelState.Create("Integrity damage", 6, 6);
level = AddLine(level, ECarrierType.Fuel, new(1, 2), new(2, 2));
level = level.SetProp(new(1, 2), new() { Type = EPropType.Flow, Carrier = ECarrierType.Fuel });
level = level.SetUnderground(new(2, 2), ECarrierType.Fuel, level.GetUnderground(new(2, 2), ECarrierType.Fuel) with {
StructuralIntegrity = Balancing.Current.MaxStructuralIntegrity - 1
});
var next = m_Engine.AdvancePulseForDebug(level);
Assert.True(next.GetUnderground(new(2, 2), ECarrierType.Fuel).StructuralIntegrity < Balancing.Current.MaxStructuralIntegrity - 1);
}
[Fact]
public void RepairingLeakRestoresStructuralIntegrity()
{
var level = LevelState.Create("Repair", 6, 6);
level = level.SetUnderground(new(2, 2), ECarrierType.Fuel, new() {
State = EUndergroundState.Leaking,
Amount = 5,
Intensity = 5,
StructuralIntegrity = 0
}) with {
Robot = new() { Position = new(2, 2) },
Leaks = [new() { Carrier = ECarrierType.Fuel, UndergroundPosition = new(2, 2), AccessPosition = new(2, 2) }]
};
var next = m_Engine.InteractLeak(level, ECarrierType.Fuel, false);
Assert.True(next.Leaks[0].Repaired);
Assert.Equal(EUndergroundState.Intact, next.GetUnderground(new(2, 2), ECarrierType.Fuel).State);
Assert.Equal(Balancing.Current.MaxStructuralIntegrity, next.GetUnderground(new(2, 2), ECarrierType.Fuel).StructuralIntegrity);
}
[Fact]
public void ElementRemedyClearsHazardAndBlocksImmediateReentry()
{
var level = LevelState.Create("Remedy", 6, 6);
level = level.SetUnderground(new(2, 2), ECarrierType.Fuel, new() { State = EUndergroundState.Leaking, Amount = 5, Intensity = 5 });
level = level.SetSurface(new(2, 2), new() { Fuel = 5 }) with {
Robot = new() { Position = new(2, 2), FuelNeutralizers = 1 },
Leaks = [new() { Carrier = ECarrierType.Fuel, UndergroundPosition = new(2, 2), AccessPosition = new(2, 2) }]
};
var next = m_Engine.InteractLeak(level, ECarrierType.Fuel, true);
Assert.Equal(0, next.GetSurface(new(2, 2)).Fuel);
Assert.True(next.GetSurface(new(2, 2)).FuelBlockTurns > 0);
Assert.Equal(0, next.Robot.FuelNeutralizers);
}
[Fact]
public void HeatShieldPreventsRobotHeatLoss()
{
var level = LevelState.Create("Heat shield", 6, 6);
level = level.SetSurface(new(2, 2), new() { Heat = Balancing.Current.RobotHeatSafetyThreshold }) with {
Robot = new() { Position = new(2, 2), HeatImmunitySteps = 1 }
};
var next = m_Engine.AdvancePulseForDebug(level);
Assert.NotEqual(ELevelState.Lost, next.Global.LevelState);
}
[Fact]
public void UnsafeEntryLossOnlyHappensWhenMovingIntoUnsafeDestination()
{
var level = LevelState.Create("Unsafe", 5, 5) with { Robot = new() { Position = new(1, 1) } };
level = level.SetSurface(new(2, 1), new() { Heat = Balancing.Current.RobotHeatSafetyThreshold });
var next = m_Engine.MoveRobot(level, new(2, 1));
Assert.Equal(ELevelState.Lost, next.Global.LevelState);
Assert.Equal("UNSAFE ENTRY LOSS", next.Global.Status);
}
[Fact]
public void FuelOnlyAndWaterOnlyCellsAreSafeToEnter()
{
var fuel = LevelState.Create("Fuel safe", 5, 5) with { Robot = new() { Position = new(1, 1) } };
fuel = fuel.SetSurface(new(2, 1), new() { Fuel = Balancing.Current.MaxValue });
var water = LevelState.Create("Water safe", 5, 5) with { Robot = new() { Position = new(1, 1) } };
water = water.SetSurface(new(2, 1), new() { Water = Balancing.Current.MaxValue });
Assert.NotEqual(ELevelState.Lost, m_Engine.MoveRobot(fuel, new(2, 1)).Global.LevelState);
Assert.NotEqual(ELevelState.Lost, m_Engine.MoveRobot(water, new(2, 1)).Global.LevelState);
}
[Fact]
public void PulseDoesNotLoseStationaryRobotWhenCellBecomesUnsafe()
{
var level = LevelState.Create("Stationary", 5, 5) with { Robot = new() { Position = new(2, 2) } };
level = level.SetSurface(new(2, 2), new() { Heat = Balancing.Current.RobotHeatSafetyThreshold });
var next = m_Engine.AdvancePulseForDebug(level);
Assert.NotEqual(ELevelState.Lost, next.Global.LevelState);
}
[Fact]
public void WaterDilutesFuelAndQuenchesHeatBeforeIgnition()
{
var level = LevelState.Create("Mitigation", 5, 5);
level = level.SetSurface(new(2, 2), new() {
Fuel = Balancing.Current.FuelCaution,
Water = Balancing.Current.WaterCritical,
Heat = Balancing.Current.HeatCaution
});
var next = m_Engine.AdvanceStepForDebug(level);
Assert.True(next.GetSurface(new(2, 2)).Fuel < level.GetSurface(new(2, 2)).Fuel);
Assert.True(next.GetSurface(new(2, 2)).Heat < level.GetSurface(new(2, 2)).Heat);
}
[Fact]
public void HotCellsEvaporateWaterFasterThanColdCells()
{
var level = LevelState.Create("Evaporation", 5, 5);
level = level.SetSurface(new(1, 1), new() { Water = 5 });
level = level.SetSurface(new(2, 1), new() { Water = 5, Heat = 6 });
var next = m_Engine.AdvanceStepForDebug(level);
Assert.True(next.GetSurface(new(2, 1)).Water < next.GetSurface(new(1, 1)).Water);
Assert.True(next.GetSurface(new(2, 1)).Heat < 6);
}
[Fact]
public void WetCellsConductElectricityFasterThanDryCells()
{
var wet = LevelState.Create("Wet conduct", 5, 5);
wet = wet.SetSurface(new(1, 1), new() { Electricity = 8, Water = Balancing.Current.WaterCaution });
var dry = LevelState.Create("Dry conduct", 5, 5);
dry = dry.SetSurface(new(1, 1), new() { Electricity = 8 });
var wetNext = m_Engine.AdvanceStepForDebug(wet);
var dryNext = m_Engine.AdvanceStepForDebug(dry);
Assert.True(wetNext.GetSurface(new(2, 1)).Electricity > dryNext.GetSurface(new(2, 1)).Electricity);
}
[Fact]
public void FuelAndElectricityCanIgniteIntoHeat()
{
var level = LevelState.Create("Ignite", 5, 5);
level = level.SetSurface(new(2, 2), new() { Fuel = Balancing.Current.FuelCritical, Electricity = Balancing.Current.ElectricityCritical });
var next = m_Engine.AdvanceStepForDebug(level);
Assert.True(next.GetSurface(new(2, 2)).Heat > 0);
Assert.True(next.GetSurface(new(2, 2)).Fuel < level.GetSurface(new(2, 2)).Fuel);
}
[Fact]
public void JunctionRatioSplitsFlowAcrossInferredOutgoingBranches()
{
var level = BuildJunctionLevel(2);
var next = m_Engine.AdvancePulseForDebug(level);
Assert.True(next.GetUnderground(new(2, 2), ECarrierType.Fuel).Amount > 0);
Assert.Equal(next.GetUnderground(new(2, 2), ECarrierType.Fuel).Amount, next.GetUnderground(new(3, 3), ECarrierType.Fuel).Amount);
Assert.True(next.GetUnderground(new(2, 2), ECarrierType.Fuel).Amount < next.GetUnderground(new(2, 3), ECarrierType.Fuel).Amount);
}
[Fact]
public void JunctionZeroWeightBranchReceivesNoIntentionalOutflow()
{
var level = BuildJunctionLevel(0);
var next = m_Engine.AdvancePulseForDebug(level);
Assert.Equal(0, next.GetUnderground(new(2, 2), ECarrierType.Fuel).Amount);
Assert.True(next.GetUnderground(new(3, 3), ECarrierType.Fuel).Amount > 0);
}
[Fact]
public void ValidatorRejectsAmbiguousJunctionSourceBranches()
{
var level = BuildJunctionLevel(2);
level = level.SetProp(new(3, 3), new() { Type = EPropType.Flow, Carrier = ECarrierType.Fuel });
var report = new LevelValidator().Validate(level);
Assert.False(report.IsValid);
Assert.Contains(report.Errors, error => error.Message.Contains("Ambiguous junction flow", StringComparison.Ordinal));
}
[Fact]
public void ValidatorRejectsInvalidDoorGeometryAndWallHazards()
{
var level = LevelState.Create("Invalid", 6, 6);
level = level.SetProp(new(2, 2), new() { Type = EPropType.Door });
level = level.SetTerrain(new(4, 4), ECellTerrain.Wall);
level = level with { Surface = level.Surface.ToArray() };
level.Surface[level.Index(new(4, 4))] = new() { Heat = 1 };
var report = new LevelValidator().Validate(level);
Assert.False(report.IsValid);
Assert.Contains(report.Errors, error => error.Message.Contains("Door must be surrounded", StringComparison.Ordinal));
Assert.Contains(report.Errors, error => error.Message.Contains("Wall cell", StringComparison.Ordinal));
}
[Fact]
public void LevelSerializationRoundTripsCurrentSchemaOnly()
{
var level = BuildReadyLevel();
var json = LevelSerializer.Serialize(level);
var loaded = LevelSerializer.Deserialize(json);
Assert.Contains("\"Version\": 4", json);
Assert.Equal(level.Name, loaded.Name);
Assert.Equal(EPropType.Consumer, loaded.GetProp(new(3, 3)).Type);
Assert.Equal(level.RequiredFuelConsumers, loaded.RequiredFuelConsumers);
}
[Fact]
public void LevelSerializationRoundTripsPropDoorsAndElectricityLeakFaces()
{
var level = BuildReadyLevel();
level = level.SetTerrain(new(6, 4), ECellTerrain.Wall);
level = level.SetUnderground(new(6, 4), ECarrierType.Electricity, new() { State = EUndergroundState.Leaking }) with {
Leaks = [new() { Carrier = ECarrierType.Electricity, UndergroundPosition = new(6, 4), AccessPosition = new(6, 3) }]
};
level = DoorLevel(level);
var loaded = LevelSerializer.Deserialize(LevelSerializer.Serialize(level));
Assert.Equal(EPropType.Door, loaded.GetProp(new(3, 2)).Type);
Assert.Single(loaded.Leaks);
Assert.Equal(new(6, 3), loaded.Leaks[0].AccessPosition);
}
[Fact]
public void LevelSerializationRoundTripsValveAndSprinklerFields()
{
var level = SprinklerLevel(EPropSwitchState.Disabled);
level = level.SetUnderground(new(3, 3), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
level = level.SetProp(new(3, 3), new() { Type = EPropType.IsolationValve, Carrier = ECarrierType.Fuel, SwitchState = EPropSwitchState.Disabled });
var loaded = LevelSerializer.Deserialize(LevelSerializer.Serialize(level));
Assert.Equal(EPropType.IsolationValve, loaded.GetProp(new(3, 3)).Type);
Assert.Equal(EPropSwitchState.Disabled, loaded.GetProp(new(3, 3)).SwitchState);
Assert.Equal(new(2, 1), loaded.GetProp(new(3, 2)).LinkedPosition);
Assert.Equal(new(2, 2), loaded.GetProp(new(2, 1)).OutletPosition);
}
[Fact]
public void LevelSerializationRejectsOldSchema()
{
var json = """
{
"Version": 2,
"Level": {}
}
""";
var exception = Assert.Throws<InvalidOperationException>(() => LevelSerializer.Deserialize(json));
Assert.Contains("Unsupported level file version 2", exception.Message);
}
[Fact]
public void SprinklerValveDischargesOnlyWithLinkedEnabledControlAndFedWaterBranch()
{
var enabled = SprinklerLevel(EPropSwitchState.Enabled);
var disabled = SprinklerLevel(EPropSwitchState.Disabled);
var enabledResult = m_Engine.AdvancePulseForDebug(enabled);
var disabledResult = m_Engine.AdvancePulseForDebug(disabled);
Assert.True(enabledResult.GetSurface(new(2, 2)).Water > 0);
Assert.Equal(0, disabledResult.GetSurface(new(2, 2)).Water);
}
[Fact]
public void SprinklerDischargeAppliesLocalPressureDebt()
{
var enabled = m_Engine.AdvancePulseForDebug(SprinklerLevel(EPropSwitchState.Enabled));
var disabled = m_Engine.AdvancePulseForDebug(SprinklerLevel(EPropSwitchState.Disabled));
Assert.True(enabled.GetUnderground(new(2, 1), ECarrierType.Water).Intensity < disabled.GetUnderground(new(2, 1), ECarrierType.Water).Intensity);
}
[Fact]
public void DirectSprinklerValveInteractionIsInvalidAndDoesNotPulse()
{
var level = SprinklerLevel(EPropSwitchState.Enabled) with { Robot = new() { Position = new(2, 1) } };
var next = m_Engine.InteractProp(level);
Assert.Equal(0, next.Global.Pulse);
Assert.Equal("PROP NOT INTERACTIVE", next.Global.Status);
}
[Fact]
public void UnfedLeakDoesNotInjectFreshSurfaceWater()
{
var level = LevelState.Create("Unfed leak", 5, 5);
level = level.SetUnderground(new(2, 2), ECarrierType.Water, new() { State = EUndergroundState.Leaking }) with {
RequiredFuelConsumers = 0,
RequiredWaterConsumers = 0,
RequiredElectricityConsumers = 0,
Leaks = [new() { Carrier = ECarrierType.Water, UndergroundPosition = new(2, 2), AccessPosition = new(2, 2) }]
};
var next = m_Engine.AdvancePulseForDebug(level);
Assert.Equal(0, next.GetSurface(new(2, 2)).Water);
}
private static LevelState BuildReadyLevel()
{
var level = LevelState.Create("Ready", 8, 7);
level = AddLine(level, ECarrierType.Fuel, new(2, 3), new(3, 3));
level = AddLine(level, ECarrierType.Water, new(2, 3), new(3, 3));
level = AddLine(level, ECarrierType.Electricity, new(2, 3), new(3, 3));
level = level.SetProp(new(2, 3), new() { Type = EPropType.Flow, Carrier = ECarrierType.Fuel });
level = level.SetProp(new(2, 2), new() { Type = EPropType.Flow, Carrier = ECarrierType.Water });
level = level.SetUnderground(new(2, 2), ECarrierType.Water, new() { State = EUndergroundState.Intact });
level = level.SetUnderground(new(2, 3), ECarrierType.Water, new() { State = EUndergroundState.Intact });
level = level.SetProp(new(2, 4), new() { Type = EPropType.Flow, Carrier = ECarrierType.Electricity });
level = level.SetUnderground(new(2, 4), ECarrierType.Electricity, new() { State = EUndergroundState.Intact });
level = level.SetUnderground(new(2, 3), ECarrierType.Electricity, new() { State = EUndergroundState.Intact });
level = level.SetProp(new(3, 3), new() { Type = EPropType.Consumer });
level = level.SetProp(new(5, 3), new() { Type = EPropType.ReactorControl, ReactorId = 1 });
return level with {
Robot = new() { Position = new(5, 3) },
Reactors = [new() { ReactorId = 1, ControlPosition = new(5, 3) }]
};
}
private static LevelState DoorLevel(LevelState? seed = null, bool powered = true)
{
var level = seed ?? LevelState.Create("Door", 6, 6);
level = level.SetTerrain(new(3, 1), ECellTerrain.Wall);
level = level.SetTerrain(new(3, 3), ECellTerrain.Wall);
if (powered)
{
level = AddLine(level, ECarrierType.Electricity, new(2, 2), new(3, 2));
level = level.SetProp(new(2, 2), new() { Type = EPropType.Flow, Carrier = ECarrierType.Electricity });
}
return level.SetProp(new(3, 2), new() { Type = EPropType.Door, DoorState = EDoorState.Closed });
}
private static LevelState AddLine(LevelState level, ECarrierType carrier, GridPosition a, GridPosition b)
{
level = level.SetUnderground(a, carrier, new() { State = EUndergroundState.Intact });
level = level.SetUnderground(b, carrier, new() { State = EUndergroundState.Intact });
return level;
}
private static LevelState BuildJunctionLevel(int mode)
{
var level = LevelState.Create("Junction", 6, 6);
level = level.SetUnderground(new(1, 3), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
level = level.SetUnderground(new(2, 3), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
level = level.SetUnderground(new(2, 2), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
level = level.SetUnderground(new(3, 3), ECarrierType.Fuel, new() { State = EUndergroundState.Intact });
level = level.SetProp(new(1, 3), new() { Type = EPropType.Flow, Carrier = ECarrierType.Fuel });
return level.SetProp(new(2, 3), new() { Type = EPropType.Junction, Carrier = ECarrierType.Fuel, JunctionMode = mode });
}
private static LevelState IsolationValveLevel(EPropSwitchState valveState)
{
var level = LevelState.Create("Valve", 6, 5);
level = AddLine(level, ECarrierType.Fuel, new(1, 2), new(2, 2));
level = AddLine(level, ECarrierType.Fuel, new(2, 2), new(3, 2));
level = level.SetProp(new(1, 2), new() { Type = EPropType.Flow, Carrier = ECarrierType.Fuel });
level = level.SetProp(new(2, 2), new() { Type = EPropType.IsolationValve, Carrier = ECarrierType.Fuel, SwitchState = valveState });
level = level.SetProp(new(3, 2), new() { Type = EPropType.ReactorControl, ReactorId = 1 });
return level with {
RequiredFuelConsumers = 0,
RequiredWaterConsumers = 0,
RequiredElectricityConsumers = 0,
Robot = new() { Position = new(3, 2) },
Reactors = [new() { ReactorId = 1, ControlPosition = new(3, 2) }]
};
}
private static LevelState SprinklerLevel(EPropSwitchState controlState)
{
var level = LevelState.Create("Sprinkler", 5, 5);
level = level.SetTerrain(new(2, 1), ECellTerrain.Wall);
level = level.SetUnderground(new(1, 1), ECarrierType.Water, new() { State = EUndergroundState.Intact });
level = level.SetUnderground(new(2, 1), ECarrierType.Water, new() { State = EUndergroundState.Intact });
level = level.SetProp(new(1, 1), new() { Type = EPropType.Flow, Carrier = ECarrierType.Water });
level = level.SetProp(new(2, 1), new() { Type = EPropType.SprinklerValve, Carrier = ECarrierType.Water, OutletPosition = new(2, 2) });
level = level.SetProp(new(3, 2), new() { Type = EPropType.SprinklerControl, SwitchState = controlState, LinkedPosition = new(2, 1) });
return level with {
RequiredFuelConsumers = 0,
RequiredWaterConsumers = 0,
RequiredElectricityConsumers = 0,
Robot = new() { Position = new(3, 2) }
};
}
private static LevelState TerminalLevel(bool powered = true)
{
var level = BuildReadyLevel();
level = level.SetProp(new(1, 1), new() { Type = EPropType.AllSeeingEyeTerminal });
level = level.SetUnderground(new(1, 1), ECarrierType.Electricity, new() { State = EUndergroundState.Intact });
if (powered)
{
level = level.SetUnderground(new(1, 2), ECarrierType.Electricity, new() { State = EUndergroundState.Intact });
level = level.SetProp(new(1, 2), new() { Type = EPropType.Flow, Carrier = ECarrierType.Electricity });
}
return level with { Robot = new() { Position = new(1, 1) } };
}
private readonly SimulationEngine m_Engine = new();
}