namespace ReactorMaintenance.Simulation; public enum EEditorTool { Cursor, Floor, Wall, FuelUnderground, CoolantUnderground, ElectricityUnderground, FuelFlow, CoolantFlow, ElectricityFlow, FuelConsumer, CoolantConsumer, ElectricityConsumer, Junction, Door, AllSeeingEyeTerminal, FuelRemedySupply, CoolantRemedySupply, ElectricityRemedySupply, HeatRemedySupply, ReactorControl, FuelLeak, CoolantLeak, ElectricityLeak, FuelHazard, CoolantHazard, ElectricityHazard, Heat, Robot } public static class LevelEditor { public static LevelState Apply(LevelState level, GridPosition position, EEditorTool tool) { if (!level.InBounds(position)) return level; return tool switch { EEditorTool.Cursor => level, EEditorTool.Floor => level.SetTerrain(position, ECellTerrain.Floor), EEditorTool.Wall => level.SetTerrain(position, ECellTerrain.Wall), EEditorTool.FuelUnderground => SetUnderground(level, position, ECarrierType.Fuel), EEditorTool.CoolantUnderground => SetUnderground(level, position, ECarrierType.Coolant), EEditorTool.ElectricityUnderground => SetUnderground(level, position, ECarrierType.Electricity), EEditorTool.FuelFlow => SetCarrierProp(level, position, EPropType.Flow, ECarrierType.Fuel), EEditorTool.CoolantFlow => SetCarrierProp(level, position, EPropType.Flow, ECarrierType.Coolant), EEditorTool.ElectricityFlow => SetCarrierProp(level, position, EPropType.Flow, ECarrierType.Electricity), EEditorTool.FuelConsumer => SetCarrierProp(level, position, EPropType.Consumer, ECarrierType.Fuel), EEditorTool.CoolantConsumer => SetCarrierProp(level, position, EPropType.Consumer, ECarrierType.Coolant), EEditorTool.ElectricityConsumer => SetCarrierProp(level, position, EPropType.Consumer, ECarrierType.Electricity), EEditorTool.Junction => SetFloorProp(level, position, new() { Type = EPropType.Junction }), EEditorTool.Door => SetDoor(level, position), EEditorTool.AllSeeingEyeTerminal => SetFloorProp(level, position, new() { Type = EPropType.AllSeeingEyeTerminal }), EEditorTool.FuelRemedySupply => SetFloorProp(level, position, new() { Type = EPropType.RemedySupply, RemedyType = ERemedyType.FuelNeutralizer }), EEditorTool.CoolantRemedySupply => SetFloorProp(level, position, new() { Type = EPropType.RemedySupply, RemedyType = ERemedyType.CoolantNeutralizer }), EEditorTool.ElectricityRemedySupply => SetFloorProp(level, position, new() { Type = EPropType.RemedySupply, RemedyType = ERemedyType.ElectricityNeutralizer }), EEditorTool.HeatRemedySupply => SetFloorProp(level, position, new() { Type = EPropType.RemedySupply, RemedyType = ERemedyType.HeatShield }), EEditorTool.ReactorControl => SetReactorControl(level, position), EEditorTool.FuelLeak => SetLeak(level, position, ECarrierType.Fuel), EEditorTool.CoolantLeak => SetLeak(level, position, ECarrierType.Coolant), EEditorTool.ElectricityLeak => SetLeak(level, position, ECarrierType.Electricity), EEditorTool.FuelHazard => level.SetSurface(position, level.GetSurface(position) with { Fuel = level.GetSurface(position).Fuel + 1 }), EEditorTool.CoolantHazard => level.SetSurface(position, level.GetSurface(position) with { Coolant = level.GetSurface(position).Coolant + 1 }), EEditorTool.ElectricityHazard => level.SetSurface(position, level.GetSurface(position) with { Electricity = level.GetSurface(position).Electricity + 1 }), EEditorTool.Heat => level.SetSurface(position, level.GetSurface(position) with { Heat = level.GetSurface(position).Heat + 1 }), EEditorTool.Robot => level.IsFloor(position) ? level with { Robot = level.Robot with { Position = position } } : level, _ => level }; } public static LevelState BindFirstReactorToConsumers(LevelState level, GridPosition fuelConsumer, GridPosition coolantConsumer, GridPosition electricityConsumer) { if (level.Reactors.Count == 0) return level; var reactors = level.Reactors.ToArray(); reactors[0] = reactors[0] with { FuelConsumerPosition = fuelConsumer, CoolantConsumerPosition = coolantConsumer, ElectricityConsumerPosition = electricityConsumer }; return level with { Reactors = reactors }; } private static LevelState SetUnderground(LevelState level, GridPosition position, ECarrierType carrier) { return level.SetUnderground(position, carrier, new() { State = EUndergroundState.Intact }); } private static LevelState SetCarrierProp(LevelState level, GridPosition position, EPropType type, ECarrierType carrier) { return SetFloorProp(level, position, new() { Type = type, Carrier = carrier, SwitchState = EPropSwitchState.Enabled }); } private static LevelState SetFloorProp(LevelState level, GridPosition position, PropState prop) { return level.IsFloor(position) ? level.SetProp(position, prop) : level; } private static LevelState SetDoor(LevelState level, GridPosition position) { if (!level.IsFloor(position)) return level; var neighbor = position.Neighbors().FirstOrDefault(level.IsFloor); if (neighbor is null) return SetFloorProp(level, position, new() { Type = EPropType.Door }); return SetFloorProp(level, position, new() { Type = EPropType.Door }) with { Doors = [.. level.Doors, new DoorState { A = position, B = neighbor }] }; } private static LevelState SetReactorControl(LevelState level, GridPosition position) { if (!level.IsFloor(position)) return level; var id = level.Reactors.Count == 0 ? 1 : level.Reactors.Max(reactor => reactor.ReactorId) + 1; var levelWithProp = level.SetProp(position, new() { Type = EPropType.ReactorControl, ReactorId = id }); return levelWithProp with { Reactors = [ .. level.Reactors, new ReactorBinding { ReactorId = id, ControlPosition = position, FuelConsumerPosition = position, CoolantConsumerPosition = position, ElectricityConsumerPosition = position } ] }; } private static LevelState SetLeak(LevelState level, GridPosition position, ECarrierType carrier) { if (!level.InBounds(position)) return level; var accessPosition = carrier == ECarrierType.Electricity && level.GetTerrain(position) == ECellTerrain.Wall ? position.Neighbors().FirstOrDefault(level.IsFloor) : position; if (accessPosition is null || !level.IsFloor(accessPosition)) return level; var next = level.SetUnderground(position, carrier, new() { State = EUndergroundState.Leaking }); return next with { Leaks = [ .. next.Leaks, new LeakState { Carrier = carrier, UndergroundPosition = position, AccessPosition = accessPosition } ] }; } }