mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-29 23:57:29 +00:00
Port: Nuclear Reactor (#5474)
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
using Robust.Shared.Map;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Client.Examine;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.ResourceManagement;
|
||||
|
||||
namespace Content.Client._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
public sealed class NuclearReactorSystem : SharedNuclearReactorSystem
|
||||
{
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<NuclearReactorComponent, ComponentInit>(OnInit);
|
||||
|
||||
SubscribeLocalEvent<NuclearReactorComponent, ClientExaminedEvent>(ReactorExamined);
|
||||
SubscribeLocalEvent<NuclearReactorComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, NuclearReactorComponent comp, ref ComponentInit args)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
||||
return;
|
||||
|
||||
if (!_resourceCache.TryGetResource("/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_component_cap.rsi", out RSIResource? resource))
|
||||
return;
|
||||
|
||||
Entity<SpriteComponent?> entSprite = (uid, sprite);
|
||||
var xspace = comp.Gridbounds[0] / 32f;
|
||||
var yspace = comp.Gridbounds[1] / 32f;
|
||||
var xoff = comp.Gridbounds[2] / 32f;
|
||||
var yoff = comp.Gridbounds[3] / 32f;
|
||||
|
||||
var gridWidth = comp.ReactorGridWidth;
|
||||
var gridHeight = comp.ReactorGridHeight;
|
||||
|
||||
var xAdj = (gridWidth - 1) / 2f;
|
||||
var yAdj = (gridHeight - 1) / 2f;
|
||||
|
||||
for (var x = 0; x < gridWidth; x++)
|
||||
{
|
||||
for (var y = 0; y < gridHeight; y++)
|
||||
{
|
||||
var layerID = _sprite.AddRsiLayer(entSprite, "empty_cap", resource.RSI);
|
||||
_sprite.LayerMapSet(entSprite, FormatMap(x, y), layerID);
|
||||
_sprite.LayerSetOffset(entSprite, layerID, new((xspace * (y - yAdj)) - xoff, (-yspace * (x - xAdj)) - yoff));
|
||||
_sprite.LayerSetColor(entSprite, layerID, Color.Black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatMap(int x, int y) => "NuclearReactorCap" + x + "/" + y;
|
||||
|
||||
private void ReactorExamined(EntityUid uid, NuclearReactorComponent comp, ClientExaminedEvent args) => Spawn(comp.ArrowPrototype, new EntityCoordinates(uid, 0, 0));
|
||||
|
||||
private void OnAppearanceChange(EntityUid uid, NuclearReactorComponent comp, ref AppearanceChangeEvent args)
|
||||
{
|
||||
for (var x = 0; x < comp.ReactorGridWidth; x++)
|
||||
{
|
||||
for (var y = 0; y < comp.ReactorGridHeight; y++)
|
||||
{
|
||||
if(comp.VisualData.TryGetValue(new(x,y), out var data))
|
||||
UpdateRodAppearance(uid, FormatMap(x,y), data.cap, data.color);
|
||||
else
|
||||
UpdateRodAppearance(uid, FormatMap(x, y), "empty_cap", Color.Black);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateRodAppearance(EntityUid uid, string map, string state, Color color)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(uid, out var sprite))
|
||||
return;
|
||||
|
||||
Entity<SpriteComponent?> entSprite = (uid, sprite);
|
||||
|
||||
if (!_sprite.LayerMapTryGet(entSprite, map, out var layer, false))
|
||||
return;
|
||||
|
||||
_sprite.LayerSetRsiState(entSprite, layer, state);
|
||||
_sprite.LayerSetColor(entSprite, layer, color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
public sealed class ReactorPartSystem : SharedReactorPartSystem
|
||||
{
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<ReactorPartComponent, AppearanceChangeEvent>(OnAppearanceChange);
|
||||
SubscribeLocalEvent<ReactorPartComponent, ComponentInit>(OnComponentInit);
|
||||
}
|
||||
|
||||
private void OnAppearanceChange(EntityUid uid, ReactorPartComponent component, ref AppearanceChangeEvent args)
|
||||
{
|
||||
if (args.Sprite == null)
|
||||
return;
|
||||
|
||||
// Re-enable if/when there are multiple sprites
|
||||
//if (!_sprite.LayerMapTryGet((uid, args.Sprite), ReactorCapVisualLayers.Sprite, out var layer, false))
|
||||
// return;
|
||||
|
||||
_sprite.LayerSetColor((uid, args.Sprite), 0, _proto.Index(component.Material).Color);
|
||||
}
|
||||
|
||||
private void OnComponentInit(Entity<ReactorPartComponent> ent, ref ComponentInit args)
|
||||
=> _sprite.LayerSetColor((ent.Owner, EntityManager.GetComponent<SpriteComponent>(ent.Owner)), 0, _proto.Index(ent.Comp.Material).Color);
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Client.GameObjects;
|
||||
using Content.Shared.Repairable;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Client.Popups;
|
||||
using Content.Client.Examine;
|
||||
using Robust.Client.Animations;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Popups;
|
||||
|
||||
namespace Content.Client._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/turbine.dm
|
||||
|
||||
public sealed class TurbineSystem : SharedTurbineSystem
|
||||
{
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!;
|
||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||
|
||||
private readonly float _threshold = 1f;
|
||||
private float _accumulator = 0;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, ClientExaminedEvent>(TurbineExamined);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, AnimationCompletedEvent>(OnAnimationCompleted);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, ItemSlotInsertAttemptEvent>(OnInsertAttempt);
|
||||
SubscribeLocalEvent<TurbineComponent, ItemSlotEjectAttemptEvent>(OnEjectAttempt);
|
||||
}
|
||||
|
||||
protected override void OnRepairTurbineFinished(EntityUid uid, TurbineComponent comp, ref RepairDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
_popupSystem.PopupClient(Loc.GetString("turbine-repair", ("target", uid), ("tool", args.Used!)), uid, args.User);
|
||||
}
|
||||
|
||||
private void TurbineExamined(EntityUid uid, TurbineComponent comp, ClientExaminedEvent args) => Spawn(comp.ArrowPrototype, new EntityCoordinates(uid, 0, 0));
|
||||
|
||||
#region Animation
|
||||
private void OnAnimationCompleted(EntityUid uid, TurbineComponent comp, ref AnimationCompletedEvent args) => PlayAnimation(uid, comp);
|
||||
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
_accumulator += frameTime;
|
||||
if (_accumulator >= _threshold)
|
||||
{
|
||||
AccUpdate();
|
||||
_accumulator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void AccUpdate()
|
||||
{
|
||||
var query = EntityQueryEnumerator<TurbineComponent>();
|
||||
while (query.MoveNext(out var uid, out var component))
|
||||
{
|
||||
// Makes sure the anim doesn't get stuck at low RPM
|
||||
PlayAnimation(uid, component);
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayAnimation(EntityUid uid, TurbineComponent comp)
|
||||
{
|
||||
if (!TryComp<SpriteComponent>(uid, out var sprite) || !_sprite.TryGetLayer((uid,sprite), TurbineVisualLayers.TurbineSpeed, out var layer, false))
|
||||
return;
|
||||
|
||||
var state = "speedanim";
|
||||
if (comp.RPM < 1)
|
||||
{
|
||||
_animationPlayer.Stop(uid, state);
|
||||
_sprite.LayerSetRsiState(layer, "turbine");
|
||||
comp.AnimRPM = -comp.BestRPM; // Primes it to start the instant it's spinning again
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.Abs(comp.RPM - comp.AnimRPM) > comp.BestRPM * 0.1)
|
||||
_animationPlayer.Stop(uid, state); // Current anim is stale, time for a new one
|
||||
|
||||
if (_animationPlayer.HasRunningAnimation(uid, state))
|
||||
return;
|
||||
|
||||
comp.AnimRPM = comp.RPM;
|
||||
var layerKey = TurbineVisualLayers.TurbineSpeed;
|
||||
var time = 0.5f * comp.BestRPM / comp.RPM;
|
||||
var timestep = time / 12;
|
||||
var animation = new Animation
|
||||
{
|
||||
Length = TimeSpan.FromSeconds(time),
|
||||
AnimationTracks =
|
||||
{
|
||||
new AnimationTrackSpriteFlick
|
||||
{
|
||||
LayerKey = layerKey,
|
||||
KeyFrames =
|
||||
{
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_00", 0),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_01", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_02", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_03", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_04", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_05", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_06", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_07", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_08", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_09", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_10", timestep),
|
||||
new AnimationTrackSpriteFlick.KeyFrame("turbinerun_11", timestep)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
_sprite.LayerSetVisible(layer, true);
|
||||
_animationPlayer.Play(uid, animation, state);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OnEjectAttempt(EntityUid uid, TurbineComponent comp, ref ItemSlotEjectAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (comp.RPM < 1)
|
||||
return;
|
||||
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnInsertAttempt(EntityUid uid, TurbineComponent comp, ref ItemSlotInsertAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (comp.RPM < 1)
|
||||
return;
|
||||
|
||||
args.Cancelled = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using Robust.Client.UserInterface;
|
||||
using JetBrains.Annotations;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
namespace Content.Client._FarHorizons.Power.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="NuclearReactorWindow"/> and updates it when new server messages are received.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed class NuclearReactorBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
[ViewVariables]
|
||||
private NuclearReactorWindow? _window;
|
||||
|
||||
public NuclearReactorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
EntityUid? reactorUid = null;
|
||||
if (_entityManager.TryGetComponent<NuclearReactorMonitorComponent>(Owner, out var reactorMonitorComponent))
|
||||
{
|
||||
if (!_entityManager.TryGetEntity(reactorMonitorComponent.reactor, out reactorUid) || reactorUid == null
|
||||
|| !_entityManager.TryGetComponent<NuclearReactorComponent>(reactorUid, out var monitoredReactorComponent) || monitoredReactorComponent.Melted)
|
||||
return;
|
||||
}
|
||||
else if (!_entityManager.TryGetComponent<NuclearReactorComponent>(Owner, out var reactorComponent) || reactorComponent.Melted)
|
||||
return;
|
||||
|
||||
base.Open();
|
||||
|
||||
_window = this.CreateWindow<NuclearReactorWindow>();
|
||||
if (_entityManager.EntityExists(reactorUid))
|
||||
_window.SetEntity(reactorUid.Value, Owner);
|
||||
else
|
||||
_window.SetEntity(Owner);
|
||||
|
||||
_window.ItemActionButtonPressed += OnActionButtonPressed;
|
||||
_window.EjectButtonPressed += OnEjectButtonPressed;
|
||||
_window.ControlRodModify += OnControlRodModify;
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
if (state is not NuclearReactorBuiState reactorState)
|
||||
return;
|
||||
|
||||
_window?.Update(reactorState);
|
||||
}
|
||||
|
||||
private void OnActionButtonPressed(Vector2d vector)
|
||||
{
|
||||
if (_window is null ) return;
|
||||
|
||||
SendPredictedMessage(new ReactorItemActionMessage(vector));
|
||||
}
|
||||
|
||||
private void OnEjectButtonPressed()
|
||||
{
|
||||
if (_window is null) return;
|
||||
|
||||
SendPredictedMessage(new ReactorEjectItemMessage());
|
||||
}
|
||||
|
||||
private void OnControlRodModify(float amount)
|
||||
{
|
||||
if (_window is null) return;
|
||||
|
||||
SendPredictedMessage(new ReactorControlRodModifyMessage(amount));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
MinSize="690 445" Title="Nuclear Reactor">
|
||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||
<!--Main Content-->
|
||||
<BoxContainer Name="MainContent" Orientation="Horizontal" VerticalExpand="True" Margin="4">
|
||||
|
||||
<!--Left Panel-->
|
||||
<BoxContainer Name="LeftPanel" Orientation="Vertical">
|
||||
|
||||
<!--Insert/remove controls-->
|
||||
<BoxContainer Name="Controls" Orientation="Vertical">
|
||||
<GridContainer Name="ControlGrid" Columns="3" Margin="2 2 2 2">
|
||||
<PanelContainer/>
|
||||
<Button Name="YDecrement" Disabled="true">
|
||||
<TextureRect SetSize="16 16" TextureScale="0.5 0.5" Margin="0 2 0 2"
|
||||
TexturePath="/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_part_inserted/arrow_up.png"/>
|
||||
</Button>
|
||||
<PanelContainer/>
|
||||
<Button Name="XDecrement" Disabled="true">
|
||||
<TextureRect SetSize="16 16" TextureScale="0.5 0.5" Margin="0 2 0 2"
|
||||
TexturePath="/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_part_inserted/arrow_left.png"/>
|
||||
</Button>
|
||||
<Label Name="TargetPos" Text="0,0" StyleClasses="LabelKeyText" HorizontalExpand="True" HorizontalAlignment="Center"/>
|
||||
<Button Name="XIncrement">
|
||||
<TextureRect SetSize="16 16" TextureScale="0.5 0.5" Margin="0 2 0 2"
|
||||
TexturePath="/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_part_inserted/arrow_right.png"/>
|
||||
</Button>
|
||||
<PanelContainer/>
|
||||
<Button Name="YIncrement">
|
||||
<TextureRect SetSize="16 16" TextureScale="0.5 0.5" Margin="0 2 0 2"
|
||||
TexturePath="/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_part_inserted/arrow_down.png"/>
|
||||
</Button>
|
||||
</GridContainer>
|
||||
<controls:StripeBack>
|
||||
<Button Name="ItemAction" Text="{Loc comp-nuclear-reactor-ui-insert-button}"/>
|
||||
<Label Name="ItemActionLock" Text="{Loc comp-nuclear-reactor-ui-locked}" Visible="false" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</controls:StripeBack>
|
||||
</BoxContainer>
|
||||
|
||||
<PanelContainer SetHeight="2" VerticalAlignment="Top" SetWidth="150" Margin="2 5" />
|
||||
|
||||
<!--Target info-->
|
||||
<BoxContainer Name="TargetData" Orientation="Vertical" VerticalExpand="True">
|
||||
<BoxContainer Name="TargetInfo" Orientation="Vertical">
|
||||
<Label Name="TargetName" Text="Rod" ClipText="True"/>
|
||||
<GridContainer Name="TargetTemperatureGrid" Columns="2" Margin="2 2 2 2">
|
||||
<Label Text="T: " StyleClasses="StatusFieldTitle" HorizontalExpand="True"/>
|
||||
<Button Name="TargetTemperature" Text="20C" HorizontalAlignment="Right"/>
|
||||
</GridContainer>
|
||||
<GridContainer Name="TargetNRadiationGrid" Columns="2" Margin="2 2 2 2">
|
||||
<Label Text="N: " StyleClasses="StatusFieldTitle" HorizontalExpand="True"/>
|
||||
<Label Name="TargetNRadiation" Text="0" HorizontalAlignment="Right"/>
|
||||
</GridContainer>
|
||||
<GridContainer Name="TargetRadiationGrid" Columns="2" Margin="2 2 2 2">
|
||||
<Label Text="R: " StyleClasses="StatusFieldTitle" HorizontalExpand="True"/>
|
||||
<Label Name="TargetRadiation" Text="0" HorizontalAlignment="Right"/>
|
||||
</GridContainer>
|
||||
<GridContainer Name="TargetSpentGrid" Columns="2" Margin="2 2 2 2">
|
||||
<Label Text="S: " StyleClasses="StatusFieldTitle" HorizontalExpand="True"/>
|
||||
<Label Name="TargetSpent" Text="0" HorizontalAlignment="Right"/>
|
||||
</GridContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!--"Shelf"-->
|
||||
<BoxContainer Name="Shelf" Orientation="Vertical">
|
||||
<Button Name="EjectItem" Text="{Loc comp-nuclear-reactor-ui-eject-button}" />
|
||||
<Label Name="ItemName" Text="empty" ClipText="True"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!--Reactor display-->
|
||||
<PanelContainer Name="GridVisuals" StyleClasses="Inset" HorizontalExpand="True" Margin="5 5 5 5">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Button Name="ChangeViewButton" Text="{Loc comp-nuclear-reactor-ui-view-change}"/>
|
||||
<Label Name="ViewLabel" Text="{Loc comp-nuclear-reactor-ui-view-temp}" StyleClasses="LabelKeyText" />
|
||||
<GridContainer Name="ReactorGrid" Columns="7" VerticalExpand="True" Margin="2 2 2 2">
|
||||
</GridContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
|
||||
<!--Right Panel-->
|
||||
<BoxContainer Name="RightPanel" Orientation="Vertical">
|
||||
<Label Name="StatusPanelLabel" Text="{Loc comp-nuclear-reactor-ui-status-panel}" StyleClasses="LabelKeyText" />
|
||||
|
||||
<BoxContainer Name="StatusIndicators" Orientation="Vertical">
|
||||
<BoxContainer Name="ReactorTemp" Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Label Name="ReactorTempLabel" Text="{Loc comp-nuclear-reactor-ui-reactor-temp}" StyleClasses="StatusFieldTitle" HorizontalExpand="True"/>
|
||||
<Label Name="ReactorTempValue" Text="20C" HorizontalAlignment="Right"/>
|
||||
</BoxContainer>
|
||||
<ProgressBar Name="ReactorTempBar" MaxValue="2000" SetSize="150 5" Margin="5" />
|
||||
|
||||
<PanelContainer SetHeight="2" VerticalAlignment="Top" SetWidth="200" Margin="2 5" />
|
||||
|
||||
<BoxContainer Name="ReactorRads" Orientation="Horizontal">
|
||||
<Label Name="ReactorRadsLabel" Text="{Loc comp-nuclear-reactor-ui-reactor-rads}" StyleClasses="StatusFieldTitle" HorizontalExpand="True"/>
|
||||
<Label Name="ReactorRadsValue" Text="0" HorizontalAlignment="Right"/>
|
||||
</BoxContainer>
|
||||
<ProgressBar Name="ReactorRadsBar" MaxValue="50" SetSize="150 5" Margin="5" />
|
||||
|
||||
<PanelContainer SetHeight="2" VerticalAlignment="Top" SetWidth="200" Margin="2 5" />
|
||||
|
||||
<BoxContainer Name="ReactorTherm" Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Label Name="ReactorThermLabel" Text="{Loc comp-nuclear-reactor-ui-reactor-therm}" StyleClasses="StatusFieldTitle" HorizontalExpand="True"/>
|
||||
<Label Name="ReactorThermValue" Text="0" HorizontalAlignment="Right"/>
|
||||
</BoxContainer>
|
||||
<ProgressBar Name="ReactorThermBar" MaxValue="10000000" SetSize="150 5" Margin="5" />
|
||||
|
||||
<PanelContainer SetHeight="2" VerticalAlignment="Top" SetWidth="200" Margin="2 5" />
|
||||
|
||||
|
||||
<BoxContainer Name="ControlRodsText" Orientation="Horizontal">
|
||||
<Label Name="ControlRodsLabel" Text="{Loc comp-nuclear-reactor-ui-reactor-control}" StyleClasses="StatusFieldTitle" HorizontalExpand="True"/>
|
||||
<Label Name="ControlRodsValue" Text="100%" HorizontalAlignment="Right"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Name="ControlRods" Orientation="Horizontal">
|
||||
<ProgressBar Name="ControlRodsActual" MaxValue="2" SetSize="5 100" Margin="5" Vertical="True" />
|
||||
<ProgressBar Name="ControlRodsSet" MaxValue="2" SetSize="5 100" Margin="5" Vertical="True" />
|
||||
<controls:StripeBack>
|
||||
<BoxContainer Name="ControlRodsButtons" Orientation="Vertical">
|
||||
<Button Name="ControlRodsInsertLarge" Text="+ +"/>
|
||||
<Button Name="ControlRodsInsert" Text=" + "/>
|
||||
<Button Name="ControlRodsRemove" Text=" - "/>
|
||||
<Button Name="ControlRodsRemoveLarge" Text="- -"/>
|
||||
</BoxContainer>
|
||||
<Label Name="ControlRodsLock" Text="{Loc comp-nuclear-reactor-ui-locked}" Visible="false" HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</controls:StripeBack>
|
||||
</BoxContainer>
|
||||
|
||||
</BoxContainer>
|
||||
|
||||
</BoxContainer>
|
||||
|
||||
</BoxContainer>
|
||||
|
||||
<!--Footer-->
|
||||
<BoxContainer Name="Footer" Orientation="Vertical">
|
||||
<PanelContainer StyleClasses="LowDivider" />
|
||||
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
|
||||
<Label Text="{Loc comp-nuclear-reactor-ui-footer-left}" StyleClasses="WindowFooterText" />
|
||||
<Label Text="{Loc comp-nuclear-reactor-ui-footer-right}" StyleClasses="WindowFooterText"
|
||||
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
|
||||
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
@@ -0,0 +1,402 @@
|
||||
using System.IO;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Lock;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Client._FarHorizons.Power.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Client-side UI used to view a nuclear reactor.
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class NuclearReactorWindow : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = null!;
|
||||
private readonly LockSystem _lock;
|
||||
|
||||
private readonly Dictionary<Vector2i, StyleBoxFlat> _reactorGrid = [];
|
||||
private readonly Dictionary<Vector2i, TextureRect> _reactorRect = [];
|
||||
private readonly Dictionary<Vector2i, Button> _reactorButton = [];
|
||||
|
||||
private readonly StyleBoxFlat _temperatureBar = new(Color.Black);
|
||||
private readonly StyleBoxFlat _radiationBar = new(Color.Black);
|
||||
private readonly StyleBoxFlat _powerBar = new(Color.Black);
|
||||
|
||||
private Dictionary<Vector2i, ReactorSlotBUIData> _data = [];
|
||||
private int _gridWidth = 0;
|
||||
private int _gridHeight = 0;
|
||||
|
||||
private byte _displayMode = 1<<0;
|
||||
|
||||
private enum DisplayModes : byte
|
||||
{
|
||||
Temperature = 1 << 0,
|
||||
Neutron = 1 << 1,
|
||||
Target = 1 << 2,
|
||||
Fuel = 1 << 3
|
||||
}
|
||||
|
||||
private byte _temperatureMode = 1 << 0;
|
||||
|
||||
private enum TemperatureModes : byte
|
||||
{
|
||||
Celcius = 1 << 0,
|
||||
Kelvin = 1 << 1,
|
||||
// Fahrenheit = 1 << 2
|
||||
}
|
||||
|
||||
private int _targetX = 0;
|
||||
private int _targetY = 0;
|
||||
|
||||
public event Action<Vector2d>? ItemActionButtonPressed;
|
||||
public event Action? EjectButtonPressed;
|
||||
|
||||
public event Action<float>? ControlRodModify;
|
||||
|
||||
private EntityUid _reactor;
|
||||
|
||||
private bool _isMonitor = false;
|
||||
private EntityUid _monitor;
|
||||
|
||||
private readonly float _repeatDelay = 0.5f;
|
||||
private readonly Dictionary<Button, float> _repeatQueue = [];
|
||||
|
||||
public NuclearReactorWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_lock = _entityManager.System<LockSystem>();
|
||||
|
||||
ReactorTempBar.ForegroundStyleBoxOverride = _temperatureBar;
|
||||
ReactorRadsBar.ForegroundStyleBoxOverride = _radiationBar;
|
||||
ReactorThermBar.ForegroundStyleBoxOverride = _powerBar;
|
||||
|
||||
ChangeViewButton.OnPressed += _ => OnChangeViewButtonPressed();
|
||||
XIncrement.OnPressed += _ => MoveTarget(1, 0);
|
||||
XDecrement.OnPressed += _ => MoveTarget(-1, 0);
|
||||
YIncrement.OnPressed += _ => MoveTarget(0, 1);
|
||||
YDecrement.OnPressed += _ => MoveTarget(0, -1);
|
||||
ItemAction.OnPressed += _ => ItemActionButtonPressed?.Invoke(new(_targetY, _targetX));
|
||||
EjectItem.OnPressed += _ => EjectButtonPressed?.Invoke();
|
||||
|
||||
ControlRodsInsertLarge.OnPressed += _ => AdjustControlRods(0.1f);
|
||||
ControlRodsInsertLarge.OnButtonDown += _ => _repeatQueue.Add(ControlRodsInsertLarge, _repeatDelay);
|
||||
ControlRodsInsertLarge.OnButtonUp += _ => _repeatQueue.Remove(ControlRodsInsertLarge);
|
||||
|
||||
ControlRodsInsert.OnPressed += _ => AdjustControlRods(0.01f);
|
||||
ControlRodsInsert.OnButtonDown += _ => _repeatQueue.Add(ControlRodsInsert, _repeatDelay);
|
||||
ControlRodsInsert.OnButtonUp += _ => _repeatQueue.Remove(ControlRodsInsert);
|
||||
|
||||
ControlRodsRemove.OnPressed += _ => AdjustControlRods(-0.01f);
|
||||
ControlRodsRemove.OnButtonDown += _ => _repeatQueue.Add(ControlRodsRemove, _repeatDelay);
|
||||
ControlRodsRemove.OnButtonUp += _ => _repeatQueue.Remove(ControlRodsRemove);
|
||||
|
||||
ControlRodsRemoveLarge.OnPressed += _ => AdjustControlRods(-0.1f);
|
||||
ControlRodsRemoveLarge.OnButtonDown += _ => _repeatQueue.Add(ControlRodsRemoveLarge, _repeatDelay);
|
||||
ControlRodsRemoveLarge.OnButtonUp += _ => _repeatQueue.Remove(ControlRodsRemoveLarge);
|
||||
|
||||
TargetTemperature.OnPressed += _ => ChangeTemp();
|
||||
}
|
||||
|
||||
public void Update(NuclearReactorBuiState msg)
|
||||
{
|
||||
_data = msg.SlotData;
|
||||
|
||||
ReactorTempValue.Text = FormatTemperature(msg.ReactorTemp);
|
||||
ReactorTempBar.Value = msg.ReactorTemp;
|
||||
_temperatureBar.BackgroundColor = GetColor(Atmospherics.T20C, ReactorTempBar.MaxValue * 0.75, msg.ReactorTemp);
|
||||
|
||||
ReactorRadsValue.Text = msg.ReactorRads <= msg.ReactorRadsMax ? Math.Round(msg.ReactorRads, 1).ToString() : "OVERLOAD";
|
||||
ReactorRadsBar.Value = msg.ReactorRads;
|
||||
_radiationBar.BackgroundColor = GetColor(0, ReactorRadsBar.MaxValue * 0.5, msg.ReactorRads);
|
||||
|
||||
ReactorThermValue.Text = FormatPower(msg.ReactorTherm);
|
||||
ReactorThermBar.Value = msg.ReactorTherm;
|
||||
_powerBar.BackgroundColor = GetSteppedColor(ReactorThermBar.MaxValue * 0.75, ReactorThermBar.MaxValue, msg.ReactorTherm);
|
||||
|
||||
ControlRodsValue.Text = Math.Round(msg.ControlRodActual * 50, 1).ToString() + "%";
|
||||
ControlRodsActual.Value = msg.ControlRodActual;
|
||||
ControlRodsSet.Value = msg.ControlRodSet;
|
||||
|
||||
var locktarget = _isMonitor ? _monitor : _reactor;
|
||||
|
||||
ControlRodsButtons.Visible = !_lock.IsLocked(locktarget);
|
||||
ItemAction.Visible = !_lock.IsLocked(_reactor) && !_isMonitor;
|
||||
|
||||
ItemActionLock.Visible = _lock.IsLocked(_reactor) && !_isMonitor;
|
||||
ControlRodsLock.Visible = _lock.IsLocked(locktarget);
|
||||
|
||||
Shelf.Visible = !_isMonitor;
|
||||
|
||||
ItemName.Text = msg.ItemName ?? "empty";
|
||||
}
|
||||
|
||||
public void SetEntity(EntityUid reactor, EntityUid? monitor = null)
|
||||
{
|
||||
_reactor = reactor;
|
||||
|
||||
if (monitor != null)
|
||||
{
|
||||
_monitor = monitor.Value;
|
||||
_isMonitor = true;
|
||||
}
|
||||
|
||||
this.SetInfoFromEntity(_entityManager, _isMonitor ? _monitor : _reactor);
|
||||
|
||||
if (!_entityManager.TryGetComponent<NuclearReactorComponent>(_reactor, out var reactorComponent))
|
||||
return;
|
||||
|
||||
_gridWidth = reactorComponent.ReactorGridWidth;
|
||||
_gridHeight = reactorComponent.ReactorGridHeight;
|
||||
|
||||
ReactorGrid.Columns = _gridWidth;
|
||||
|
||||
ReactorTempBar.MaxValue = reactorComponent.ReactorMeltdownTemp;
|
||||
ReactorRadsBar.MaxValue = reactorComponent.MaximumRadiation;
|
||||
ReactorThermBar.MaxValue = reactorComponent.MaximumThermalPower;
|
||||
|
||||
InitReactorGrid();
|
||||
}
|
||||
|
||||
public void InitReactorGrid()
|
||||
{
|
||||
for (var x = 0; x < _gridWidth; x++)
|
||||
{
|
||||
for (var y = 0; y < _gridHeight; y++)
|
||||
{
|
||||
var styleBox = new StyleBoxFlat();
|
||||
var icon = new TextureRect()
|
||||
{
|
||||
SetSize = new(32, 32),
|
||||
TexturePath = "/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_part_inserted/base.png"
|
||||
};
|
||||
var button = new Button
|
||||
{
|
||||
Margin = new(0),
|
||||
StyleBoxOverride = new StyleBoxFlat(Color.Transparent),
|
||||
ToolTip = "",
|
||||
TooltipDelay = 0.5f
|
||||
};
|
||||
|
||||
var vect = new Vector2i(x, y);
|
||||
_reactorGrid.Add(vect, styleBox);
|
||||
_reactorRect.Add(vect, icon);
|
||||
_reactorButton.Add(vect, button);
|
||||
|
||||
var control = new PanelContainer
|
||||
{
|
||||
Margin = new Thickness(2),
|
||||
PanelOverride = styleBox,
|
||||
HorizontalExpand = true,
|
||||
VerticalExpand = true,
|
||||
};
|
||||
control.AddChild(button);
|
||||
var nvect = new Vector2i(y, x); // Can't be declared as a part of the line below for some reason, will break if you try
|
||||
button.OnPressed += _ => SetTarget(nvect);
|
||||
button.AddChild(icon);
|
||||
ReactorGrid.AddChild(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
//Update the grid
|
||||
for (var x = 0; x < _gridWidth; x++)
|
||||
{
|
||||
for (var y = 0; y < _gridHeight; y++)
|
||||
{
|
||||
var vect = new Vector2i(x, y);
|
||||
var exists = _data.ContainsKey(vect);
|
||||
var box = _reactorGrid[vect];
|
||||
switch (_displayMode)
|
||||
{
|
||||
case (byte)DisplayModes.Temperature:
|
||||
box.BackgroundColor = GetColor(293.15, 1200, exists ? _data[vect].Temperature : 0);
|
||||
ViewLabel.Text = Loc.GetString("comp-nuclear-reactor-ui-view-temp");
|
||||
break;
|
||||
case (byte)DisplayModes.Neutron:
|
||||
box.BackgroundColor = GetColor(0, 7, exists ? _data[vect].NeutronCount : 0);
|
||||
ViewLabel.Text = Loc.GetString("comp-nuclear-reactor-ui-view-neutron");
|
||||
break;
|
||||
case (byte)DisplayModes.Target:
|
||||
box.BackgroundColor = y == _targetX && x == _targetY ? Color.Yellow : Color.Gray;
|
||||
ViewLabel.Text = Loc.GetString("comp-nuclear-reactor-ui-view-target");
|
||||
break;
|
||||
case (byte)DisplayModes.Fuel:
|
||||
box.BackgroundColor = Color.InterpolateBetween(Color.Gray, Color.FromHex("#22bbff"), exists && _data[vect].SpentFuel > 0 ? (float)GetFuelLevel(_data[vect]) : 0);
|
||||
ViewLabel.Text = Loc.GetString("comp-nuclear-reactor-ui-view-fuel");
|
||||
break;
|
||||
}
|
||||
|
||||
var icon = exists ? _data[vect].IconName : "base";
|
||||
_reactorRect[vect].TexturePath = "/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_part_inserted/" + icon + ".png";
|
||||
|
||||
_reactorButton[vect].ToolTip = exists && _data[vect].SpentFuel > 0
|
||||
? "Fuel Level: " + (int)Math.Round(GetFuelLevel(_data[vect]) * 100) + "%"
|
||||
: "";
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTargetInfo();
|
||||
UpdateItemAction();
|
||||
|
||||
// Handle repeat buttons
|
||||
foreach ( var kvp in _repeatQueue)
|
||||
{
|
||||
if(kvp.Value > 0)
|
||||
{
|
||||
_repeatQueue[kvp.Key] -= args.DeltaSeconds;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (kvp.Key)
|
||||
{
|
||||
case var _ when kvp.Key == ControlRodsInsertLarge:
|
||||
AdjustControlRods(0.1f);
|
||||
break;
|
||||
case var _ when kvp.Key == ControlRodsInsert:
|
||||
AdjustControlRods(0.01f);
|
||||
break;
|
||||
case var _ when kvp.Key == ControlRodsRemove:
|
||||
AdjustControlRods(-0.01f);
|
||||
break;
|
||||
case var _ when kvp.Key == ControlRodsRemoveLarge:
|
||||
AdjustControlRods(-0.1f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Color GetColor(double pointA, double pointB, double value)
|
||||
{
|
||||
var mid = pointA+((pointB-pointA) / 2);
|
||||
Color result;
|
||||
|
||||
if (value < pointA && pointA > 0)
|
||||
result = Color.InterpolateBetween(Color.DarkBlue, Color.FromHex("#31843E"), (float)(value / pointA));
|
||||
else if (value >= pointA && value < mid)
|
||||
result = Color.InterpolateBetween(Color.FromHex("#31843E"), Color.FromHex("#BBBB00"), (float)((value - pointA) / (mid - pointA)));
|
||||
else if (value >= mid && value < pointB)
|
||||
result = Color.InterpolateBetween(Color.FromHex("#BBBB00"), Color.FromHex("#BB3232"), (float)((value - mid) / (pointB - mid)));
|
||||
else if (value >= pointB && value < pointB * 1.4)
|
||||
result = Color.InterpolateBetween(Color.FromHex("#BB3232"), Color.FromHex("#550000"), (float)((value - pointB) / ((pointB * 1.4) - pointB)));
|
||||
else if (value >= pointB * 1.4)
|
||||
result = Color.FromHex("#550000"); // Death.
|
||||
else
|
||||
result = Color.Black;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Color GetSteppedColor(double pointA, double pointB, double value)
|
||||
{
|
||||
Color result;
|
||||
|
||||
if (value > pointB)
|
||||
result = Color.FromHex("#BB3232");
|
||||
else if (value > pointA)
|
||||
result = Color.FromHex("#BBBB00");
|
||||
else
|
||||
result = Color.FromHex("#31843E");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void OnChangeViewButtonPressed()
|
||||
{
|
||||
// The bits go marching one by one...
|
||||
_displayMode <<= 1;
|
||||
if (_displayMode >= 1 << Enum.GetNames<DisplayModes>().Length)
|
||||
_displayMode = 1 << 0;
|
||||
}
|
||||
|
||||
private void ChangeTemp()
|
||||
{
|
||||
_temperatureMode <<= 1;
|
||||
if (_temperatureMode >= 1 << Enum.GetNames<TemperatureModes>().Length)
|
||||
_temperatureMode = 1 << 0;
|
||||
}
|
||||
|
||||
private string FormatTemperature(double temperature) => _temperatureMode switch
|
||||
{
|
||||
(byte)TemperatureModes.Celcius => Math.Round(temperature - Atmospherics.T0C, 1).ToString() + "C",
|
||||
(byte)TemperatureModes.Kelvin => Math.Round(temperature, 1).ToString() + "K",
|
||||
// (byte)TemperatureModes.Fahrenheit => Math.Round(((temperature - Atmospherics.T0C) * 9 / 5) + 32, 1).ToString() + "F",
|
||||
_ => "NaN",
|
||||
};
|
||||
|
||||
private void UpdateTargetInfo()
|
||||
{
|
||||
var vect = new Vector2i(_targetY, _targetX);
|
||||
if(!_data.TryGetValue(vect, out var value))
|
||||
{
|
||||
TargetName.Text = "empty";
|
||||
TargetTemperatureGrid.Visible = TargetNRadiationGrid.Visible = TargetRadiationGrid.Visible = TargetSpentGrid.Visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
TargetName.Text = value.PartName;
|
||||
|
||||
TargetTemperatureGrid.Visible = value.Temperature > 0;
|
||||
TargetTemperature.Text = FormatTemperature(value.Temperature);
|
||||
|
||||
TargetNRadiationGrid.Visible = value.NeutronRadioactivity > 0;
|
||||
TargetNRadiation.Text = Math.Round(value.NeutronRadioactivity, 2).ToString();
|
||||
|
||||
TargetRadiationGrid.Visible = value.Radioactivity > 0;
|
||||
TargetRadiation.Text = Math.Round(value.Radioactivity, 2).ToString();
|
||||
|
||||
TargetSpentGrid.Visible = value.SpentFuel > 0;
|
||||
TargetSpent.Text = Math.Round(value.SpentFuel, 2).ToString();
|
||||
}
|
||||
|
||||
private void UpdateItemAction()
|
||||
{
|
||||
if(ItemName.Text == "empty" == (TargetName.Text == "empty"))
|
||||
{
|
||||
ItemAction.Disabled = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
ItemAction.Disabled = false;
|
||||
|
||||
ItemAction.Text = TargetName.Text != "empty"
|
||||
? Loc.GetString("comp-nuclear-reactor-ui-remove-button")
|
||||
: Loc.GetString("comp-nuclear-reactor-ui-insert-button");
|
||||
}
|
||||
|
||||
private void MoveTarget(int x, int y) => SetTarget(_targetX + x, _targetY + y);
|
||||
|
||||
private void SetTarget(Vector2i vect) => SetTarget(vect.X, vect.Y);
|
||||
|
||||
private void SetTarget(int x, int y)
|
||||
{
|
||||
_targetX = Math.Clamp(x, 0, _gridWidth - 1);
|
||||
_targetY = Math.Clamp(y, 0, _gridHeight - 1);
|
||||
|
||||
TargetPos.Text = _targetX.ToString() +"," + _targetY.ToString();
|
||||
|
||||
XIncrement.Disabled = _targetX >= _gridWidth - 1;
|
||||
XDecrement.Disabled = _targetX <= 0;
|
||||
YIncrement.Disabled = _targetY >= _gridHeight - 1;
|
||||
YDecrement.Disabled = _targetY <= 0;
|
||||
}
|
||||
|
||||
public void SetItemName(string? itemName) => ItemName.Text = itemName ?? "empty";
|
||||
|
||||
private static string FormatPower(float power) => Loc.GetString("comp-nuclear-reactor-ui-therm-format", ("power", power));
|
||||
|
||||
private static double GetFuelLevel(ReactorSlotBUIData data) => Math.Max(1 - (data.SpentFuel / (data.SpentFuel + (data.Radioactivity * 0.5) + (data.NeutronRadioactivity * 0.25))), 0);
|
||||
|
||||
private void AdjustControlRods(float amount) => ControlRodModify?.Invoke(amount);
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.Timing;
|
||||
using JetBrains.Annotations;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Client.UserInterface;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Client._FarHorizons.Power.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a <see cref="TurbineWindow"/> and updates it when new server messages are received.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed class TurbineBoundUserInterface : BoundUserInterface, IBuiPreTickUpdate
|
||||
{
|
||||
[Dependency] private readonly IClientGameTiming _gameTiming = null!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = null!;
|
||||
|
||||
[ViewVariables]
|
||||
private TurbineWindow? _window;
|
||||
|
||||
private BuiPredictionState? _pred;
|
||||
private InputCoalescer<float> _flowRateCoalescer;
|
||||
private InputCoalescer<float> _statorLoadCoalescer;
|
||||
|
||||
public TurbineBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
EntityUid? turbineUid = null;
|
||||
if (_entityManager.TryGetComponent<GasTurbineMonitorComponent>(Owner, out var turbineMonitorComponent))
|
||||
if (!_entityManager.TryGetEntity(turbineMonitorComponent.turbine, out turbineUid) || turbineUid == null
|
||||
|| !_entityManager.HasComponent<TurbineComponent>(turbineUid))
|
||||
return;
|
||||
|
||||
base.Open();
|
||||
|
||||
_pred = new BuiPredictionState(this, _gameTiming);
|
||||
|
||||
_window = this.CreateWindow<TurbineWindow>();
|
||||
if (_entityManager.EntityExists(turbineUid))
|
||||
_window.SetEntity(turbineUid.Value, Owner);
|
||||
else
|
||||
_window.SetEntity(Owner);
|
||||
|
||||
_window.TurbineFlowRateChanged += val => _flowRateCoalescer.Set(val);
|
||||
_window.TurbineStatorLoadChanged += val => _statorLoadCoalescer.Set(val);
|
||||
Update();
|
||||
}
|
||||
|
||||
void IBuiPreTickUpdate.PreTickUpdate()
|
||||
{
|
||||
if (_flowRateCoalescer.CheckIsModified(out var flowRateValue))
|
||||
_pred!.SendMessage(new TurbineChangeFlowRateMessage(flowRateValue));
|
||||
|
||||
if (_statorLoadCoalescer.CheckIsModified(out var statorLoadValue))
|
||||
_pred!.SendMessage(new TurbineChangeStatorLoadMessage(statorLoadValue));
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
if (state is not TurbineBuiState turbineState)
|
||||
return;
|
||||
|
||||
if (!_entityManager.TryGetComponent<TurbineComponent>(Owner, out var comp))
|
||||
if(!TryGetTurbineComp(Owner, out comp))
|
||||
return;
|
||||
|
||||
foreach (var replayMsg in _pred!.MessagesToReplay())
|
||||
{
|
||||
switch (replayMsg)
|
||||
{
|
||||
case TurbineChangeFlowRateMessage setFlowRate:
|
||||
turbineState.FlowRate = Math.Clamp(setFlowRate.FlowRate, 0f, comp.FlowRateMax);
|
||||
break;
|
||||
|
||||
case TurbineChangeStatorLoadMessage setStatorLoad:
|
||||
turbineState.StatorLoad = Math.Max(setStatorLoad.StatorLoad, 1000f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_window?.Update(turbineState);
|
||||
}
|
||||
|
||||
public bool TryGetTurbineComp(EntityUid uid, [NotNullWhen(true)] out TurbineComponent? turbineComponent)
|
||||
{
|
||||
turbineComponent = null;
|
||||
if (!_entityManager.TryGetComponent<GasTurbineMonitorComponent>(uid, out var turbineMonitor))
|
||||
return false;
|
||||
|
||||
if (!_entityManager.TryGetEntity(turbineMonitor.turbine, out var turbineUid) || turbineUid == null)
|
||||
return false;
|
||||
|
||||
if (!_entityManager.TryGetComponent<TurbineComponent>(turbineUid, out var turbine))
|
||||
return false;
|
||||
|
||||
turbineComponent = turbine;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
MinSize="525 415" Title="Gas Turbine">
|
||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||
<TabContainer Name="CTabContainer" VerticalExpand="True" Margin="1 1 1 2">
|
||||
<!--Main Content-->
|
||||
<BoxContainer Name="MainContent" Orientation="Horizontal" VerticalExpand="True" Margin="4">
|
||||
|
||||
<!--View of turbine sprite-->
|
||||
<BoxContainer Name="TurbineVeiw" Orientation="Horizontal" VerticalExpand="True" Margin="4">
|
||||
<SpriteView Name="EntityView" SetSize="96 160" Scale="2 2" OverrideDirection="South" Margin="15" />
|
||||
</BoxContainer>
|
||||
|
||||
<!--RPM gauge-->
|
||||
<PanelContainer Name="Speed" StyleClasses="Inset">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Text="{Loc 'comp-turbine-ui-rpm'}" StyleClasses="LabelKeyText" />
|
||||
<GridContainer Name="RPMMeter" Columns="1" VerticalExpand="True" Margin="0 0 0 0">
|
||||
</GridContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
|
||||
|
||||
<!--Right panel-->
|
||||
<BoxContainer Name="RightPanel" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10" HorizontalExpand="True" VerticalExpand="True">
|
||||
<!--Indicator Lights-->
|
||||
<PanelContainer Name="Indicators" StyleClasses="Inset">
|
||||
<GridContainer Columns="4">
|
||||
<Label Text="{Loc 'comp-turbine-ui-overspeed'}" StyleClasses="StatusFieldTitle" />
|
||||
<TextureRect Name="TurbineOverspeed" SetSize="16 16" HorizontalAlignment="Left" HorizontalExpand="True"/>
|
||||
<Label Text="{Loc 'comp-turbine-ui-overtemp'}" StyleClasses="StatusFieldTitle" />
|
||||
<TextureRect Name="TurbineOvertemp" SetSize="16 16" HorizontalAlignment="Left" HorizontalExpand="True"/>
|
||||
<Label Text="{Loc 'comp-turbine-ui-stalling'}" StyleClasses="StatusFieldTitle" />
|
||||
<TextureRect Name="TurbineStalling" SetSize="16 16" HorizontalAlignment="Left" HorizontalExpand="True"/>
|
||||
<Label Text="{Loc 'comp-turbine-ui-undertemp'}" StyleClasses="StatusFieldTitle" />
|
||||
<TextureRect Name="TurbineUndertemp" SetSize="16 16" HorizontalAlignment="Left" HorizontalExpand="True"/>
|
||||
</GridContainer>
|
||||
</PanelContainer>
|
||||
|
||||
<!--Inputs-->
|
||||
<controls:StripeBack VerticalExpand="True">
|
||||
<BoxContainer Name="Inputs" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10" HorizontalExpand="True" >
|
||||
<PanelContainer StyleClasses="Inset" Margin="0 0 0 8">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc comp-turbine-ui-flow-rate}" StyleClasses="StatusFieldTitle" HorizontalExpand="True" />
|
||||
<LineEdit Name="TurbineFlowRateLabel" MinSize="70 0"/>
|
||||
</BoxContainer>
|
||||
<Slider Name="TurbineFlowRateSlider" />
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Button Name="FlowRateDecrease" Text="-100"/>
|
||||
<BoxContainer HorizontalExpand="True" />
|
||||
<Button Name="FlowRateIncrease" Text="+100"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
|
||||
<PanelContainer StyleClasses="Inset" Margin="0 0 0 8">
|
||||
<BoxContainer Orientation="Vertical" >
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Label Text="{Loc comp-turbine-ui-stator-load}" StyleClasses="StatusFieldTitle" HorizontalExpand="True" />
|
||||
<LineEdit Name="TurbineStatorLoadLabel" MinSize="70 0"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<Button Name="StatorLoadDecreaseLarge" Text="-1000"/>
|
||||
<Button Name="StatorLoadDecrease" Text="-100"/>
|
||||
<BoxContainer HorizontalExpand="True" />
|
||||
<Button Name="StatorLoadIncrease" Text="+100"/>
|
||||
<Button Name="StatorLoadIncreaseLarge" Text="+1000"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
<Label Name="LockedMessage" Text="{Loc comp-turbine-ui-locked-message}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</controls:StripeBack>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!--Blade / Stator info-->
|
||||
<BoxContainer Name="PartInfo" Orientation="Horizontal" VerticalExpand="True" Margin="4">
|
||||
<PanelContainer StyleClasses="Inset" HorizontalExpand="True" Margin="4">
|
||||
<TextureRect Name="BladeTexture" SetSize="128 128" TextureScale="2 2" HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
TexturePath="/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/turbine_parts/blade.png"/>
|
||||
|
||||
<BoxContainer Name="BladeInfo" Orientation="Vertical" HorizontalExpand="True" Margin="4">
|
||||
<Label Name="BladeInfoName" Text="{Loc 'comp-turbine-ui-blade'}" StyleClasses="LabelKeyText" HorizontalAlignment="Center" HorizontalExpand="True"/>
|
||||
|
||||
<SpriteView Name="BladeEntityView" SetSize="128 128" Scale="2 2" OverrideDirection="South" Margin="15" />
|
||||
<BoxContainer VerticalExpand="True"/>
|
||||
|
||||
<GridContainer Columns="2">
|
||||
<Label Text="{Loc 'comp-turbine-ui-blade-integrity'}" StyleClasses="StatusFieldTitle" />
|
||||
<Label Name="BladeInfoIntegrity" Text="100%" HorizontalAlignment="Right" HorizontalExpand="True"/>
|
||||
<Label Text="{Loc 'comp-turbine-ui-blade-stress'}" StyleClasses="StatusFieldTitle" />
|
||||
<Label Name="BladeInfoStress" Text="0%" HorizontalAlignment="Right" HorizontalExpand="True"/>
|
||||
</GridContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
|
||||
<PanelContainer StyleClasses="Inset" HorizontalExpand="True" Margin="4">
|
||||
<TextureRect Name="StatorTexture" SetSize="128 128" TextureScale="2 2" HorizontalAlignment="Center"
|
||||
TexturePath="/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/turbine_parts/stator.png"/>
|
||||
|
||||
<BoxContainer Name="StatorInfo" Orientation="Vertical" HorizontalExpand="True" Margin="4">
|
||||
<Label Name="StatorInfoName" Text="{Loc 'comp-turbine-ui-stator'}" StyleClasses="LabelKeyText" HorizontalAlignment="Center" HorizontalExpand="True"/>
|
||||
|
||||
<SpriteView Name="StatorEntityView" SetSize="128 128" Scale="2 2" OverrideDirection="South" Margin="15" />
|
||||
<BoxContainer VerticalExpand="True"/>
|
||||
|
||||
<GridContainer Columns="2">
|
||||
<Label Text="{Loc 'comp-turbine-ui-stator-potential'}" StyleClasses="StatusFieldTitle" />
|
||||
<Label Name="StatorInfoPotential" Text="0.0 W" HorizontalAlignment="Right" HorizontalExpand="True"/>
|
||||
<Label Text="{Loc 'comp-turbine-ui-stator-supply'}" StyleClasses="StatusFieldTitle" />
|
||||
<Label Name="StatorInfoSupply" Text="0.0 W" HorizontalAlignment="Right" HorizontalExpand="True"/>
|
||||
</GridContainer>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
|
||||
</TabContainer>
|
||||
<!--Footer-->
|
||||
<BoxContainer Name="Footer" Orientation="Vertical">
|
||||
<PanelContainer StyleClasses="LowDivider" />
|
||||
<BoxContainer Orientation="Horizontal" Margin="10 2 5 0" VerticalAlignment="Bottom">
|
||||
<Label Text="{Loc comp-turbine-ui-footer-left}" StyleClasses="WindowFooterText" />
|
||||
<Label Text="{Loc comp-turbine-ui-footer-right}" StyleClasses="WindowFooterText"
|
||||
HorizontalAlignment="Right" HorizontalExpand="True" Margin="0 0 5 0" />
|
||||
<TextureRect StyleClasses="NTLogoDark" Stretch="KeepAspectCentered"
|
||||
VerticalAlignment="Center" HorizontalAlignment="Right" SetSize="19 19" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
@@ -0,0 +1,298 @@
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Rounding;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Client._FarHorizons.Power.UI;
|
||||
|
||||
/// <summary>
|
||||
/// Client-side UI used to control a turbine.
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class TurbineWindow : FancyWindow
|
||||
{
|
||||
// Dependencies
|
||||
[Dependency] private readonly IEntityManager _entityManager = null!;
|
||||
private readonly LockSystem _lock;
|
||||
|
||||
#region Variables
|
||||
//Colors for the RPM meter. (lit)
|
||||
private static readonly Color[] _speedColors = [
|
||||
Color.FromHex("#BB3232"),
|
||||
Color.FromHex("#BB3232"),
|
||||
Color.FromHex("#BB3232"),
|
||||
Color.FromHex("#C49438"),
|
||||
Color.FromHex("#C49438"),
|
||||
Color.FromHex("#C49438"),
|
||||
Color.FromHex("#B3BF28"),
|
||||
Color.FromHex("#B3BF28"),
|
||||
Color.FromHex("#B3BF28"),
|
||||
Color.FromHex("#6FC938"),
|
||||
Color.FromHex("#C49438"),
|
||||
Color.FromHex("#BB3232"),
|
||||
];
|
||||
|
||||
//Colors for the RPM meter. (unlit)
|
||||
private static readonly Color[] _speedColorsDim =
|
||||
[
|
||||
DimGaugeColor(_speedColors[0]),
|
||||
DimGaugeColor(_speedColors[1]),
|
||||
DimGaugeColor(_speedColors[2]),
|
||||
DimGaugeColor(_speedColors[3]),
|
||||
DimGaugeColor(_speedColors[4]),
|
||||
DimGaugeColor(_speedColors[5]),
|
||||
DimGaugeColor(_speedColors[6]),
|
||||
DimGaugeColor(_speedColors[7]),
|
||||
DimGaugeColor(_speedColors[8]),
|
||||
DimGaugeColor(_speedColors[9]),
|
||||
DimGaugeColor(_speedColors[10]),
|
||||
DimGaugeColor(_speedColors[11]),
|
||||
];
|
||||
|
||||
// Style boxes for the RPM meter.
|
||||
private StyleBoxFlat[] _speedMeter;
|
||||
|
||||
private int _speedLevel;
|
||||
private float _flowRate = 0;
|
||||
private float _statorLevel = 0;
|
||||
|
||||
private EntityUid _turbine;
|
||||
|
||||
private bool _isMonitor = false;
|
||||
private EntityUid _monitor;
|
||||
|
||||
private bool _suppressSliderEvents;
|
||||
private bool _suppressStatorUpdate;
|
||||
private bool _suppressFlowUpdate;
|
||||
|
||||
private readonly float _repeatDelay = 0.5f;
|
||||
private readonly Dictionary<Button, float> _repeatQueue = [];
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public event Action<float>? TurbineFlowRateChanged;
|
||||
public event Action<float>? TurbineStatorLoadChanged;
|
||||
#endregion
|
||||
|
||||
public TurbineWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_lock = _entityManager.System<LockSystem>();
|
||||
|
||||
InitRPMMeter();
|
||||
|
||||
// Handle flow rate
|
||||
TurbineFlowRateLabel.OnFocusEnter += _ => _suppressFlowUpdate = true;
|
||||
TurbineFlowRateLabel.OnFocusExit += _ => FlowTextChanged();
|
||||
TurbineFlowRateLabel.OnTextEntered += _ => FlowTextChanged(true);
|
||||
|
||||
TurbineFlowRateSlider.OnValueChanged += _ =>
|
||||
{
|
||||
if (!_suppressSliderEvents)
|
||||
TurbineFlowRateChanged?.Invoke(TurbineFlowRateSlider.Value);
|
||||
};
|
||||
FlowRateDecrease.OnPressed += _ => TurbineFlowRateChanged?.Invoke(_flowRate - 100);
|
||||
FlowRateDecrease.OnButtonDown += _ => _repeatQueue.Add(FlowRateDecrease, _repeatDelay);
|
||||
FlowRateDecrease.OnButtonUp += _ => _repeatQueue.Remove(FlowRateDecrease);
|
||||
|
||||
FlowRateIncrease.OnPressed += _ => TurbineFlowRateChanged?.Invoke(_flowRate + 100);
|
||||
FlowRateIncrease.OnButtonDown += _ => _repeatQueue.Add(FlowRateIncrease, _repeatDelay);
|
||||
FlowRateIncrease.OnButtonUp += _ => _repeatQueue.Remove(FlowRateIncrease);
|
||||
|
||||
// Handle stator load
|
||||
TurbineStatorLoadLabel.OnFocusEnter += _ => _suppressStatorUpdate = true;
|
||||
TurbineStatorLoadLabel.OnFocusExit += _ => StatorTextChanged();
|
||||
TurbineStatorLoadLabel.OnTextEntered += _ => StatorTextChanged(true);
|
||||
|
||||
StatorLoadDecreaseLarge.OnPressed += _ => TurbineStatorLoadChanged?.Invoke(_statorLevel - 1000);
|
||||
StatorLoadDecreaseLarge.OnButtonDown += _ => _repeatQueue.Add(StatorLoadDecreaseLarge, _repeatDelay);
|
||||
StatorLoadDecreaseLarge.OnButtonUp += _ => _repeatQueue.Remove(StatorLoadDecreaseLarge);
|
||||
|
||||
StatorLoadDecrease.OnPressed += _ => TurbineStatorLoadChanged?.Invoke(_statorLevel - 100);
|
||||
StatorLoadDecrease.OnButtonDown += _ => _repeatQueue.Add(StatorLoadDecrease, _repeatDelay);
|
||||
StatorLoadDecrease.OnButtonUp += _ => _repeatQueue.Remove(StatorLoadDecrease);
|
||||
|
||||
StatorLoadIncrease.OnPressed += _ => TurbineStatorLoadChanged?.Invoke(_statorLevel + 100);
|
||||
StatorLoadIncrease.OnButtonDown += _ => _repeatQueue.Add(StatorLoadIncrease, _repeatDelay);
|
||||
StatorLoadIncrease.OnButtonUp += _ => _repeatQueue.Remove(StatorLoadIncrease);
|
||||
|
||||
StatorLoadIncreaseLarge.OnPressed += _ => TurbineStatorLoadChanged?.Invoke(_statorLevel + 1000);
|
||||
StatorLoadIncreaseLarge.OnButtonDown += _ => _repeatQueue.Add(StatorLoadIncreaseLarge, _repeatDelay);
|
||||
StatorLoadIncreaseLarge.OnButtonUp += _ => _repeatQueue.Remove(StatorLoadIncreaseLarge);
|
||||
|
||||
CTabContainer.SetTabTitle(0, Loc.GetString("comp-turbine-ui-tab-main"));
|
||||
CTabContainer.SetTabTitle(1, Loc.GetString("comp-turbine-ui-tab-parts"));
|
||||
|
||||
return;
|
||||
|
||||
void FlowTextChanged(bool suppress = false)
|
||||
{
|
||||
if (float.TryParse(TurbineFlowRateLabel.Text, out var num) && !float.IsNaN(num))
|
||||
TurbineFlowRateChanged?.Invoke(num);
|
||||
_suppressFlowUpdate = suppress;
|
||||
}
|
||||
|
||||
void StatorTextChanged(bool suppress = false)
|
||||
{
|
||||
if (float.TryParse(TurbineStatorLoadLabel.Text, out var num) && !float.IsNaN(num))
|
||||
TurbineStatorLoadChanged?.Invoke(num);
|
||||
_suppressStatorUpdate = suppress;
|
||||
}
|
||||
}
|
||||
|
||||
#region Graphics
|
||||
public void SetEntity(EntityUid turbine, EntityUid? monitor = null)
|
||||
{
|
||||
_turbine = turbine;
|
||||
|
||||
if (monitor != null)
|
||||
{
|
||||
_monitor = monitor.Value;
|
||||
_isMonitor = true;
|
||||
}
|
||||
|
||||
this.SetInfoFromEntity(_entityManager, _isMonitor ? _monitor : _turbine);
|
||||
|
||||
EntityView.SetEntity(turbine);
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(_speedMeter))]
|
||||
public void InitRPMMeter()
|
||||
{
|
||||
_speedMeter = new StyleBoxFlat[_speedColors.Length];
|
||||
|
||||
for (var i = _speedColors.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var styleBox = new StyleBoxFlat();
|
||||
_speedMeter[i] = styleBox;
|
||||
|
||||
for (var j = 0; j < RPMMeter.Columns; j++)
|
||||
{
|
||||
var control = new PanelContainer
|
||||
{
|
||||
Margin = new Thickness(2),
|
||||
PanelOverride = styleBox,
|
||||
HorizontalExpand = true,
|
||||
VerticalExpand = true,
|
||||
};
|
||||
RPMMeter.AddChild(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Color DimGaugeColor(Color color)
|
||||
{
|
||||
var hsv = Color.ToHsv(color);
|
||||
hsv.Z /= 5;
|
||||
return Color.FromHsv(hsv);
|
||||
}
|
||||
|
||||
public void Update(TurbineBuiState msg)
|
||||
{
|
||||
UpdateIndicators(msg);
|
||||
|
||||
if(!_suppressFlowUpdate)
|
||||
TurbineFlowRateLabel.Text = Math.Round(msg.FlowRate).ToString();
|
||||
if(!_suppressStatorUpdate)
|
||||
TurbineStatorLoadLabel.Text = Math.Round(msg.StatorLoad).ToString();
|
||||
|
||||
var locktarget = _isMonitor ? _monitor : _turbine;
|
||||
Inputs.Visible = !_lock.IsLocked(locktarget);
|
||||
LockedMessage.Visible = _lock.IsLocked(locktarget);
|
||||
|
||||
_suppressSliderEvents = true;
|
||||
TurbineFlowRateSlider.MaxValue = msg.FlowRateMax;
|
||||
TurbineFlowRateSlider.MinValue = msg.FlowRateMin;
|
||||
TurbineFlowRateSlider.Value = msg.FlowRate;
|
||||
_flowRate = msg.FlowRate;
|
||||
_statorLevel = msg.StatorLoad;
|
||||
|
||||
_suppressSliderEvents = false;
|
||||
|
||||
_speedLevel = ContentHelpers.RoundToNearestLevels(msg.RPM, msg.BestRPM * 1.2, _speedMeter.Length);
|
||||
|
||||
var bladeExists = msg.Blade != null;
|
||||
if(bladeExists)
|
||||
{
|
||||
BladeEntityView.SetEntity(msg.Blade!.Value);
|
||||
BladeInfoName.Text = Identity.Name(_entityManager.GetEntity(msg.Blade!.Value), _entityManager);
|
||||
}
|
||||
|
||||
BladeInfo.Visible = bladeExists;
|
||||
BladeInfoIntegrity.Text = Math.Round(msg.Health * 100 / msg.HealthMax).ToString() + "%";
|
||||
BladeInfoStress.Text = Math.Round(msg.RPM * 100 / (msg.BestRPM * 1.2)).ToString() + "%";
|
||||
|
||||
var statorExists = msg.Stator != null;
|
||||
if (statorExists)
|
||||
{
|
||||
StatorEntityView.SetEntity(msg.Stator!.Value);
|
||||
StatorInfoName.Text = Identity.Name(_entityManager.GetEntity(msg.Stator!.Value), _entityManager);
|
||||
}
|
||||
|
||||
StatorInfo.Visible = statorExists;
|
||||
StatorInfoPotential.Text = Loc.GetString("comp-turbine-ui-power", ("power", msg.PowerGeneration));
|
||||
StatorInfoSupply.Text = Loc.GetString("comp-turbine-ui-power", ("power", msg.PowerSupply));
|
||||
}
|
||||
|
||||
private void UpdateIndicators(TurbineBuiState msg)
|
||||
{
|
||||
var FilePath = "/Textures/_FarHorizons/Structures/Power/Generation/FissionGenerator/indicator_lamps/";
|
||||
// These are just if/else statements in black magic form
|
||||
TurbineOverspeed.TexturePath = msg.Overspeed ? FilePath + "redlit.png" : FilePath + "reddim.png";
|
||||
TurbineOvertemp.TexturePath = msg.Overtemp ? FilePath + "redlit.png" : FilePath + "reddim.png";
|
||||
TurbineStalling.TexturePath = msg.Stalling ? FilePath + "amberlit.png" : FilePath + "amberdim.png";
|
||||
TurbineUndertemp.TexturePath = msg.Undertemp ? FilePath + "bluelit.png" : FilePath + "bluedim.png";
|
||||
}
|
||||
|
||||
protected override void FrameUpdate(FrameEventArgs args)
|
||||
{
|
||||
base.FrameUpdate(args);
|
||||
|
||||
for (var i = 0; i < _speedMeter.Length; i++)
|
||||
{
|
||||
var box = _speedMeter[i];
|
||||
box.BackgroundColor = _speedLevel > i ? _speedColors[i] : _speedColorsDim[i];
|
||||
}
|
||||
|
||||
foreach (var kvp in _repeatQueue)
|
||||
{
|
||||
if(kvp.Value > 0)
|
||||
{
|
||||
_repeatQueue[kvp.Key] -= args.DeltaSeconds;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (kvp.Key)
|
||||
{
|
||||
case var _ when kvp.Key == FlowRateDecrease:
|
||||
TurbineFlowRateChanged?.Invoke(_flowRate - 100);
|
||||
break;
|
||||
case var _ when kvp.Key == FlowRateIncrease:
|
||||
TurbineFlowRateChanged?.Invoke(_flowRate + 100);
|
||||
break;
|
||||
case var _ when kvp.Key == StatorLoadDecreaseLarge:
|
||||
TurbineStatorLoadChanged?.Invoke(_statorLevel - 1000);
|
||||
break;
|
||||
case var _ when kvp.Key == StatorLoadDecrease:
|
||||
TurbineStatorLoadChanged?.Invoke(_statorLevel - 100);
|
||||
break;
|
||||
case var _ when kvp.Key == StatorLoadIncrease:
|
||||
TurbineStatorLoadChanged?.Invoke(_statorLevel + 100);
|
||||
break;
|
||||
case var _ when kvp.Key == StatorLoadIncreaseLarge:
|
||||
TurbineStatorLoadChanged?.Invoke(_statorLevel + 1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.DeviceLinking.Systems;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Content.Shared.DeviceLinking.Events;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
public sealed partial class GasTurbineMonitorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly TurbineSystem _turbineSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly DeviceLinkSystem _signal = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = null!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private readonly float _threshold = 0.5f;
|
||||
private float _accumulator = 0f;
|
||||
|
||||
private sealed class LogData
|
||||
{
|
||||
public TimeSpan CreationTime;
|
||||
public NetEntity Turbine;
|
||||
public float? SetFlowRate;
|
||||
public float? SetStatorLoad;
|
||||
}
|
||||
|
||||
private readonly Dictionary<KeyValuePair<EntityUid, EntityUid>, LogData> _logQueue = [];
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GasTurbineMonitorComponent, MapInitEvent>(OnMapInit);
|
||||
|
||||
SubscribeLocalEvent<GasTurbineMonitorComponent, NewLinkEvent>(OnNewLink);
|
||||
SubscribeLocalEvent<GasTurbineMonitorComponent, PortDisconnectedEvent>(OnPortDisconnected);
|
||||
|
||||
SubscribeLocalEvent<GasTurbineMonitorComponent, TurbineChangeFlowRateMessage>(OnTurbineFlowRateChanged);
|
||||
SubscribeLocalEvent<GasTurbineMonitorComponent, TurbineChangeStatorLoadMessage>(OnTurbineStatorLoadChanged);
|
||||
|
||||
SubscribeLocalEvent<GasTurbineMonitorComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, GasTurbineMonitorComponent comp, ref MapInitEvent args)
|
||||
{
|
||||
if (!_entityManager.TryGetComponent<DeviceLinkSinkComponent>(uid, out var sink))
|
||||
return;
|
||||
|
||||
foreach (var source in sink.LinkedSources)
|
||||
{
|
||||
if (!HasComp<TurbineComponent>(source))
|
||||
continue;
|
||||
|
||||
comp.turbine = GetNetEntity(source);
|
||||
Dirty(uid, comp);
|
||||
return; // The return is to make it behave such that the first connetion that's a turbine is the one chosen
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNewLink(EntityUid uid, GasTurbineMonitorComponent comp, ref NewLinkEvent args)
|
||||
{
|
||||
if (!HasComp<TurbineComponent>(args.Source))
|
||||
return;
|
||||
|
||||
comp.turbine = GetNetEntity(args.Source);
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
|
||||
private void OnPortDisconnected(EntityUid uid, GasTurbineMonitorComponent comp, ref PortDisconnectedEvent args)
|
||||
{
|
||||
if (args.Port != comp.LinkingPort)
|
||||
return;
|
||||
|
||||
comp.turbine = null;
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
|
||||
public bool TryGetTurbineComp(GasTurbineMonitorComponent turbineMonitor, [NotNullWhen(true)] out TurbineComponent? turbineComponent)
|
||||
{
|
||||
turbineComponent = null;
|
||||
if (!_entityManager.TryGetEntity(turbineMonitor.turbine, out var turbineUid) || turbineUid == null)
|
||||
return false;
|
||||
|
||||
if (!_entityManager.TryGetComponent<TurbineComponent>(turbineUid, out var turbine))
|
||||
return false;
|
||||
|
||||
turbineComponent = turbine;
|
||||
return true;
|
||||
}
|
||||
|
||||
#region BUI
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_accumulator += frameTime;
|
||||
if (_accumulator > _threshold)
|
||||
{
|
||||
AccUpdate();
|
||||
UpdateLogs();
|
||||
_accumulator = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
void UpdateLogs()
|
||||
{
|
||||
var toRemove = new List<KeyValuePair<EntityUid, EntityUid>>();
|
||||
foreach (var log in _logQueue.Where(log => !((_gameTiming.RealTime - log.Value.CreationTime).TotalSeconds < 2)))
|
||||
{
|
||||
toRemove.Add(log.Key);
|
||||
|
||||
if (log.Value.SetFlowRate != null)
|
||||
_adminLogger.Add(LogType.AtmosVolumeChanged, LogImpact.Medium,
|
||||
$"{ToPrettyString(log.Key.Key):player} set the flow rate on {ToPrettyString(log.Value.Turbine):device} to {log.Value.SetFlowRate} through {ToPrettyString(log.Key.Value):monitor}");
|
||||
|
||||
if (log.Value.SetStatorLoad != null)
|
||||
_adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium,
|
||||
$"{ToPrettyString(log.Key.Key):player} set the stator load on {ToPrettyString(log.Value.Turbine):device} to {log.Value.SetStatorLoad} through {ToPrettyString(log.Key.Value):monitor}");
|
||||
}
|
||||
|
||||
foreach (var kvp in toRemove)
|
||||
_logQueue.Remove(kvp);
|
||||
}
|
||||
}
|
||||
|
||||
private void AccUpdate()
|
||||
{
|
||||
var query = EntityQueryEnumerator<GasTurbineMonitorComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var turbineMonitor))
|
||||
{
|
||||
CheckRange(uid, turbineMonitor);
|
||||
if (!TryGetTurbineComp(turbineMonitor, out var turbine))
|
||||
continue;
|
||||
|
||||
_turbineSystem.UpdateUI(uid, turbine);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTurbineFlowRateChanged(EntityUid uid, GasTurbineMonitorComponent comp, TurbineChangeFlowRateMessage args)
|
||||
{
|
||||
if (!TryGetTurbineComp(comp, out var turbine))
|
||||
return;
|
||||
|
||||
if(TrySetFlowRate())
|
||||
{
|
||||
// Data is sent to a log queue to avoid spamming the admin log when adjusting values rapidly
|
||||
var key = new KeyValuePair<EntityUid, EntityUid>(args.Actor, uid);
|
||||
if(!_logQueue.TryGetValue(key, out var value))
|
||||
_logQueue.Add(key, new LogData
|
||||
{
|
||||
CreationTime = _gameTiming.RealTime,
|
||||
Turbine = comp.turbine!.Value,
|
||||
SetFlowRate = turbine.FlowRate
|
||||
});
|
||||
else
|
||||
value.SetFlowRate = turbine.FlowRate;
|
||||
}
|
||||
|
||||
_turbineSystem.UpdateUI(uid, turbine);
|
||||
|
||||
return;
|
||||
|
||||
bool TrySetFlowRate()
|
||||
{
|
||||
var newSet = Math.Clamp(args.FlowRate, 0f, turbine.FlowRateMax);
|
||||
if (turbine.FlowRate != newSet)
|
||||
{
|
||||
turbine.FlowRate = newSet;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTurbineStatorLoadChanged(EntityUid uid, GasTurbineMonitorComponent comp, TurbineChangeStatorLoadMessage args)
|
||||
{
|
||||
if (!TryGetTurbineComp(comp, out var turbine))
|
||||
return;
|
||||
|
||||
if (TrySetStatorLoad())
|
||||
{
|
||||
// Data is sent to a log queue to avoid spamming the admin log when adjusting values rapidly
|
||||
var key = new KeyValuePair<EntityUid, EntityUid>(args.Actor, uid);
|
||||
if (!_logQueue.TryGetValue(key, out var value))
|
||||
_logQueue.Add(key, new LogData
|
||||
{
|
||||
CreationTime = _gameTiming.RealTime,
|
||||
Turbine = comp.turbine!.Value,
|
||||
SetStatorLoad = turbine.StatorLoad
|
||||
});
|
||||
else
|
||||
value.SetStatorLoad = turbine.StatorLoad;
|
||||
}
|
||||
|
||||
_turbineSystem.UpdateUI(uid, turbine);
|
||||
|
||||
return;
|
||||
|
||||
bool TrySetStatorLoad()
|
||||
{
|
||||
var newSet = Math.Max(args.StatorLoad, 1000f);
|
||||
if (turbine.StatorLoad != newSet)
|
||||
{
|
||||
turbine.StatorLoad = newSet;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OnAnchorChanged(EntityUid uid, GasTurbineMonitorComponent comp, ref AnchorStateChangedEvent args)
|
||||
{
|
||||
if (!args.Anchored)
|
||||
return;
|
||||
|
||||
CheckRange(uid, comp);
|
||||
}
|
||||
|
||||
private void CheckRange(EntityUid uid, GasTurbineMonitorComponent comp)
|
||||
{
|
||||
if (!_entityManager.TryGetComponent<DeviceLinkSinkComponent>(uid, out var sink) || sink.LinkedSources.Count < 1)
|
||||
return;
|
||||
|
||||
if (!_entityManager.TryGetEntity(comp.turbine, out var uidTurbine))
|
||||
return;
|
||||
|
||||
if (!_entityManager.TryGetComponent<DeviceLinkSourceComponent>(uidTurbine, out var source))
|
||||
return;
|
||||
|
||||
var xformMonitor = Transform(uid);
|
||||
var xformReactor = Transform(uidTurbine.Value);
|
||||
var posMonitor = _transformSystem.GetWorldPosition(xformMonitor);
|
||||
var posReactor = _transformSystem.GetWorldPosition(xformReactor);
|
||||
|
||||
if (xformMonitor.MapID == xformReactor.MapID && (posMonitor - posReactor).Length() <= source.Range)
|
||||
return;
|
||||
|
||||
_uiSystem.CloseUi(uid, TurbineUiKey.Key);
|
||||
comp.turbine = null;
|
||||
_signal.RemoveSinkFromSource(uidTurbine.Value, uid, source, sink);
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/centrifuge.dm
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class NuclearCentrifugeComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Processed fuel
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ExtractedFuel = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Fuel left to be processed
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float FuelToExtract = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating the centrifuge is running
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool Processing = false;
|
||||
|
||||
/// <summary>
|
||||
/// Sound played when loading an item into the centrifuge
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundPathSpecifier SoundLoad = new("/Audio/Weapons/Guns/MagIn/revolver_magin.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Sound played while the centrifuge is processing
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundPathSpecifier SoundProcess = new("/Audio/Machines/spinning.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Sound played when the centrifuge failed to create any plutonium
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundPathSpecifier SoundFail = new("/Audio/Machines/buzz-two.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Sound played when the centrifuge creates plutonium
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public SoundPathSpecifier SoundSucceed = new("/Audio/Machines/ding.ogg");
|
||||
|
||||
[ViewVariables]
|
||||
public EntityUid? AudioProcess;
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
using Content.Server.Stack;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Power;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
|
||||
namespace Content.Server._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/centrifuge.dm
|
||||
|
||||
public sealed class NuclearCentrifugeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly StackSystem _stackSystem = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
|
||||
private readonly float _threshold = 1f;
|
||||
private float _accumulator = 0f;
|
||||
private readonly int _stackSize = 30;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<NuclearCentrifugeComponent, InteractUsingEvent>(OnInteract);
|
||||
SubscribeLocalEvent<NuclearCentrifugeComponent, PowerChangedEvent>(OnPowerChange);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_accumulator += frameTime;
|
||||
if (_accumulator > _threshold)
|
||||
{
|
||||
AccUpdate();
|
||||
_accumulator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void AccUpdate()
|
||||
{
|
||||
var query = EntityQueryEnumerator<NuclearCentrifugeComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
if(!comp.Processing)
|
||||
continue;
|
||||
|
||||
if(comp.FuelToExtract>0)
|
||||
{
|
||||
var delta = Math.Min(comp.FuelToExtract, 0.5f);
|
||||
comp.ExtractedFuel += delta;
|
||||
comp.FuelToExtract -= delta;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(comp.ExtractedFuel > 1)
|
||||
{
|
||||
// If this while loop causes problems, blame whoever put 1.78e308 plutonium in the centrifuge
|
||||
while (comp.ExtractedFuel > 1)
|
||||
{
|
||||
var plutoniumStack = Spawn("IngotPlutonium1", Transform(uid).Coordinates);
|
||||
_stackSystem.SetCount(plutoniumStack, Math.Clamp((int)Math.Floor(comp.ExtractedFuel), 1, _stackSize));
|
||||
comp.ExtractedFuel -= _stackSystem.GetCount(plutoniumStack);
|
||||
_stackSystem.TryMergeToContacts(plutoniumStack);
|
||||
}
|
||||
_audio.PlayPvs(comp.SoundSucceed, uid);
|
||||
}
|
||||
else
|
||||
{
|
||||
_audio.PlayPvs(comp.SoundFail, uid, AudioParams.Default.WithVolume(-2));
|
||||
}
|
||||
|
||||
_audio.Stop(comp.AudioProcess);
|
||||
|
||||
comp.Processing = false;
|
||||
_appearance.SetData(uid, NuclearCentrifugeVisuals.Processing, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInteract(EntityUid uid, NuclearCentrifugeComponent comp, ref InteractUsingEvent args)
|
||||
{
|
||||
if (!this.IsPowered(uid, _entityManager))
|
||||
return;
|
||||
|
||||
if (!_entityManager.TryGetComponent<ReactorPartComponent>(args.Used, out var ReactorPart) || !ReactorPart.HasRodType(ReactorPartComponent.RodTypes.FuelRod))
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("nuclear-centrifuge-wrong-item", ("item", args.Used)), args.User, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ReactorPart.Properties == null || ReactorPart.Properties.FissileIsotopes < 0.1)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("nuclear-centrifuge-unfit-item", ("item", args.Used)), args.User, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("nuclear-centrifuge-insert-item", ("user", args.User), ("machine", uid), ("item", args.Used)), uid);
|
||||
_audio.PlayPvs(comp.SoundLoad, uid);
|
||||
|
||||
if(!_audio.IsPlaying(comp.AudioProcess))
|
||||
comp.AudioProcess = _audio.PlayPvs(comp.SoundProcess, uid, AudioParams.Default.WithLoop(true).WithVolume(-2))?.Entity;
|
||||
|
||||
comp.FuelToExtract += ReactorPart.Properties.FissileIsotopes;
|
||||
comp.Processing = true;
|
||||
_entityManager.DeleteEntity(args.Used);
|
||||
|
||||
_appearance.SetData(uid, NuclearCentrifugeVisuals.Processing, true);
|
||||
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnPowerChange(EntityUid uid, NuclearCentrifugeComponent comp, ref PowerChangedEvent args)
|
||||
{
|
||||
if(!args.Powered && comp.Processing)
|
||||
{
|
||||
if(_audio.IsPlaying(comp.AudioProcess))
|
||||
_audio.Stop(comp.AudioProcess);
|
||||
comp.Processing = false;
|
||||
}
|
||||
|
||||
if(args.Powered && comp.FuelToExtract > 0)
|
||||
{
|
||||
comp.AudioProcess = _audio.PlayPvs(comp.SoundProcess, uid, AudioParams.Default.WithLoop(true).WithVolume(-2))?.Entity;
|
||||
comp.Processing = true;
|
||||
}
|
||||
|
||||
_appearance.SetData(uid, NuclearCentrifugeVisuals.Processing, comp.Processing);
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.DeviceLinking.Systems;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Content.Shared.DeviceLinking.Events;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
public sealed partial class NuclearReactorMonitorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLog = default!;
|
||||
[Dependency] private readonly NuclearReactorSystem _reactorSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly DeviceLinkSystem _signal = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = null!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private readonly float _threshold = 0.5f;
|
||||
private float _accumulator = 0f;
|
||||
|
||||
private sealed class LogData
|
||||
{
|
||||
public TimeSpan CreationTime;
|
||||
public NetEntity Reactor;
|
||||
public float? SetControlRodInsertion;
|
||||
}
|
||||
|
||||
private readonly Dictionary<KeyValuePair<EntityUid, EntityUid>, LogData> _logQueue = [];
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<NuclearReactorMonitorComponent, MapInitEvent>(OnMapInit);
|
||||
|
||||
SubscribeLocalEvent<NuclearReactorMonitorComponent, NewLinkEvent>(OnNewLink);
|
||||
SubscribeLocalEvent<NuclearReactorMonitorComponent, PortDisconnectedEvent>(OnPortDisconnected);
|
||||
|
||||
SubscribeLocalEvent<NuclearReactorMonitorComponent, ReactorControlRodModifyMessage>(OnControlRodMessage);
|
||||
|
||||
SubscribeLocalEvent<NuclearReactorMonitorComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, NuclearReactorMonitorComponent comp, ref MapInitEvent args)
|
||||
{
|
||||
if (!_entityManager.TryGetComponent<DeviceLinkSinkComponent>(uid, out var sink))
|
||||
return;
|
||||
|
||||
foreach(var source in sink.LinkedSources)
|
||||
{
|
||||
if (!HasComp<NuclearReactorComponent>(source))
|
||||
continue;
|
||||
|
||||
comp.reactor = GetNetEntity(source);
|
||||
Dirty(uid, comp);
|
||||
return; // The return is to make it behave such that the first connetion that's a reactor is the one chosen
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNewLink(EntityUid uid, NuclearReactorMonitorComponent comp, ref NewLinkEvent args)
|
||||
{
|
||||
if (!HasComp<NuclearReactorComponent>(args.Source))
|
||||
return;
|
||||
|
||||
comp.reactor = GetNetEntity(args.Source);
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
|
||||
private void OnPortDisconnected(EntityUid uid, NuclearReactorMonitorComponent comp, ref PortDisconnectedEvent args)
|
||||
{
|
||||
if (args.Port != comp.LinkingPort)
|
||||
return;
|
||||
|
||||
comp.reactor = null;
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
|
||||
public bool TryGetReactorComp(NuclearReactorMonitorComponent reactorMonitor, [NotNullWhen(true)] out NuclearReactorComponent? reactorComponent)
|
||||
{
|
||||
reactorComponent = null;
|
||||
if (!_entityManager.TryGetEntity(reactorMonitor.reactor, out var reactorEnt) || reactorEnt == null)
|
||||
return false;
|
||||
|
||||
if (!_entityManager.TryGetComponent<NuclearReactorComponent>(reactorEnt, out var reactor))
|
||||
return false;
|
||||
|
||||
reactorComponent = reactor;
|
||||
return true;
|
||||
}
|
||||
|
||||
#region BUI
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_accumulator += frameTime;
|
||||
if (_accumulator > _threshold)
|
||||
{
|
||||
AccUpdate();
|
||||
UpdateLogs();
|
||||
_accumulator = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
void UpdateLogs()
|
||||
{
|
||||
var toRemove = new List<KeyValuePair<EntityUid, EntityUid>>();
|
||||
foreach (var log in _logQueue.Where(log => !((_gameTiming.RealTime - log.Value.CreationTime).TotalSeconds < 2)))
|
||||
{
|
||||
toRemove.Add(log.Key);
|
||||
|
||||
if (log.Value.SetControlRodInsertion != null)
|
||||
_adminLog.Add(LogType.Action, $"{ToPrettyString(log.Key.Key):actor} set control rod insertion of {ToPrettyString(log.Value.Reactor):target} to {log.Value.SetControlRodInsertion} through {ToPrettyString(log.Key.Value):monitor}");
|
||||
}
|
||||
|
||||
foreach (var kvp in toRemove)
|
||||
_logQueue.Remove(kvp);
|
||||
}
|
||||
}
|
||||
|
||||
private void AccUpdate()
|
||||
{
|
||||
var query = EntityQueryEnumerator<NuclearReactorMonitorComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var reactorMonitor))
|
||||
{
|
||||
CheckRange(uid, reactorMonitor);
|
||||
if (!TryGetReactorComp(reactorMonitor, out var reactor))
|
||||
continue;
|
||||
|
||||
_reactorSystem.UpdateUI(uid, reactor);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnControlRodMessage(EntityUid uid, NuclearReactorMonitorComponent comp, ref ReactorControlRodModifyMessage args)
|
||||
{
|
||||
if (!TryGetReactorComp(comp, out var reactor))
|
||||
return;
|
||||
|
||||
if(SharedNuclearReactorSystem.AdjustControlRods(reactor, args.Change))
|
||||
{
|
||||
// Data is sent to a log queue to avoid spamming the admin log when adjusting values rapidly
|
||||
var key = new KeyValuePair<EntityUid, EntityUid>(args.Actor, uid);
|
||||
if(!_logQueue.TryGetValue(key, out var value))
|
||||
_logQueue.Add(key, new LogData {
|
||||
CreationTime = _gameTiming.RealTime,
|
||||
Reactor = comp.reactor!.Value,
|
||||
SetControlRodInsertion = reactor.ControlRodInsertion
|
||||
});
|
||||
else
|
||||
value.SetControlRodInsertion = reactor.ControlRodInsertion;
|
||||
}
|
||||
|
||||
_reactorSystem.UpdateUI(uid, reactor);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OnAnchorChanged(EntityUid uid, NuclearReactorMonitorComponent comp, ref AnchorStateChangedEvent args)
|
||||
{
|
||||
if (!args.Anchored)
|
||||
return;
|
||||
|
||||
CheckRange(uid, comp);
|
||||
}
|
||||
|
||||
private void CheckRange(EntityUid uid, NuclearReactorMonitorComponent comp)
|
||||
{
|
||||
if (!_entityManager.TryGetComponent<DeviceLinkSinkComponent>(uid, out var sink) || sink.LinkedSources.Count < 1)
|
||||
return;
|
||||
|
||||
if (!_entityManager.TryGetEntity(comp.reactor, out var uidReactor))
|
||||
return;
|
||||
|
||||
if (!_entityManager.TryGetComponent<DeviceLinkSourceComponent>(uidReactor, out var source))
|
||||
return;
|
||||
|
||||
var xformMonitor = Transform(uid);
|
||||
var xformReactor = Transform(uidReactor.Value);
|
||||
var posMonitor = _transformSystem.GetWorldPosition(xformMonitor);
|
||||
var posReactor = _transformSystem.GetWorldPosition(xformReactor);
|
||||
|
||||
if (xformMonitor.MapID == xformReactor.MapID && (posMonitor - posReactor).Length() <= source.Range)
|
||||
return;
|
||||
|
||||
_uiSystem.CloseUi(uid, NuclearReactorUiKey.Key);
|
||||
comp.reactor = null;
|
||||
_signal.RemoveSinkFromSource(uidReactor.Value, uid, source, sink);
|
||||
Dirty(uid, comp);
|
||||
}
|
||||
}
|
||||
+1012
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,614 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Random;
|
||||
using Content.Shared._FarHorizons.Materials.Systems;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Nutrition;
|
||||
using Content.Shared.Radiation.Components;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/reactorcomponents.dm
|
||||
|
||||
public sealed class ReactorPartSystem : SharedReactorPartSystem
|
||||
{
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly SharedPointLightSystem _lightSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Changes the overall rate of events
|
||||
/// </summary>
|
||||
private readonly float _rate = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Changes the likelyhood of neutron interactions
|
||||
/// </summary>
|
||||
private readonly float _bias = 1.5f;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of a property consumed by a reaction
|
||||
/// </summary>
|
||||
private readonly float _reactant = 0.01f;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of a property resultant from a reaction
|
||||
/// </summary>
|
||||
private readonly float _product = 0.005f;
|
||||
|
||||
/// <summary>
|
||||
/// Temperature (in C) when people's hands can be burnt
|
||||
/// </summary>
|
||||
private readonly static float _hotTemp = 80;
|
||||
|
||||
/// <summary>
|
||||
/// Temperature (in C) when insulated gloves can no longer protect
|
||||
/// </summary>
|
||||
private readonly static float _burnTemp = 400;
|
||||
|
||||
private readonly static float _burnDiv = (_burnTemp - _hotTemp) / 5; // The 5 is how much heat damage insulated gloves protect from
|
||||
|
||||
private readonly float _threshold = 1f;
|
||||
private float _accumulator = 0f;
|
||||
|
||||
#region Item Methods
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ReactorPartComponent, MapInitEvent>(OnInit);
|
||||
SubscribeLocalEvent<ReactorPartComponent, ExaminedEvent>(OnExamine);
|
||||
SubscribeLocalEvent<ReactorPartComponent, IngestedEvent>(OnIngest);
|
||||
}
|
||||
|
||||
private void OnInit(EntityUid uid, ReactorPartComponent component, ref MapInitEvent args)
|
||||
{
|
||||
var radvalue = (component.Properties.Radioactivity * 0.1f) + (component.Properties.NeutronRadioactivity * 0.15f) + (component.Properties.FissileIsotopes * 0.125f);
|
||||
if (radvalue > 0)
|
||||
{
|
||||
var radcomp = EnsureComp<RadiationSourceComponent>(uid);
|
||||
radcomp.Intensity = radvalue;
|
||||
}
|
||||
|
||||
if (component.Properties.NeutronRadioactivity > 0)
|
||||
{
|
||||
var lightcomp = _lightSystem.EnsureLight(uid);
|
||||
_lightSystem.SetEnergy(uid, component.Properties.NeutronRadioactivity, lightcomp);
|
||||
_lightSystem.SetColor(uid, Color.FromHex("#22bbff"), lightcomp);
|
||||
_lightSystem.SetRadius(uid, 1.2f, lightcomp);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<ReactorPartComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
var comp = ent.Comp;
|
||||
if (!args.IsInDetailsRange)
|
||||
return;
|
||||
|
||||
using (args.PushGroup(nameof(ReactorPartComponent)))
|
||||
{
|
||||
switch (comp.Properties.NeutronRadioactivity)
|
||||
{
|
||||
case > 8:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-nrad-5"));
|
||||
break;
|
||||
case > 6:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-nrad-4"));
|
||||
break;
|
||||
case > 4:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-nrad-3"));
|
||||
break;
|
||||
case > 2:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-nrad-2"));
|
||||
break;
|
||||
case > 1:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-nrad-1"));
|
||||
break;
|
||||
case > 0:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-nrad-0"));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (comp.Properties.Radioactivity)
|
||||
{
|
||||
case > 8:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-rad-5"));
|
||||
break;
|
||||
case > 6:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-rad-4"));
|
||||
break;
|
||||
case > 4:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-rad-3"));
|
||||
break;
|
||||
case > 2:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-rad-2"));
|
||||
break;
|
||||
case > 1:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-rad-1"));
|
||||
break;
|
||||
case > 0:
|
||||
args.PushMarkup(Loc.GetString("reactor-part-rad-0"));
|
||||
break;
|
||||
}
|
||||
|
||||
if (comp.Temperature > Atmospherics.T0C + _burnTemp)
|
||||
args.PushMarkup(Loc.GetString("reactor-part-burning"));
|
||||
else if (comp.Temperature > Atmospherics.T0C + _hotTemp)
|
||||
args.PushMarkup(Loc.GetString("reactor-part-hot"));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIngest(Entity<ReactorPartComponent> ent, ref IngestedEvent args)
|
||||
{
|
||||
var comp = ent.Comp;
|
||||
if (comp.Properties == null)
|
||||
return;
|
||||
|
||||
var properties = comp.Properties;
|
||||
|
||||
if (!_entityManager.TryGetComponent<DamageableComponent>(args.Target, out var damageable) || damageable.Damage.DamageDict == null)
|
||||
return;
|
||||
|
||||
var dict = damageable.Damage.DamageDict;
|
||||
|
||||
var dmgKey = "Radiation";
|
||||
var dmg = (properties.NeutronRadioactivity * 20) + (properties.Radioactivity * 10) + (properties.FissileIsotopes * 5);
|
||||
|
||||
if (!dict.TryAdd(dmgKey, dmg))
|
||||
{
|
||||
var prev = dict[dmgKey];
|
||||
dict.Remove(dmgKey);
|
||||
dict.Add(dmgKey, prev + dmg);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_accumulator += frameTime;
|
||||
if (_accumulator > _threshold)
|
||||
{
|
||||
AccUpdate();
|
||||
_accumulator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void AccUpdate()
|
||||
{
|
||||
var query = EntityQueryEnumerator<ReactorPartComponent>();
|
||||
while (query.MoveNext(out var uid, out var component))
|
||||
{
|
||||
var gasMix = _atmosphereSystem.GetTileMixture(uid, true) ?? GasMixture.SpaceGas;
|
||||
var DeltaT = (component.Temperature - gasMix.Temperature) * 0.01f;
|
||||
|
||||
if (Math.Abs(DeltaT) < 0.1)
|
||||
continue;
|
||||
|
||||
// This viloates the laws of physics, but if energy is conserved, then pulling out a hot rod will turn the room into an oven
|
||||
// Also does not take into account thermal mass
|
||||
component.Temperature -= DeltaT;
|
||||
if (!gasMix.Immutable) // This prevents it from heating up space itself
|
||||
gasMix.Temperature += DeltaT;
|
||||
|
||||
var burncomp = EnsureComp<DamageOnInteractComponent>(uid);
|
||||
|
||||
burncomp.IsDamageActive = component.Temperature > Atmospherics.T0C + _hotTemp;
|
||||
|
||||
if (burncomp.IsDamageActive)
|
||||
{
|
||||
var damage = Math.Max((component.Temperature - Atmospherics.T0C - _hotTemp) / _burnDiv, 0);
|
||||
|
||||
// Giant string of if/else that makes sure it will interfere only as much as it needs to
|
||||
if (burncomp.Damage == null)
|
||||
burncomp.Damage = new() { DamageDict = new() { { "Heat", damage } } };
|
||||
else if (burncomp.Damage.DamageDict == null)
|
||||
burncomp.Damage.DamageDict = new() { { "Heat", damage } };
|
||||
else if (!burncomp.Damage.DamageDict.ContainsKey("Heat"))
|
||||
burncomp.Damage.DamageDict.Add("Heat", damage);
|
||||
else
|
||||
burncomp.Damage.DamageDict["Heat"] = damage;
|
||||
}
|
||||
|
||||
Dirty(uid, burncomp);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Reactor Methods
|
||||
/// <summary>
|
||||
/// Processes gas flowing through a reactor part.
|
||||
/// </summary>
|
||||
/// <param name="reactorPart">The reactor part.</param>
|
||||
/// <param name="reactorEnt">The entity representing the reactor this part is inserted into.</param>
|
||||
/// <param name="inGas">The gas to be processed.</param>
|
||||
/// <returns></returns>
|
||||
public GasMixture? ProcessGas(ReactorPartComponent reactorPart, Entity<NuclearReactorComponent> reactorEnt, GasMixture inGas)
|
||||
{
|
||||
if (!reactorPart.HasRodType(ReactorPartComponent.RodTypes.GasChannel))
|
||||
return null;
|
||||
|
||||
GasMixture? ProcessedGas = null;
|
||||
if (reactorPart.AirContents != null)
|
||||
{
|
||||
var compTemp = reactorPart.Temperature;
|
||||
var gasTemp = reactorPart.AirContents.Temperature;
|
||||
|
||||
var DeltaT = compTemp - gasTemp;
|
||||
var DeltaTr = (compTemp + gasTemp) * (compTemp - gasTemp) * (Math.Pow(compTemp, 2) + Math.Pow(gasTemp, 2));
|
||||
|
||||
var k = MaterialSystem.CalculateHeatTransferCoefficient(reactorPart.Properties, null);
|
||||
var A = reactorPart.GasThermalCrossSection * (0.4 * 8);
|
||||
|
||||
var ThermalEnergy = _atmosphereSystem.GetThermalEnergy(reactorPart.AirContents);
|
||||
|
||||
var Hottest = Math.Max(gasTemp, compTemp);
|
||||
var Coldest = Math.Min(gasTemp, compTemp);
|
||||
|
||||
var MaxDeltaE = Math.Clamp((k * A * DeltaT) + (5.67037442e-8 * A * DeltaTr),
|
||||
(compTemp * reactorPart.ThermalMass) - (Hottest * reactorPart.ThermalMass),
|
||||
(compTemp * reactorPart.ThermalMass) - (Coldest * reactorPart.ThermalMass));
|
||||
|
||||
reactorPart.AirContents.Temperature = (float)Math.Clamp(gasTemp +
|
||||
(MaxDeltaE / _atmosphereSystem.GetHeatCapacity(reactorPart.AirContents, true)), Coldest, Hottest);
|
||||
|
||||
reactorPart.Temperature = (float)Math.Clamp(compTemp -
|
||||
((_atmosphereSystem.GetThermalEnergy(reactorPart.AirContents) - ThermalEnergy) / reactorPart.ThermalMass), Coldest, Hottest);
|
||||
|
||||
if (gasTemp < 0 || compTemp < 0)
|
||||
throw new Exception("Reactor part temperature went below 0k.");
|
||||
|
||||
if (reactorPart.Melted)
|
||||
{
|
||||
var T = _atmosphereSystem.GetTileMixture(reactorEnt.Owner, excite: true);
|
||||
if (T != null)
|
||||
_atmosphereSystem.Merge(T, reactorPart.AirContents);
|
||||
}
|
||||
else
|
||||
ProcessedGas = reactorPart.AirContents;
|
||||
}
|
||||
|
||||
if (inGas != null && _atmosphereSystem.GetThermalEnergy(inGas) > 0)
|
||||
{
|
||||
reactorPart.AirContents = inGas.RemoveVolume(reactorPart.GasVolume);
|
||||
reactorPart.AirContents.Volume = reactorPart.GasVolume;
|
||||
|
||||
if (reactorPart.AirContents != null && reactorPart.AirContents.TotalMoles < 1)
|
||||
{
|
||||
if (ProcessedGas != null)
|
||||
{
|
||||
_atmosphereSystem.Merge(ProcessedGas, reactorPart.AirContents);
|
||||
reactorPart.AirContents.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessedGas = reactorPart.AirContents;
|
||||
reactorPart.AirContents.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
return ProcessedGas;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes heat transfer within the reactor grid.
|
||||
/// </summary>
|
||||
/// <param name="reactorPart">Reactor part applying the calculations.</param>
|
||||
/// <param name="reactorEnt">Reactor housing the reactor part.</param>
|
||||
/// <param name="AdjacentComponents">List of reactor parts next to the reactorPart.</param>
|
||||
/// <param name="reactorSystem">The SharedNuclearReactorSystem.</param>
|
||||
/// <exception cref="Exception">Calculations resulted in a sub-zero value.</exception>
|
||||
public void ProcessHeat(ReactorPartComponent reactorPart, Entity<NuclearReactorComponent> reactorEnt, List<ReactorPartComponent?> AdjacentComponents, SharedNuclearReactorSystem reactorSystem)
|
||||
{
|
||||
var reactor = reactorEnt.Comp;
|
||||
|
||||
// Intercomponent calculation
|
||||
foreach (var RC in AdjacentComponents)
|
||||
{
|
||||
if (RC == null)
|
||||
continue;
|
||||
|
||||
var DeltaT = reactorPart.Temperature - RC.Temperature;
|
||||
var k = MaterialSystem.CalculateHeatTransferCoefficient(reactorPart.Properties, RC.Properties);
|
||||
var A = Math.Min(reactorPart.ThermalCrossSection, RC.ThermalCrossSection);
|
||||
|
||||
reactorPart.Temperature = (float)(reactorPart.Temperature - (k * A * (0.5 * 8) / reactorPart.ThermalMass * DeltaT));
|
||||
RC.Temperature = (float)(RC.Temperature - (k * A * (0.5 * 8) / RC.ThermalMass * -DeltaT));
|
||||
|
||||
if (RC.Temperature < 0 || reactorPart.Temperature < 0)
|
||||
throw new Exception("ReactorPart-ReactorPart temperature calculation resulted in sub-zero value.");
|
||||
|
||||
ProcessHeatEffects(RC);
|
||||
ProcessHeatEffects(reactorPart);
|
||||
}
|
||||
|
||||
// Component-Reactor calculation
|
||||
if (reactor != null)
|
||||
{
|
||||
var DeltaT = reactorPart.Temperature - reactor.Temperature;
|
||||
|
||||
var k = MaterialSystem.CalculateHeatTransferCoefficient(reactorPart.Properties, _proto.Index(reactor.Material).Properties);
|
||||
var A = reactorPart.ThermalCrossSection;
|
||||
|
||||
reactorPart.Temperature = (float)(reactorPart.Temperature - (k * A * (0.5 * 8) / reactorPart.ThermalMass * DeltaT));
|
||||
reactor.Temperature = (float)(reactor.Temperature - (k * A * (0.5 * 8) / reactor.ThermalMass * -DeltaT));
|
||||
|
||||
if (reactor.Temperature < 0 || reactorPart.Temperature < 0)
|
||||
throw new Exception("Reactor-ReactorPart temperature calculation resulted in sub-zero value.");
|
||||
|
||||
ProcessHeatEffects(reactorPart);
|
||||
}
|
||||
if (reactorPart.Temperature > reactorPart.MeltingPoint && reactorPart.MeltHealth > 0)
|
||||
reactorPart.MeltHealth -= _random.Next(10, 50 + 1);
|
||||
if (reactorPart.MeltHealth <= 0)
|
||||
Melt(reactorPart, reactorEnt, reactorSystem);
|
||||
|
||||
return;
|
||||
|
||||
// I would really like for these to be defined by the MaterialPrototype, like GasReactionPrototype, but it caused the client and server to fight when I tried
|
||||
// Also, function in a function because I found it funny
|
||||
void ProcessHeatEffects(ReactorPartComponent part)
|
||||
{
|
||||
switch (part.Material)
|
||||
{
|
||||
case "Plasma":
|
||||
PlasmaTemperatureEffects(part);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PlasmaTemperatureEffects(ReactorPartComponent part)
|
||||
{
|
||||
var temperatureThreshold = Atmospherics.T0C + 80;
|
||||
if (part.Temperature <= temperatureThreshold || part.Properties.ActivePlasma <= 0)
|
||||
return;
|
||||
|
||||
var molesPerUnit = 100f; // Arbitrary value for how much gaseous plasma is in each unit of active plasma
|
||||
|
||||
var payload = new GasMixture();
|
||||
payload.SetMoles(Gas.Plasma, (float)Math.Min(part.Properties.ActivePlasma * molesPerUnit, Math.Log(((part.Temperature - temperatureThreshold) / 100) + 1)));
|
||||
payload.Temperature = part.Temperature;
|
||||
part.Properties.ActivePlasma -= payload.GetMoles(Gas.Plasma) / molesPerUnit;
|
||||
|
||||
reactor.AirContents ??= new GasMixture();
|
||||
_atmosphereSystem.Merge(reactor.AirContents, payload);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Melts the related ReactorPart.
|
||||
/// </summary>
|
||||
/// <param name="reactorPart">Reactor part to be melted</param>
|
||||
/// <param name="reactorEnt">Reactor housing the reactor part</param>
|
||||
/// <param name="reactorSystem">The SharedNuclearReactorSystem</param>
|
||||
public void Melt(ReactorPartComponent reactorPart, Entity<NuclearReactorComponent> reactorEnt, SharedNuclearReactorSystem reactorSystem)
|
||||
{
|
||||
if (reactorPart.Melted)
|
||||
return;
|
||||
|
||||
reactorPart.Melted = true;
|
||||
reactorPart.IconStateCap += "_melted_" + _random.Next(1, 4 + 1);
|
||||
reactorSystem.UpdateGridVisual(reactorEnt);
|
||||
reactorPart.NeutronCrossSection = 5f;
|
||||
reactorPart.ThermalCrossSection = 20f;
|
||||
reactorPart.IsControlRod = false;
|
||||
|
||||
if(reactorPart.HasRodType(ReactorPartComponent.RodTypes.GasChannel))
|
||||
reactorPart.GasThermalCrossSection = 0.1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of neutrons from the interation of the given ReactorPart and initial neutrons.
|
||||
/// </summary>
|
||||
/// <param name="reactorPart">Reactor part applying the calculations.</param>
|
||||
/// <param name="neutrons">List of neutrons to be processed.</param>
|
||||
/// <param name="thermalEnergy">Thermal energy released from the process.</param>
|
||||
/// <returns>Post-processing list of neutrons.</returns>
|
||||
public List<ReactorNeutron> ProcessNeutrons(ReactorPartComponent reactorPart, List<ReactorNeutron> neutrons, out float thermalEnergy)
|
||||
{
|
||||
var preCalcTemp = reactorPart.Temperature;
|
||||
var flux = new List<ReactorNeutron>(neutrons);
|
||||
|
||||
foreach (var neutron in flux)
|
||||
{
|
||||
if (Prob(reactorPart.Properties.Density * _rate * reactorPart.NeutronCrossSection * _bias))
|
||||
{
|
||||
if (neutron.velocity <= 1 && Prob(_rate * reactorPart.Properties.NeutronRadioactivity * _bias)) // neutron stimulated emission
|
||||
{
|
||||
reactorPart.Properties.NeutronRadioactivity -= _reactant;
|
||||
reactorPart.Properties.Radioactivity += _product;
|
||||
for (var i = 0; i < _random.Next(3, 5 + 1); i++) // was 1, 5+1
|
||||
{
|
||||
neutrons.Add(new() { dir = _random.NextAngle().GetDir(), velocity = _random.Next(2, 3 + 1) });
|
||||
}
|
||||
neutrons.Remove(neutron);
|
||||
reactorPart.Temperature += 75f; // Was 50, increased to make neutron reactions stronger
|
||||
}
|
||||
else if (neutron.velocity <= 5 && Prob(_rate * reactorPart.Properties.Radioactivity * _bias)) // stimulated emission
|
||||
{
|
||||
reactorPart.Properties.Radioactivity -= _reactant;
|
||||
reactorPart.Properties.FissileIsotopes += _product;
|
||||
for (var i = 0; i < _random.Next(3, 5 + 1); i++)// was 1, 5+1
|
||||
{
|
||||
neutrons.Add(new() { dir = _random.NextAngle().GetDir(), velocity = _random.Next(1, 3 + 1) });
|
||||
}
|
||||
neutrons.Remove(neutron);
|
||||
reactorPart.Temperature += 50f; // Was 25, increased to make neutron reactions stronger
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Prob(_rate * reactorPart.Properties.Hardness)) // reflection, based on hardness
|
||||
// A really complicated way of saying do a 180 or a 180+/-45
|
||||
neutron.dir = (neutron.dir.GetOpposite().ToAngle() + (_random.NextAngle() / 4) - (MathF.Tau / 8)).GetDir();
|
||||
else if (reactorPart.IsControlRod)
|
||||
neutron.velocity = 0;
|
||||
else
|
||||
neutron.velocity--;
|
||||
|
||||
if (neutron.velocity <= 0)
|
||||
neutrons.Remove(neutron);
|
||||
|
||||
reactorPart.Temperature += 1; // ... not worth the adjustment
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Prob(reactorPart.Properties.NeutronRadioactivity * _rate * reactorPart.NeutronCrossSection))
|
||||
{
|
||||
var count = _random.Next(1, 5 + 1); // Was 3+1
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
neutrons.Add(new() { dir = _random.NextAngle().GetDir(), velocity = 3 });
|
||||
}
|
||||
reactorPart.Properties.NeutronRadioactivity -= _reactant / 2;
|
||||
reactorPart.Properties.Radioactivity += _product / 2;
|
||||
//This code has been deactivated so neutrons would have a bigger impact
|
||||
//reactorPart.Temperature += 13; // 20 * 0.65
|
||||
}
|
||||
if (Prob(reactorPart.Properties.Radioactivity * _rate * reactorPart.NeutronCrossSection))
|
||||
{
|
||||
var count = _random.Next(1, 5 + 1); // Was 3+1
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
neutrons.Add(new() { dir = _random.NextAngle().GetDir(), velocity = _random.Next(1, 3 + 1) });
|
||||
}
|
||||
reactorPart.Properties.Radioactivity -= _reactant / 2;
|
||||
reactorPart.Properties.FissileIsotopes += _product / 2;
|
||||
//This code has been deactivated so neutrons would have a bigger impact
|
||||
//reactorPart.Temperature += 6.5f; // 10 * 0.65
|
||||
}
|
||||
|
||||
if (reactorPart.HasRodType(ReactorPartComponent.RodTypes.ControlRod))
|
||||
{
|
||||
if (!reactorPart.Melted && (reactorPart.NeutronCrossSection != reactorPart.ConfiguredInsertionLevel))
|
||||
{
|
||||
if (reactorPart.ConfiguredInsertionLevel < reactorPart.NeutronCrossSection)
|
||||
reactorPart.NeutronCrossSection -= Math.Min(0.1f, reactorPart.NeutronCrossSection - reactorPart.ConfiguredInsertionLevel);
|
||||
else
|
||||
reactorPart.NeutronCrossSection += Math.Min(0.1f, reactorPart.ConfiguredInsertionLevel - reactorPart.NeutronCrossSection);
|
||||
}
|
||||
}
|
||||
|
||||
if (reactorPart.HasRodType(ReactorPartComponent.RodTypes.GasChannel))
|
||||
neutrons = ProcessNeutronsGas(reactorPart, neutrons);
|
||||
|
||||
neutrons ??= [];
|
||||
thermalEnergy = (reactorPart.Temperature - preCalcTemp) * reactorPart.ThermalMass;
|
||||
return neutrons;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processes neutrons interacting with gas in a reactor part.
|
||||
/// </summary>
|
||||
/// <param name="reactorPart">The reactor part to process neutrons for.</param>
|
||||
/// <param name="neutrons">The list of neutrons to process.</param>
|
||||
/// <returns>The updated list of neutrons after processing.</returns>
|
||||
private List<ReactorNeutron> ProcessNeutronsGas(ReactorPartComponent reactorPart, List<ReactorNeutron> neutrons)
|
||||
{
|
||||
if (reactorPart.AirContents == null) return neutrons;
|
||||
|
||||
var flux = new List<ReactorNeutron>(neutrons);
|
||||
foreach (var neutron in flux)
|
||||
{
|
||||
if (neutron.velocity > 0)
|
||||
{
|
||||
var neutronCount = GasNeutronInteract(reactorPart);
|
||||
if (neutronCount > 1)
|
||||
for (var i = 0; i < neutronCount; i++)
|
||||
neutrons.Add(new() { dir = _random.NextAngle().GetDir(), velocity = _random.Next(1, 3 + 1) });
|
||||
else if (neutronCount < 1)
|
||||
neutrons.Remove(neutron);
|
||||
}
|
||||
}
|
||||
|
||||
return neutrons;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs neutron interactions with the gas in the reactor part.
|
||||
/// </summary>
|
||||
/// <param name="reactorPart">The reactor part to process neutron interactions for.</param>
|
||||
/// <returns>Change in number of neutrons.</returns>
|
||||
private int GasNeutronInteract(ReactorPartComponent reactorPart)
|
||||
{
|
||||
if (reactorPart.AirContents == null)
|
||||
return 1;
|
||||
|
||||
var neutronCount = 1;
|
||||
var gas = reactorPart.AirContents;
|
||||
|
||||
if (gas.GetMoles(Gas.Plasma) > 1)
|
||||
{
|
||||
var reactMolPerLiter = 0.25;
|
||||
var reactMol = reactMolPerLiter * gas.Volume;
|
||||
|
||||
var plasma = gas.GetMoles(Gas.Plasma);
|
||||
var plasmaReactCount = (int)Math.Round((plasma - (plasma % reactMol)) / reactMol) + (Prob(plasma - (plasma % reactMol)) ? 1 : 0);
|
||||
plasmaReactCount = _random.Next(0, plasmaReactCount + 1);
|
||||
gas.AdjustMoles(Gas.Plasma, plasmaReactCount * -0.5f);
|
||||
gas.AdjustMoles(Gas.Tritium, plasmaReactCount * 2);
|
||||
neutronCount += plasmaReactCount;
|
||||
}
|
||||
|
||||
if (gas.GetMoles(Gas.CarbonDioxide) > 1)
|
||||
{
|
||||
var reactMolPerLiter = 0.4;
|
||||
var reactMol = reactMolPerLiter * gas.Volume;
|
||||
|
||||
var co2 = gas.GetMoles(Gas.CarbonDioxide);
|
||||
var co2ReactCount = (int)Math.Round((co2 - (co2 % reactMol)) / reactMol) + (Prob(co2 - (co2 % reactMol)) ? 1 : 0);
|
||||
co2ReactCount = _random.Next(0, co2ReactCount + 1);
|
||||
reactorPart.Temperature += Math.Min(co2ReactCount, neutronCount);
|
||||
neutronCount -= Math.Min(co2ReactCount, neutronCount);
|
||||
}
|
||||
|
||||
if (gas.GetMoles(Gas.Tritium) > 1)
|
||||
{
|
||||
var reactMolPerLiter = 0.5;
|
||||
var reactMol = reactMolPerLiter * gas.Volume;
|
||||
|
||||
var tritium = gas.GetMoles(Gas.Tritium);
|
||||
var tritiumReactCount = (int)Math.Round((tritium - (tritium % reactMol)) / reactMol) + (Prob(tritium - (tritium % reactMol)) ? 1 : 0);
|
||||
tritiumReactCount = _random.Next(0, tritiumReactCount + 1);
|
||||
if (tritiumReactCount > 0)
|
||||
{
|
||||
gas.AdjustMoles(Gas.Tritium, -1 * tritiumReactCount);
|
||||
reactorPart.Temperature += 1 * tritiumReactCount;
|
||||
switch (_random.Next(0, 5))
|
||||
{
|
||||
case 0:
|
||||
gas.AdjustMoles(Gas.Oxygen, 0.5f * tritiumReactCount);
|
||||
break;
|
||||
case 1:
|
||||
gas.AdjustMoles(Gas.Nitrogen, 0.5f * tritiumReactCount);
|
||||
break;
|
||||
case 2:
|
||||
gas.AdjustMoles(Gas.Ammonia, 0.1f * tritiumReactCount);
|
||||
break;
|
||||
case 3:
|
||||
gas.AdjustMoles(Gas.NitrousOxide, 0.1f * tritiumReactCount);
|
||||
break;
|
||||
case 4:
|
||||
gas.AdjustMoles(Gas.Frezon, 0.1f * tritiumReactCount);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return neutronCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Probablity check that accepts chances > 100%
|
||||
/// </summary>
|
||||
/// <param name="chance">The chance percentage between 0 and 100.</param>
|
||||
private bool Prob(double chance) => _random.NextDouble() <= chance / 100;
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,679 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.Explosion.EntitySystems;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.Weapons.Ranged.Systems;
|
||||
using Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Random;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Shared.DeviceLinking.Events;
|
||||
using Content.Server.DeviceLinking.Systems;
|
||||
using Content.Shared.Construction.Components;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Content.Shared.DeviceNetwork;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Robust.Shared.Containers;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Server.Audio;
|
||||
using Content.Shared.Audio;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Server._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/turbine.dm
|
||||
|
||||
public sealed class TurbineSystem : SharedTurbineSystem
|
||||
{
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
[Dependency] private readonly ExplosionSystem _explosion = default!;
|
||||
[Dependency] private readonly GunSystem _gun = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly TransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = null!;
|
||||
[Dependency] private readonly DeviceLinkSystem _signal = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly AmbientSoundSystem _ambientSoundSystem = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
|
||||
private readonly List<string> _damageSoundList = [
|
||||
"/Audio/_FarHorizons/Effects/engine_grump1.ogg",
|
||||
"/Audio/_FarHorizons/Effects/engine_grump2.ogg",
|
||||
"/Audio/_FarHorizons/Effects/engine_grump3.ogg",
|
||||
"/Audio/Effects/metal_slam5.ogg",
|
||||
"/Audio/Effects/metal_scrape2.ogg"
|
||||
];
|
||||
|
||||
private sealed class LogData
|
||||
{
|
||||
public TimeSpan CreationTime;
|
||||
public float? SetFlowRate;
|
||||
public float? SetStatorLoad;
|
||||
}
|
||||
|
||||
private readonly Dictionary<KeyValuePair<EntityUid, EntityUid>, LogData> _logQueue = [];
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<TurbineComponent, MapInitEvent>(OnInit);
|
||||
SubscribeLocalEvent<TurbineComponent, ComponentShutdown>(OnShutdown);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, DamageChangedEvent>(OnDamaged);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, ItemSlotInsertAttemptEvent>(OnInsertAttempt);
|
||||
SubscribeLocalEvent<TurbineComponent, ItemSlotEjectAttemptEvent>(OnEjectAttempt);
|
||||
SubscribeLocalEvent<TurbineComponent, EntInsertedIntoContainerMessage>(OnPartInserted);
|
||||
SubscribeLocalEvent<TurbineComponent, EntRemovedFromContainerMessage>(OnPartEjected);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, AtmosDeviceUpdateEvent>(OnUpdate);
|
||||
SubscribeLocalEvent<TurbineComponent, GasAnalyzerScanEvent>(OnAnalyze);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, TurbineChangeFlowRateMessage>(OnTurbineFlowRateChanged);
|
||||
SubscribeLocalEvent<TurbineComponent, TurbineChangeStatorLoadMessage>(OnTurbineStatorLoadChanged);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, SignalReceivedEvent>(OnSignalReceived);
|
||||
SubscribeLocalEvent<TurbineComponent, PortDisconnectedEvent>(OnPortDisconnected);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
||||
SubscribeLocalEvent<TurbineComponent, UnanchorAttemptEvent>(OnUnanchorAttempt);
|
||||
}
|
||||
|
||||
private const string BladeContainer = "blade_slot";
|
||||
private const string StatorContainer = "stator_slot";
|
||||
|
||||
private void OnInit(EntityUid uid, TurbineComponent comp, ref MapInitEvent args)
|
||||
{
|
||||
_signal.EnsureSourcePorts(uid, comp.SpeedHighPort, comp.SpeedLowPort, comp.TurbineDataPort);
|
||||
_signal.EnsureSinkPorts(uid, comp.StatorLoadIncreasePort, comp.StatorLoadDecreasePort);
|
||||
|
||||
TryGetPart(uid, BladeContainer, out comp.CurrentBlade);
|
||||
TryGetPart(uid, StatorContainer, out comp.CurrentStator);
|
||||
|
||||
UpdatePartValues(comp);
|
||||
|
||||
comp.AlarmAudioOvertemp = SpawnAttachedTo("GasTurbineAlarmEntity", new(uid, 0, 0));
|
||||
comp.AlarmAudioUnderspeed = SpawnAttachedTo("GasTurbineAlarmEntity", new(uid, 0, 0));
|
||||
_ambientSoundSystem.SetSound(comp.AlarmAudioUnderspeed.Value, new SoundPathSpecifier("/Audio/_FarHorizons/Machines/alarm_beep.ogg"));
|
||||
_ambientSoundSystem.SetVolume(comp.AlarmAudioUnderspeed.Value, -4);
|
||||
}
|
||||
|
||||
private bool TryGetPart(EntityUid uid, string slot, [NotNullWhen(true)] out EntityUid? part)
|
||||
{
|
||||
part = null;
|
||||
|
||||
if (!_containerSystem.TryGetContainer(uid, slot, out var container) || container.ContainedEntities.Count == 0)
|
||||
return false;
|
||||
|
||||
part = container.ContainedEntities[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnAnalyze(EntityUid uid, TurbineComponent comp, ref GasAnalyzerScanEvent args)
|
||||
{
|
||||
if (!comp.InletEnt.HasValue || !comp.OutletEnt.HasValue)
|
||||
return;
|
||||
|
||||
args.GasMixtures ??= [];
|
||||
|
||||
if (_nodeContainer.TryGetNode(comp.InletEnt.Value, comp.PipeName, out PipeNode? inlet) && inlet.Air.Volume != 0f)
|
||||
{
|
||||
var inletAirLocal = inlet.Air.Clone();
|
||||
inletAirLocal.Multiply(inlet.Volume / inlet.Air.Volume);
|
||||
inletAirLocal.Volume = inlet.Volume;
|
||||
args.GasMixtures.Add((Loc.GetString("gas-analyzer-window-text-inlet"), inletAirLocal));
|
||||
}
|
||||
|
||||
if (_nodeContainer.TryGetNode(comp.OutletEnt.Value, comp.PipeName, out PipeNode? outlet) && outlet.Air.Volume != 0f)
|
||||
{
|
||||
var outletAirLocal = outlet.Air.Clone();
|
||||
outletAirLocal.Multiply(outlet.Volume / outlet.Air.Volume);
|
||||
outletAirLocal.Volume = outlet.Volume;
|
||||
args.GasMixtures.Add((Loc.GetString("gas-analyzer-window-text-outlet"), outletAirLocal));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnShutdown(EntityUid uid, TurbineComponent comp, ref ComponentShutdown args)
|
||||
{
|
||||
QueueDel(comp.InletEnt);
|
||||
QueueDel(comp.OutletEnt);
|
||||
}
|
||||
|
||||
#region Main Loop
|
||||
private void OnUpdate(EntityUid uid, TurbineComponent comp, ref AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var supplier = Comp<PowerSupplierComponent>(uid);
|
||||
comp.SupplierMaxSupply = supplier.MaxSupply;
|
||||
comp.SupplierLastSupply = supplier.CurrentSupply;
|
||||
|
||||
supplier.MaxSupply = comp.LastGen;
|
||||
|
||||
if(!GetPipes(uid, comp, out var inlet, out var outlet))
|
||||
return;
|
||||
|
||||
if (comp.CurrentBlade == null || comp.CurrentStator == null)
|
||||
comp.Ruined = true;
|
||||
|
||||
UpdateAppearance(uid, comp);
|
||||
|
||||
var transferVolume = CalculateTransferVolume(comp, inlet, outlet, args.dt);
|
||||
|
||||
var AirContents = inlet.Air.RemoveVolume(transferVolume) ?? new GasMixture();
|
||||
|
||||
comp.LastVolumeTransfer = transferVolume;
|
||||
comp.LastGen = 0;
|
||||
comp.Overtemp = AirContents.Temperature >= comp.MaxTemp - 500;
|
||||
comp.Undertemp = AirContents.Temperature <= comp.MinTemp;
|
||||
|
||||
// Dump gas into atmosphere
|
||||
if (comp.Ruined || AirContents.Temperature >= comp.MaxTemp)
|
||||
{
|
||||
var tile = _atmosphereSystem.GetTileMixture(uid, excite: true);
|
||||
|
||||
if (tile != null)
|
||||
{
|
||||
_atmosphereSystem.Merge(tile, AirContents);
|
||||
}
|
||||
|
||||
// This does rely on the alarm existing, but if it doesn't then there are bigger problems
|
||||
if (!comp.Ruined && _entityManager.TryGetComponent<AmbientSoundComponent>(comp.AlarmAudioOvertemp, out var ambience) && !ambience.Enabled)
|
||||
_popupSystem.PopupEntity(Loc.GetString("turbine-overheat", ("owner", uid)), uid, PopupType.LargeCaution);
|
||||
|
||||
// Prevent power from being generated by residual gasses
|
||||
AirContents.Clear();
|
||||
}
|
||||
|
||||
if(Exists(comp.AlarmAudioOvertemp))
|
||||
_ambientSoundSystem.SetAmbience(comp.AlarmAudioOvertemp.Value, !comp.Ruined && AirContents.Temperature >= comp.MaxTemp);
|
||||
|
||||
// Update stator load based on device network
|
||||
if (comp.IncreasePortState != SignalState.Low)
|
||||
AdjustStatorLoad(comp, 1000);
|
||||
if (comp.DecreasePortState != SignalState.Low)
|
||||
AdjustStatorLoad(comp, -1000);
|
||||
|
||||
if (comp.IncreasePortState == SignalState.Momentary)
|
||||
comp.IncreasePortState = SignalState.Low;
|
||||
if (comp.DecreasePortState == SignalState.Momentary)
|
||||
comp.DecreasePortState = SignalState.Low;
|
||||
|
||||
if (!comp.Ruined && AirContents != null)
|
||||
{
|
||||
var InputStartingEnergy = _atmosphereSystem.GetThermalEnergy(AirContents);
|
||||
var InputHeatCap = _atmosphereSystem.GetHeatCapacity(AirContents, true);
|
||||
|
||||
// Prevents div by 0 if it would come up
|
||||
if (InputStartingEnergy <= 0)
|
||||
{
|
||||
InputStartingEnergy = 1;
|
||||
}
|
||||
if (InputHeatCap <= 0)
|
||||
{
|
||||
InputHeatCap = 1;
|
||||
}
|
||||
|
||||
if (AirContents.Temperature > comp.MinTemp)
|
||||
{
|
||||
AirContents.Temperature = (float)Math.Max((InputStartingEnergy - ((InputStartingEnergy - (InputHeatCap * Atmospherics.T20C)) * 0.8)) / InputHeatCap, Atmospherics.T20C);
|
||||
}
|
||||
|
||||
var OutputStartingEnergy = _atmosphereSystem.GetThermalEnergy(AirContents);
|
||||
var EnergyGenerated = comp.StatorLoad * (comp.RPM / 60);
|
||||
|
||||
var DeltaE = InputStartingEnergy - OutputStartingEnergy;
|
||||
float NewRPM;
|
||||
|
||||
if (DeltaE - EnergyGenerated > 0)
|
||||
{
|
||||
NewRPM = comp.RPM + (float)Math.Sqrt(2 * (Math.Max(DeltaE - EnergyGenerated, 0) / comp.TurbineMass));
|
||||
}
|
||||
else
|
||||
{
|
||||
NewRPM = comp.RPM - (float)Math.Sqrt(2 * (Math.Max(EnergyGenerated - DeltaE, 0) / comp.TurbineMass));
|
||||
}
|
||||
|
||||
var NextGen = comp.StatorLoad * (Math.Max(NewRPM, 0) / 60);
|
||||
float NextRPM;
|
||||
|
||||
if (DeltaE - NextGen > 0)
|
||||
{
|
||||
NextRPM = comp.RPM + (float)Math.Sqrt(2 * (Math.Max(DeltaE - NextGen, 0) / comp.TurbineMass));
|
||||
}
|
||||
else
|
||||
{
|
||||
NextRPM = comp.RPM - (float)Math.Sqrt(2 * (Math.Max(NextGen - DeltaE, 0) / comp.TurbineMass));
|
||||
}
|
||||
|
||||
if (NewRPM < 0 || NextRPM < 0)
|
||||
{
|
||||
// Stator load is too high
|
||||
comp.Stalling = true;
|
||||
comp.RPM = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
comp.Stalling = false;
|
||||
comp.RPM = NextRPM;
|
||||
}
|
||||
|
||||
if(Exists(comp.AlarmAudioUnderspeed))
|
||||
_ambientSoundSystem.SetAmbience(comp.AlarmAudioUnderspeed.Value, !comp.Ruined && comp.Stalling && !comp.Undertemp && comp.FlowRate > 0);
|
||||
|
||||
if (comp.RPM > 10)
|
||||
{
|
||||
// Sacrifices must be made to have a smooth ramp up:
|
||||
// This will generate 2 audio streams every second with up to 4 of them playing at once... surely this can't go wrong :clueless:
|
||||
_audio.PlayPvs(new SoundPathSpecifier("/Audio/_FarHorizons/Ambience/Objects/turbine_room.ogg"), uid, AudioParams.Default.WithPitchScale(comp.RPM / comp.BestRPM).WithVolume(-2));
|
||||
}
|
||||
|
||||
// Calculate power generation
|
||||
comp.LastGen = comp.PowerMultiplier * comp.StatorLoad * (comp.RPM / 30) * (float)(1 / Math.Cosh(0.01 * (comp.RPM - comp.BestRPM)));
|
||||
|
||||
if (float.IsNaN(comp.LastGen))
|
||||
throw new NotFiniteNumberException("Turbine made NaN power");
|
||||
|
||||
comp.Overspeed = comp.RPM > comp.BestRPM * 1.2;
|
||||
|
||||
// Damage the turbines during overspeed, linear increase from 18% to 45% then stays at 45%
|
||||
if (comp.Overspeed && _random.NextFloat() < 0.15 * Math.Min(comp.RPM / comp.BestRPM, 3))
|
||||
{
|
||||
// TODO: damage flash
|
||||
_audio.PlayPvs(new SoundPathSpecifier(_damageSoundList[_random.Next(0, _damageSoundList.Count - 1)]), uid, AudioParams.Default.WithVariation(0.25f).WithVolume(-1));
|
||||
comp.BladeHealth--;
|
||||
UpdateHealthIndicators(uid, comp);
|
||||
}
|
||||
|
||||
_atmosphereSystem.Merge(outlet.Air, AirContents);
|
||||
}
|
||||
|
||||
// Explode
|
||||
if (!comp.Ruined && (comp.BladeHealth <= 0|| comp.RPM>comp.BestRPM*4))
|
||||
{
|
||||
TearApart(uid, comp);
|
||||
}
|
||||
|
||||
// Send signals to device network
|
||||
_signal.SendSignal(uid, comp.SpeedHighPort, comp.RPM > comp.BestRPM * 1.05);
|
||||
_signal.SendSignal(uid, comp.SpeedLowPort, comp.RPM < comp.BestRPM * 0.95);
|
||||
|
||||
Dirty(uid, comp);
|
||||
UpdateUI(uid, comp);
|
||||
}
|
||||
|
||||
private float CalculateTransferVolume(TurbineComponent comp, PipeNode inlet, PipeNode outlet, float dt)
|
||||
{
|
||||
var wantToTransfer = comp.FlowRate * _atmosphereSystem.PumpSpeedup() * dt;
|
||||
var transferVolume = Math.Min(inlet.Air.Volume, wantToTransfer);
|
||||
var transferMoles = inlet.Air.Pressure * transferVolume / (inlet.Air.Temperature * Atmospherics.R);
|
||||
var molesSpaceLeft = (comp.OutputPressure - outlet.Air.Pressure) * outlet.Air.Volume / (outlet.Air.Temperature * Atmospherics.R);
|
||||
var actualMolesTransfered = Math.Clamp(transferMoles, 0, Math.Max(0, molesSpaceLeft));
|
||||
return Math.Max(0, actualMolesTransfered * inlet.Air.Temperature * Atmospherics.R / inlet.Air.Pressure);
|
||||
}
|
||||
|
||||
private void TearApart(EntityUid uid, TurbineComponent comp)
|
||||
{
|
||||
_audio.PlayPvs(new SoundPathSpecifier("/Audio/Effects/metal_break5.ogg"), uid, AudioParams.Default);
|
||||
_popupSystem.PopupEntity(Loc.GetString("turbine-explode", ("owner", uid)), uid, PopupType.LargeCaution);
|
||||
|
||||
_explosion.QueueExplosion(uid, "Default", comp.RPM / 10, 15, 5, 0, canCreateVacuum: false);
|
||||
|
||||
if (comp.RPM > comp.BestRPM / 6) // If it's barely moving then there's not really reason it would throw shrapnel
|
||||
ShootShrapnel(uid);
|
||||
|
||||
_adminLogger.Add(LogType.Explosion, LogImpact.High, $"{ToPrettyString(uid)} destroyed by overspeeding for too long");
|
||||
|
||||
comp.Ruined = true;
|
||||
comp.RPM = 0;
|
||||
_entityManager.QueueDeleteEntity(comp.CurrentBlade);
|
||||
comp.CurrentBlade = null;
|
||||
|
||||
UpdateAppearance(uid, comp);
|
||||
}
|
||||
|
||||
private void ShootShrapnel(EntityUid uid)
|
||||
{
|
||||
var ShrapnelCount = _random.Next(5, 20);
|
||||
for (var i=0;i< ShrapnelCount; i++)
|
||||
{
|
||||
_gun.ShootProjectile(Spawn("TurbineBladeShrapnel", _transformSystem.GetMapCoordinates(uid)), _random.NextAngle().ToVec().Normalized(), _random.NextVector2(2, 6), uid, uid);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region BUI
|
||||
public void UpdateUI(EntityUid uid, TurbineComponent turbine)
|
||||
{
|
||||
if (!_uiSystem.IsUiOpen(uid, TurbineUiKey.Key))
|
||||
return;
|
||||
|
||||
_uiSystem.SetUiState(uid, TurbineUiKey.Key,
|
||||
new TurbineBuiState
|
||||
{
|
||||
Overspeed = turbine.Overspeed,
|
||||
Stalling = turbine.Stalling,
|
||||
Overtemp = turbine.Overtemp,
|
||||
Undertemp = turbine.Undertemp,
|
||||
|
||||
RPM = turbine.RPM,
|
||||
BestRPM = turbine.BestRPM,
|
||||
|
||||
FlowRateMin = 0,
|
||||
FlowRateMax = turbine.FlowRateMax,
|
||||
FlowRate = turbine.FlowRate,
|
||||
|
||||
StatorLoadMin = 1000,
|
||||
StatorLoad = turbine.StatorLoad,
|
||||
|
||||
PowerGeneration = turbine.SupplierMaxSupply,
|
||||
PowerSupply = turbine.SupplierLastSupply,
|
||||
|
||||
Health = turbine.BladeHealth,
|
||||
HealthMax = turbine.BladeHealthMax,
|
||||
|
||||
Blade = _entityManager.GetNetEntity(turbine.CurrentBlade),
|
||||
Stator = _entityManager.GetNetEntity(turbine.CurrentStator),
|
||||
});
|
||||
}
|
||||
|
||||
private void OnTurbineFlowRateChanged(EntityUid uid, TurbineComponent turbine, TurbineChangeFlowRateMessage args)
|
||||
{
|
||||
if(TrySetFlowRate())
|
||||
{
|
||||
// Data is sent to a log queue to avoid spamming the admin log when adjusting values rapidly
|
||||
var key = new KeyValuePair<EntityUid, EntityUid>(args.Actor, uid);
|
||||
if(!_logQueue.TryGetValue(key, out var value))
|
||||
_logQueue.Add(key, new LogData
|
||||
{
|
||||
CreationTime = _gameTiming.RealTime,
|
||||
SetFlowRate = turbine.FlowRate
|
||||
});
|
||||
else
|
||||
value.SetFlowRate = turbine.FlowRate;
|
||||
}
|
||||
|
||||
UpdateUI(uid, turbine);
|
||||
|
||||
return;
|
||||
|
||||
bool TrySetFlowRate()
|
||||
{
|
||||
var newSet = Math.Clamp(args.FlowRate, 0f, turbine.FlowRateMax);
|
||||
if (turbine.FlowRate != newSet)
|
||||
{
|
||||
turbine.FlowRate = newSet;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTurbineStatorLoadChanged(EntityUid uid, TurbineComponent turbine, TurbineChangeStatorLoadMessage args)
|
||||
{
|
||||
if (TrySetStatorLoad())
|
||||
{
|
||||
// Data is sent to a log queue to avoid spamming the admin log when adjusting values rapidly
|
||||
var key = new KeyValuePair<EntityUid, EntityUid>(args.Actor, uid);
|
||||
if (!_logQueue.TryGetValue(key, out var value))
|
||||
_logQueue.Add(key, new LogData
|
||||
{
|
||||
CreationTime = _gameTiming.RealTime,
|
||||
SetStatorLoad = turbine.StatorLoad
|
||||
});
|
||||
else
|
||||
value.SetStatorLoad = turbine.StatorLoad;
|
||||
}
|
||||
|
||||
UpdateUI(uid, turbine);
|
||||
|
||||
return;
|
||||
|
||||
bool TrySetStatorLoad()
|
||||
{
|
||||
var newSet = Math.Max(args.StatorLoad, 1000f);
|
||||
if (turbine.StatorLoad != newSet)
|
||||
{
|
||||
turbine.StatorLoad = newSet;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private float _accumulator = 0f;
|
||||
private readonly float _threshold = 0.5f;
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
_accumulator += frameTime;
|
||||
if (_accumulator > _threshold)
|
||||
{
|
||||
UpdateLogs();
|
||||
_accumulator = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
void UpdateLogs()
|
||||
{
|
||||
var toRemove = new List<KeyValuePair<EntityUid, EntityUid>>();
|
||||
foreach (var log in _logQueue.Where(log => !((_gameTiming.RealTime - log.Value.CreationTime).TotalSeconds < 2)))
|
||||
{
|
||||
toRemove.Add(log.Key);
|
||||
|
||||
if (log.Value.SetFlowRate != null)
|
||||
_adminLogger.Add(LogType.AtmosVolumeChanged, LogImpact.Medium,
|
||||
$"{ToPrettyString(log.Key.Key):player} set the flow rate on {ToPrettyString(log.Key.Value):device} to {log.Value.SetFlowRate}");
|
||||
|
||||
if (log.Value.SetStatorLoad != null)
|
||||
_adminLogger.Add(LogType.AtmosDeviceSetting, LogImpact.Medium,
|
||||
$"{ToPrettyString(log.Key.Key):player} set the stator load on {ToPrettyString(log.Key.Value):device} to {log.Value.SetStatorLoad}");
|
||||
}
|
||||
|
||||
foreach (var kvp in toRemove)
|
||||
_logQueue.Remove(kvp);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OnSignalReceived(EntityUid uid, TurbineComponent comp, ref SignalReceivedEvent args)
|
||||
{
|
||||
var state = SignalState.Momentary;
|
||||
args.Data?.TryGetValue(DeviceNetworkConstants.LogicState, out state);
|
||||
|
||||
if (args.Port == comp.StatorLoadIncreasePort)
|
||||
comp.IncreasePortState = state;
|
||||
else if (args.Port == comp.StatorLoadDecreasePort)
|
||||
comp.DecreasePortState = state;
|
||||
|
||||
var logtext = "maintain";
|
||||
if (comp.IncreasePortState != SignalState.Low && comp.DecreasePortState == SignalState.Low)
|
||||
logtext = "increase";
|
||||
else if (comp.DecreasePortState != SignalState.Low && comp.IncreasePortState == SignalState.Low)
|
||||
logtext = "decrease";
|
||||
|
||||
_adminLogger.Add(LogType.Action, $"{ToPrettyString(args.Trigger):trigger} set the stator load on {ToPrettyString(uid):target} to {logtext}");
|
||||
}
|
||||
|
||||
private void OnPortDisconnected(EntityUid uid, TurbineComponent comp, ref PortDisconnectedEvent args)
|
||||
{
|
||||
if (args.Port == comp.StatorLoadIncreasePort)
|
||||
comp.IncreasePortState = SignalState.Low;
|
||||
if (args.Port == comp.StatorLoadDecreasePort)
|
||||
comp.DecreasePortState = SignalState.Low;
|
||||
}
|
||||
|
||||
#region Anchoring
|
||||
private void OnAnchorChanged(EntityUid uid, TurbineComponent comp, ref AnchorStateChangedEvent args)
|
||||
{
|
||||
if (!args.Anchored)
|
||||
{
|
||||
CleanUp(comp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUnanchorAttempt(EntityUid uid, TurbineComponent comp, ref UnanchorAttemptEvent args)
|
||||
{
|
||||
if (comp.RPM>1)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("turbine-unanchor-warning"), args.User, args.User, PopupType.LargeCaution);
|
||||
args.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private bool GetPipes(EntityUid uid, TurbineComponent comp, [NotNullWhen(true)] out PipeNode? inlet, [NotNullWhen(true)] out PipeNode? outlet)
|
||||
{
|
||||
inlet = null;
|
||||
outlet = null;
|
||||
|
||||
if (!comp.InletEnt.HasValue || EntityManager.Deleted(comp.InletEnt.Value))
|
||||
comp.InletEnt = SpawnAttachedTo(comp.PipePrototype, new(uid, comp.InletPos), rotation: Angle.FromDegrees(comp.InletRot));
|
||||
if (!comp.OutletEnt.HasValue || EntityManager.Deleted(comp.OutletEnt.Value))
|
||||
comp.OutletEnt = SpawnAttachedTo(comp.PipePrototype, new(uid, comp.OutletPos), rotation: Angle.FromDegrees(comp.OutletRot));
|
||||
|
||||
if (comp.InletEnt == null || comp.OutletEnt == null)
|
||||
return false;
|
||||
|
||||
if (!Transform(comp.InletEnt.Value).Anchored || !Transform(comp.OutletEnt.Value).Anchored)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("turbine-anchor-warning"), uid, PopupType.MediumCaution);
|
||||
CleanUp(comp);
|
||||
_transform.Unanchor(uid);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_nodeContainer.TryGetNode(comp.InletEnt.Value, comp.PipeName, out inlet))
|
||||
return false;
|
||||
if (!_nodeContainer.TryGetNode(comp.OutletEnt.Value, comp.PipeName, out outlet))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void CleanUp(TurbineComponent comp)
|
||||
{
|
||||
QueueDel(comp.InletEnt);
|
||||
QueueDel(comp.OutletEnt);
|
||||
}
|
||||
|
||||
private void OnDamaged(EntityUid uid, TurbineComponent comp, ref DamageChangedEvent args)
|
||||
{
|
||||
if (comp.Ruined)
|
||||
return;
|
||||
|
||||
if (!args.DamageIncreased || args.DamageDelta == null)
|
||||
return;
|
||||
|
||||
var damage = (float)args.DamageDelta.GetTotal();
|
||||
var threshold = 50;
|
||||
var ratio = damage / threshold;
|
||||
|
||||
if(ratio < 1)
|
||||
{
|
||||
comp.BladeHealth -= _random.Next(1, (int)(3f * ratio) + 1);
|
||||
UpdateHealthIndicators(uid, comp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (comp.RPM > comp.BestRPM / 6)
|
||||
TearApart(uid, comp);
|
||||
_entityManager.QueueDeleteEntity(comp.CurrentBlade);
|
||||
comp.CurrentBlade = null;
|
||||
if (_random.Prob(Math.Clamp(ratio - 1f, 0, 1)))
|
||||
{
|
||||
_entityManager.QueueDeleteEntity(comp.CurrentStator);
|
||||
comp.CurrentStator = null;
|
||||
}
|
||||
comp.Ruined = true;
|
||||
}
|
||||
|
||||
private void OnEjectAttempt(EntityUid uid, TurbineComponent comp, ref ItemSlotEjectAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (comp.RPM < 1)
|
||||
return;
|
||||
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnInsertAttempt(EntityUid uid, TurbineComponent comp, ref ItemSlotInsertAttemptEvent args)
|
||||
{
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
if (comp.RPM < 1)
|
||||
return;
|
||||
|
||||
args.Cancelled = true;
|
||||
}
|
||||
|
||||
private void OnPartInserted(EntityUid uid, TurbineComponent comp, ref EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
switch (args.Container.ID)
|
||||
{
|
||||
case BladeContainer:
|
||||
comp.CurrentBlade = args.Container.ContainedEntities[0];
|
||||
break;
|
||||
case StatorContainer:
|
||||
comp.CurrentStator = args.Container.ContainedEntities[0];
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
UpdatePartValues(comp);
|
||||
}
|
||||
|
||||
private void OnPartEjected(EntityUid uid, TurbineComponent comp, ref EntRemovedFromContainerMessage args)
|
||||
{
|
||||
switch (args.Container.ID)
|
||||
{
|
||||
case BladeContainer:
|
||||
comp.CurrentBlade = null;
|
||||
break;
|
||||
case StatorContainer:
|
||||
comp.CurrentStator = null;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
UpdatePartValues(comp);
|
||||
}
|
||||
|
||||
private void UpdatePartValues(TurbineComponent comp)
|
||||
{
|
||||
_entityManager.TryGetComponent<GasTurbineBladeComponent>(comp.CurrentBlade, out var bladeComp);
|
||||
_entityManager.TryGetComponent<GasTurbineStatorComponent>(comp.CurrentStator, out var statorComp);
|
||||
|
||||
if (bladeComp != null)
|
||||
{
|
||||
comp.TurbineMass = Math.Max(200, 200 * bladeComp.Properties.Density);
|
||||
comp.BladeHealthMax = (int)Math.Max(1, 5 * bladeComp.Properties.Hardness);
|
||||
comp.BladeHealth = comp.BladeHealthMax;
|
||||
}
|
||||
|
||||
if (statorComp != null)
|
||||
{
|
||||
comp.PowerMultiplier = (float)Math.Max(0.2, 0.2 * statorComp.Properties.ElectricalConductivity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._FarHorizons.Materials; //Far Horizons Nuclear Reactor Port
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -56,5 +57,12 @@ namespace Content.Shared.Materials
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public double Price = 0;
|
||||
|
||||
// Far Horizons Edit
|
||||
/// <summary>
|
||||
/// The physical properties of this material.
|
||||
/// </summary>
|
||||
[DataField("properties")]
|
||||
public MaterialProperties Properties { get; private set; } = new();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
namespace Content.Shared._FarHorizons.Materials;
|
||||
|
||||
/// <summary>
|
||||
/// A data type that stores information on a material's properties
|
||||
/// </summary>
|
||||
[DataDefinition]
|
||||
public sealed partial class MaterialProperties()
|
||||
{
|
||||
[DataField("electrical")]
|
||||
public float ElectricalConductivity { get; set; } = 5;
|
||||
|
||||
[DataField("thermal")]
|
||||
public float ThermalConductivity { get; set; } = 5;
|
||||
|
||||
[DataField("hard")]
|
||||
public float Hardness { get; set; } = 3;
|
||||
|
||||
[DataField("density")]
|
||||
public float Density { get; set; } = 3;
|
||||
|
||||
[DataField("reflective")]
|
||||
public float Reflectivity { get; set; } = 0;
|
||||
|
||||
[DataField("flammable")]
|
||||
public float Flammability { get; set; } = 1;
|
||||
|
||||
[DataField("chemical")]
|
||||
public float ChemicalResistance { get; set; } = 3;
|
||||
|
||||
[DataField("radioactive")]
|
||||
public float Radioactivity { get; set; } = 0;
|
||||
|
||||
[DataField("n_radioactive")]
|
||||
public float NeutronRadioactivity { get; set; } = 0;
|
||||
|
||||
[DataField("spent_fuel")]
|
||||
public float FissileIsotopes { get; set; } = 0;
|
||||
|
||||
[DataField("molitz_bubbles")]
|
||||
public float GasPockets { get; set; } = 0;
|
||||
|
||||
[DataField("plasma_offgas")]
|
||||
public float ActivePlasma { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="MaterialProperties"> with information from an existing one.
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
public MaterialProperties(MaterialProperties source) : this()
|
||||
{
|
||||
ElectricalConductivity = source.ElectricalConductivity;
|
||||
ThermalConductivity = source.ThermalConductivity;
|
||||
Hardness = source.Hardness;
|
||||
Density = source.Density;
|
||||
Reflectivity = source.Reflectivity;
|
||||
Flammability = source.Flammability;
|
||||
ChemicalResistance = source.ChemicalResistance;
|
||||
Radioactivity = source.Radioactivity;
|
||||
NeutronRadioactivity = source.NeutronRadioactivity;
|
||||
FissileIsotopes = source.FissileIsotopes;
|
||||
GasPockets = source.GasPockets;
|
||||
ActivePlasma = source.ActivePlasma;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
namespace Content.Shared._FarHorizons.Materials.Systems;
|
||||
|
||||
public sealed class MaterialSystem
|
||||
{
|
||||
public static double CalculateHeatTransferCoefficient(MaterialProperties? materialA, MaterialProperties? materialB)
|
||||
{
|
||||
var hTC1 = 5.0;
|
||||
var hTC2 = 5.0;
|
||||
|
||||
if (materialA != null)
|
||||
if (materialA.ThermalConductivity > 0 && materialA.ElectricalConductivity > 0)
|
||||
hTC1 = (Math.Max(materialA.ThermalConductivity, 0) + Math.Max(materialA.ElectricalConductivity, 0)) / 2;
|
||||
else if (materialA.ThermalConductivity > 0)
|
||||
hTC1 = Math.Max(materialA.ThermalConductivity, 0);
|
||||
else if (materialA.ElectricalConductivity > 0)
|
||||
hTC1 = Math.Max(materialA.ElectricalConductivity, 0);
|
||||
if (materialB != null)
|
||||
if (materialB.ThermalConductivity > 0 && materialB.ElectricalConductivity > 0)
|
||||
hTC2 = (Math.Max(materialB.ThermalConductivity, 0) + Math.Max(materialB.ElectricalConductivity, 0)) / 2;
|
||||
else if (materialB.ThermalConductivity > 0)
|
||||
hTC2 = Math.Max(materialB.ThermalConductivity, 0);
|
||||
else if (materialB.ElectricalConductivity > 0)
|
||||
hTC2 = Math.Max(materialB.ElectricalConductivity, 0);
|
||||
|
||||
return ((Math.Pow(10, hTC1 / 5) - 1) + (Math.Pow(10, hTC2 / 5) - 1)) / 2;
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class GasTurbineMonitorComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public NetEntity? turbine;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<SinkPortPrototype> LinkingPort = "GasTurbineDataReceiver";
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
using Content.Shared._FarHorizons.Materials;
|
||||
using Content.Shared.Materials;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
public abstract partial class GasTurbinePartComponent : Component
|
||||
{
|
||||
[Dependency] private IPrototypeManager _proto = default!;
|
||||
|
||||
[DataField("material")]
|
||||
public ProtoId<MaterialPrototype> Material = "Steel";
|
||||
|
||||
public MaterialProperties Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
IoCManager.Resolve(ref _proto);
|
||||
_properties ??= new MaterialProperties(_proto.Index(Material).Properties);
|
||||
|
||||
return _properties;
|
||||
}
|
||||
set => _properties = value;
|
||||
}
|
||||
[DataField("properties")]
|
||||
private MaterialProperties? _properties;
|
||||
}
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class GasTurbineBladeComponent : GasTurbinePartComponent;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class GasTurbineStatorComponent : GasTurbinePartComponent;
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Audio;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.Serialization;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/nuclearreactor.dm
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class NuclearReactorComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Width of the reactor grid
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||
public int ReactorGridWidth = 7;
|
||||
|
||||
/// <summary>
|
||||
/// Height of the reactor grid
|
||||
/// </summary>
|
||||
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||
public int ReactorGridHeight = 7;
|
||||
|
||||
public readonly int ReactorOverheatTemp = 1200;
|
||||
public readonly int ReactorFireTemp = 1500;
|
||||
public readonly int ReactorMeltdownTemp = 2000;
|
||||
|
||||
// Making this a DataField causes the game to explode, neat
|
||||
/// <summary>
|
||||
/// 2D grid of reactor components, or null where there are no components. Size is ReactorGridWidth x ReactorGridHeight
|
||||
/// </summary>
|
||||
public ReactorPartComponent?[,] ComponentGrid;
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary of data that determines the reactor grid's visuals
|
||||
/// </summary>
|
||||
[AutoNetworkedField]
|
||||
public Dictionary<Vector2i, ReactorCapVisualData> VisualData = [];
|
||||
|
||||
// Woe, 3 dimensions be upon ye
|
||||
/// <summary>
|
||||
/// 2D grid of lists of neutrons in each grid slot of the component grid
|
||||
/// </summary>
|
||||
public List<ReactorNeutron>[,] FluxGrid;
|
||||
|
||||
/// <summary>
|
||||
/// Number of neutrons that hit the edge of the reactor grid last tick
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public float RadiationLevel = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gas mixture currently in the reactor
|
||||
/// </summary>
|
||||
public GasMixture? AirContents;
|
||||
|
||||
/// <summary>
|
||||
/// Reactor casing temperature
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float Temperature = Atmospherics.T20C;
|
||||
|
||||
/// <summary>
|
||||
/// Thermal mass. Basically how much energy it takes to heat this up 1Kelvin
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ThermalMass = 420 * 2000; // specific heat capacity of steel (420 J/KgK) * mass of reactor (Kg)
|
||||
|
||||
/// <summary>
|
||||
/// Volume of gas to process each tick
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ReactorVesselGasVolume = 200;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating the reactor is overheating
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool IsSmoking = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating the reactor is on fire
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool IsBurning = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating total meltdown has happened
|
||||
/// </summary>
|
||||
[DataField, ViewVariables, AutoNetworkedField]
|
||||
public bool Melted = false;
|
||||
|
||||
/// <summary>
|
||||
/// The set insertion level of the control rods
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ControlRodInsertion = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The actual insertion level of the control rods
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float AvgInsertion = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Sound that plays globally on meltdown
|
||||
/// </summary>
|
||||
public SoundSpecifier MeltdownSound = new SoundPathSpecifier("/Audio/_FarHorizons/Machines/meltdown_siren.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Radio channel to send alerts to
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string EngineeringChannel = "Engineering";
|
||||
|
||||
/// <summary>
|
||||
/// Last reported temperature during overheat events
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public float LastSendTemperature = Atmospherics.T20C;
|
||||
|
||||
/// <summary>
|
||||
/// If the reactor has given the nuclear emergency warning
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool HasSentWarning = false;
|
||||
|
||||
/// <summary>
|
||||
/// Alert level to set after meltdown
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string MeltdownAlertLevel = "yellow";
|
||||
|
||||
/// <summary>
|
||||
/// The minimum radiation from the melted reactor
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float MeltdownRadiation = 10;
|
||||
|
||||
/// <summary>
|
||||
/// How quickly radiation decreases
|
||||
/// </summary>
|
||||
/// <remarks>Cannot be less than 1</remarks>
|
||||
[DataField]
|
||||
public float RadiationStability = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The soft maximum radiation the reactor is expected to produce, beyond which radiation increases logarithmically. Also used for alarms and UI.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float MaximumRadiation = 50;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum thermal power the reactor is expected to produce
|
||||
/// </summary>
|
||||
/// <remarks>This will NOT stop the reactor from making more than this value</remarks>
|
||||
[DataField]
|
||||
public float MaximumThermalPower = 10000000;
|
||||
|
||||
/// <summary>
|
||||
/// The estimated thermal power the reactor is making
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float ThermalPower = 0;
|
||||
public int ThermalPowerCount = 0;
|
||||
public int ThermalPowerPrecision = 128;
|
||||
|
||||
[ViewVariables]
|
||||
public EntityUid? AlarmAudioHighThermal;
|
||||
[ViewVariables]
|
||||
public EntityUid? AlarmAudioHighTemp;
|
||||
[ViewVariables]
|
||||
public EntityUid? AlarmAudioHighRads;
|
||||
|
||||
[ViewVariables]
|
||||
public ItemSlot PartSlot = new();
|
||||
|
||||
/// <summary>
|
||||
/// Grid of temperature values
|
||||
/// </summary>
|
||||
public double[,] TemperatureGrid;
|
||||
|
||||
/// <summary>
|
||||
/// Grid of neutron counts
|
||||
/// </summary>
|
||||
public int[,] NeutronGrid;
|
||||
|
||||
/// <summary>
|
||||
/// The selected prefab
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string Prefab = "ReactorPrefab7x7Normal";
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating the reactor should apply the selected prefab
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool ApplyPrefab = false;
|
||||
|
||||
/// <summary>
|
||||
/// Chance that a reactor slot is filled when applying the random prefab
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float RandomPrefabFill = 0.3f;
|
||||
|
||||
/// <summary>
|
||||
/// Material the reactor is made out of
|
||||
/// </summary>
|
||||
[DataField("material")]
|
||||
public ProtoId<MaterialPrototype> Material = "Steel";
|
||||
|
||||
/// <summary>
|
||||
/// Determines the spacing and position of the visual grid. Measured in pixels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// [0] Spacing along the x axis<br/>
|
||||
/// [1] Spacing along the y axis<br/>
|
||||
/// [2] Offset of the center along the x axis<br/>
|
||||
/// [3] Offset of the center along the y axis
|
||||
/// </remarks>
|
||||
[DataField]
|
||||
public int[] Gridbounds = [ 18, 15, 0, 5 ];
|
||||
|
||||
#region Pipe Connections
|
||||
/// <summary>
|
||||
/// Name of the pipe node
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string PipeName { get; set; } = "pipe";
|
||||
|
||||
/// <summary>
|
||||
/// Inlet entity
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public EntityUid? InletEnt;
|
||||
|
||||
/// <summary>
|
||||
/// Position of the inlet entity
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Vector2 InletPos = new(-2, -1);
|
||||
|
||||
/// <summary>
|
||||
/// Rotation of the inlet entity, in degrees
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float InletRot = -90;
|
||||
|
||||
/// <summary>
|
||||
/// Outlet entity
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public EntityUid? OutletEnt;
|
||||
|
||||
/// <summary>
|
||||
/// Position of the outlet entity
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Vector2 OutletPos = new(2, 1);
|
||||
|
||||
/// <summary>
|
||||
/// Rotation of the outlet entity, in degrees
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float OutletRot = 90;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the prototype of the arrows that indicate flow on inspect
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId ArrowPrototype = "ReactorFlowArrow";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the prototype of the pipes the reactor uses to connect to the pipe network
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId PipePrototype = "ReactorGasPipe";
|
||||
#endregion
|
||||
|
||||
#region Device Network
|
||||
/// <summary>
|
||||
/// The proto ID of the "Retract Control Rods" sink port
|
||||
/// </summary>
|
||||
[DataField("controlRodRetractPort", customTypeSerializer: typeof(PrototypeIdSerializer<SinkPortPrototype>))]
|
||||
public string ControlRodRetractPort = "RetractControlRods";
|
||||
|
||||
/// <summary>
|
||||
/// The proto ID of the "Insert Control Rods" sink port
|
||||
/// </summary>
|
||||
[DataField("controlRodInsertPort", customTypeSerializer: typeof(PrototypeIdSerializer<SinkPortPrototype>))]
|
||||
public string ControlRodInsertPort = "InsertControlRods";
|
||||
|
||||
/// <summary>
|
||||
/// The signal state of the retract control rods port
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SignalState RetractPortState = SignalState.Low;
|
||||
|
||||
/// <summary>
|
||||
/// The signal state of the insert control rods port
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SignalState InsertPortState = SignalState.Low;
|
||||
#endregion
|
||||
|
||||
#region Debug
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public int NeutronCount = 0;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public int MeltedParts = 0;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public int DetectedControlRods = 0;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float TotalNRads = 0;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float TotalRads = 0;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float TotalSpent = 0;
|
||||
#endregion
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable, DataDefinition]
|
||||
public sealed partial class ReactorCapVisualData
|
||||
{
|
||||
public Color color = Color.Black;
|
||||
public string cap = "";
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class NuclearReactorMonitorComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public NetEntity? reactor;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<SinkPortPrototype> LinkingPort = "NuclearReactorDataReceiver";
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
[Prototype]
|
||||
public sealed partial class NuclearReactorPrefabPrototype : IPrototype
|
||||
{
|
||||
[ViewVariables]
|
||||
[IdDataField]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[DataField("parts")]
|
||||
public Dictionary<Vector2i, EntProtoId> ReactorComponents { get; private set; } = [];
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
using Content.Shared._FarHorizons.Materials;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.Materials;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/reactorcomponents.dm
|
||||
|
||||
/// <summary>
|
||||
/// A reactor part for the reactor grid.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class ReactorPartComponent : Component
|
||||
{
|
||||
[Dependency] private IPrototypeManager _proto = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The entity prototype name this component results from.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId ProtoId = "BaseReactorPart";
|
||||
|
||||
/// <summary>
|
||||
/// Icon of this component as it shows in the UIs.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string IconStateInserted = "base";
|
||||
|
||||
/// <summary>
|
||||
/// Icon of this component as it shows in the world.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string IconStateCap = "rod_cap";
|
||||
|
||||
/// <summary>
|
||||
/// Byte indicating what type of rod this reactor part is
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public int RodType = 0;
|
||||
|
||||
public enum RodTypes
|
||||
{
|
||||
None = 0,
|
||||
FuelRod = 1 << 0, // 1 Can be processed by the nuclear centrifuge
|
||||
ControlRod = 1 << 1, // 2 Can change its NeutronCrossSection according to control rod setting
|
||||
GasChannel = 1 << 2, // 4 Can process gas
|
||||
}
|
||||
|
||||
#region Variables
|
||||
/// <summary>
|
||||
/// Temperature of this component, starts at room temp Kelvin by default.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float Temperature = Atmospherics.T20C;
|
||||
|
||||
/// <summary>
|
||||
/// How much does this component share heat with surrounding components? Basically surface area in contact (m2).
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ThermalCrossSection = 10;
|
||||
|
||||
/// <summary>
|
||||
/// How adept is this component at interacting with neutrons - fuel rods are set up to capture them, heat exchangers are set up not to.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float NeutronCrossSection = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Control rods don't moderate neutrons, they absorb them.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool IsControlRod = false;
|
||||
|
||||
/// <summary>
|
||||
/// Max health to set <see cref="MeltHealth"/> to on init.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float MaxHealth = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Essentially indicates how long this component can be at a dangerous temperature before it melts.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float MeltHealth = 100;
|
||||
|
||||
/// <summary>
|
||||
/// If this component is melted, you can't take it out of the reactor and it might do some weird stuff.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool Melted = false;
|
||||
|
||||
/// <summary>
|
||||
/// The dangerous temperature above which this component starts to melt. 1700K is the melting point of steel.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float MeltingPoint = 1700;
|
||||
|
||||
/// <summary>
|
||||
/// How much gas this component can hold, and will be processed per tick.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float GasVolume = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Thermal mass. Basically how much energy it takes to heat this up 1Kelvin.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ThermalMass = 420 * 250; //specific heat capacity of steel (420 J/KgK) * mass of component (Kg)
|
||||
#endregion
|
||||
|
||||
[DataField("material")]
|
||||
public ProtoId<MaterialPrototype> Material = "Steel";
|
||||
|
||||
public MaterialProperties Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
IoCManager.Resolve(ref _proto);
|
||||
_properties ??= new MaterialProperties(_proto.Index(Material).Properties);
|
||||
|
||||
return _properties;
|
||||
}
|
||||
set => _properties = value;
|
||||
}
|
||||
[DataField("properties")]
|
||||
private MaterialProperties? _properties;
|
||||
|
||||
#region Type specific
|
||||
/// <summary>
|
||||
/// The target insertion level of the control rod.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float ConfiguredInsertionLevel = 1;
|
||||
|
||||
/// <summary>
|
||||
/// How adept the gas channel is at transfering heat to/from gasses.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float GasThermalCrossSection = 15; //was 15
|
||||
|
||||
/// <summary>
|
||||
/// The gas mixture inside the gas channel.
|
||||
/// </summary>
|
||||
public GasMixture? AirContents;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="ReactorPartComponent"> with information from an existing one.
|
||||
/// </summary>
|
||||
/// <param name="source"></param>
|
||||
public ReactorPartComponent(ReactorPartComponent source)
|
||||
{
|
||||
ProtoId = source.ProtoId;
|
||||
IconStateInserted = source.IconStateInserted;
|
||||
IconStateCap = source.IconStateCap;
|
||||
RodType = source.RodType;
|
||||
|
||||
Temperature = source.Temperature;
|
||||
ThermalCrossSection = source.ThermalCrossSection;
|
||||
NeutronCrossSection = source.NeutronCrossSection;
|
||||
IsControlRod = source.IsControlRod;
|
||||
MaxHealth = source.MaxHealth;
|
||||
MeltHealth = source.MeltHealth;
|
||||
Melted = source.Melted;
|
||||
MeltingPoint = source.MeltingPoint;
|
||||
GasVolume = source.GasVolume;
|
||||
ThermalMass = source.ThermalMass;
|
||||
|
||||
Material = source.Material;
|
||||
_properties = source._properties;
|
||||
|
||||
ConfiguredInsertionLevel = source.ConfiguredInsertionLevel;
|
||||
GasThermalCrossSection = source.GasThermalCrossSection;
|
||||
AirContents = source.AirContents;
|
||||
}
|
||||
|
||||
public bool HasRodType(RodTypes type) => (RodType & (int)type) == (int)type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A virtual neutron that flies around within the reactor.
|
||||
/// </summary>
|
||||
[NetworkedComponent]
|
||||
public sealed class ReactorNeutron
|
||||
{
|
||||
public Direction dir = Direction.North;
|
||||
public float velocity = 1;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum NuclearCentrifugeVisuals
|
||||
{
|
||||
Processing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum NuclearCentrifugeVisualLayers
|
||||
{
|
||||
Processing
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum NuclearReactorUiKey : byte
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class NuclearReactorBuiState : BoundUserInterfaceState
|
||||
{
|
||||
public Dictionary<Vector2i, ReactorSlotBUIData> SlotData = [];
|
||||
|
||||
public int GridWidth = 0;
|
||||
public int GridHeight = 0;
|
||||
|
||||
public string? ItemName;
|
||||
|
||||
public float ReactorTemp = 0;
|
||||
public float ReactorRads = 0;
|
||||
public float ReactorRadsMax = 0;
|
||||
public float ReactorTherm = 0;
|
||||
public float ControlRodActual = 0;
|
||||
public float ControlRodSet = 0;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable, DataDefinition]
|
||||
public sealed partial class ReactorSlotBUIData
|
||||
{
|
||||
public double Temperature = 0f;
|
||||
public int NeutronCount = 0;
|
||||
public string IconName = "base";
|
||||
public string PartName = "empty";
|
||||
|
||||
public float NeutronRadioactivity = 0f;
|
||||
public float Radioactivity = 0f;
|
||||
public float SpentFuel = 0f;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ReactorItemActionMessage(Vector2d position) : BoundUserInterfaceMessage
|
||||
{
|
||||
public Vector2d Position { get; } = position;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ReactorEjectItemMessage() : BoundUserInterfaceMessage;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ReactorControlRodModifyMessage(float change) : BoundUserInterfaceMessage
|
||||
{
|
||||
public float Change { get; } = change;
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/nuclearreactor.dm
|
||||
|
||||
public abstract class SharedNuclearReactorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ItemSlotsSystem _slotsSystem = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
// BUI event
|
||||
SubscribeLocalEvent<NuclearReactorComponent, ReactorEjectItemMessage>(OnEjectItemMessage);
|
||||
}
|
||||
|
||||
private void OnEjectItemMessage(EntityUid uid, NuclearReactorComponent component, ReactorEjectItemMessage args)
|
||||
{
|
||||
if (component.PartSlot.Item == null)
|
||||
return;
|
||||
|
||||
_slotsSystem.TryEjectToHands(uid, component.PartSlot, args.Actor);
|
||||
}
|
||||
|
||||
protected bool ReactorTryGetSlot(EntityUid uid, string slotID, out ItemSlot? itemSlot) => _slotsSystem.TryGetSlot(uid, slotID, out itemSlot);
|
||||
|
||||
public void UpdateGridVisual(Entity<NuclearReactorComponent> ent)
|
||||
{
|
||||
var comp = ent.Comp;
|
||||
var uid = ent.Owner;
|
||||
|
||||
if (comp.ComponentGrid == null)
|
||||
return;
|
||||
|
||||
for (var x = 0; x < comp.ReactorGridWidth; x++)
|
||||
{
|
||||
for (var y = 0; y < comp.ReactorGridHeight; y++)
|
||||
{
|
||||
var gridComp = comp.ComponentGrid[x, y];
|
||||
var vector = new Vector2i(x, y);
|
||||
|
||||
if (gridComp == null)
|
||||
{
|
||||
comp.VisualData.Remove(vector);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = new ReactorCapVisualData { cap = gridComp.IconStateCap, color = _proto.Index(gridComp.Material).Color };
|
||||
if (!comp.VisualData.TryAdd(vector, data))
|
||||
comp.VisualData[vector] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
Dirty(ent);
|
||||
|
||||
// Sanity check to make sure there is actually an appearance component (nullpointer hell)
|
||||
if (!_entityManager.HasComponent<AppearanceComponent>(uid))
|
||||
return;
|
||||
|
||||
// The data being set doesn't really matter, it just has to trigger AppearanceChangeEvent and the client will handle the rest
|
||||
if (!_appearance.TryGetData(uid, ReactorCapVisuals.Sprite, out bool prevValue))
|
||||
_appearance.SetData(uid, ReactorCapVisuals.Sprite, true);
|
||||
_appearance.SetData(uid, ReactorCapVisuals.Sprite, !prevValue);
|
||||
}
|
||||
|
||||
protected void UpdateTempIndicators(Entity<NuclearReactorComponent> ent)
|
||||
{
|
||||
var comp = ent.Comp;
|
||||
var uid = ent.Owner;
|
||||
|
||||
if (comp.Temperature >= comp.ReactorOverheatTemp)
|
||||
{
|
||||
if(!comp.IsSmoking)
|
||||
{
|
||||
comp.IsSmoking = true;
|
||||
_appearance.SetData(uid, ReactorVisuals.Smoke, true);
|
||||
_popupSystem.PopupEntity(Loc.GetString("reactor-smoke-start", ("owner", uid)), uid, PopupType.MediumCaution);
|
||||
}
|
||||
if (comp.Temperature >= comp.ReactorFireTemp && !comp.IsBurning)
|
||||
{
|
||||
comp.IsBurning = true;
|
||||
_appearance.SetData(uid, ReactorVisuals.Fire, true);
|
||||
_popupSystem.PopupEntity(Loc.GetString("reactor-fire-start", ("owner", uid)), uid, PopupType.MediumCaution);
|
||||
}
|
||||
else if (comp.Temperature < comp.ReactorFireTemp && comp.IsBurning)
|
||||
{
|
||||
comp.IsBurning = false;
|
||||
_appearance.SetData(uid, ReactorVisuals.Fire, false);
|
||||
_popupSystem.PopupEntity(Loc.GetString("reactor-fire-stop", ("owner", uid)), uid, PopupType.Medium);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(comp.IsSmoking)
|
||||
{
|
||||
comp.IsSmoking = false;
|
||||
_appearance.SetData(uid, ReactorVisuals.Smoke, false);
|
||||
_popupSystem.PopupEntity(Loc.GetString("reactor-smoke-stop", ("owner", uid)), uid, PopupType.Medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool AdjustControlRods(NuclearReactorComponent comp, float change) {
|
||||
var newSet = Math.Clamp(comp.ControlRodInsertion + change, 0, 2);
|
||||
if (comp.ControlRodInsertion != newSet)
|
||||
{
|
||||
comp.ControlRodInsertion = newSet;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
#region Reactor Caps
|
||||
/// <summary>
|
||||
/// Appearance key for the reactor caps.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum ReactorCapVisuals
|
||||
{
|
||||
Sprite
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Reactor
|
||||
/// <summary>
|
||||
/// Appearance keys for the reactor.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum ReactorVisuals
|
||||
{
|
||||
Sprite,
|
||||
Status,
|
||||
Input,
|
||||
Output,
|
||||
Lights,
|
||||
Smoke,
|
||||
Fire,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visual sprite layers for the reactor.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum ReactorVisualLayers
|
||||
{
|
||||
Sprite,
|
||||
Status,
|
||||
Input,
|
||||
Output,
|
||||
Lights,
|
||||
Smoke,
|
||||
Fire,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reactor sprites.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum Reactors
|
||||
{
|
||||
Normal,
|
||||
Melted,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Status screens.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum ReactorStatusLights
|
||||
{
|
||||
Off,
|
||||
Active,
|
||||
Overheat,
|
||||
Meltdown,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warning lights settings.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum ReactorWarningLights
|
||||
{
|
||||
LightsOff,
|
||||
LightsWarning,
|
||||
LightsMeltdown,
|
||||
}
|
||||
#endregion
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
public abstract class SharedReactorPartSystem : EntitySystem;
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum TurbineUiKey : byte
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class TurbineBuiState : BoundUserInterfaceState
|
||||
{
|
||||
// Indicator Lights
|
||||
public bool Overspeed;
|
||||
public bool Stalling;
|
||||
public bool Overtemp;
|
||||
public bool Undertemp;
|
||||
|
||||
// Speed
|
||||
public float RPM;
|
||||
public float BestRPM;
|
||||
|
||||
// Flow rate
|
||||
public float FlowRateMin;
|
||||
public float FlowRateMax;
|
||||
public float FlowRate;
|
||||
|
||||
// Stator load
|
||||
public float StatorLoadMin;
|
||||
public float StatorLoad;
|
||||
|
||||
// Power generation
|
||||
public float PowerGeneration;
|
||||
public float PowerSupply;
|
||||
|
||||
// Health
|
||||
public float Health;
|
||||
public float HealthMax;
|
||||
|
||||
// Parts
|
||||
public NetEntity? Blade;
|
||||
public NetEntity? Stator;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class TurbineChangeFlowRateMessage(float flowRate) : BoundUserInterfaceMessage
|
||||
{
|
||||
public float FlowRate { get; } = flowRate;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class TurbineChangeStatorLoadMessage(float statorLoad) : BoundUserInterfaceMessage
|
||||
{
|
||||
public float StatorLoad { get; } = statorLoad;
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Damage.Components;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.Electrocution;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Repairable;
|
||||
using Content.Shared.Tools.Systems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/turbine.dm
|
||||
|
||||
public abstract class SharedTurbineSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||
[Dependency] protected readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
[Dependency] private readonly SharedToolSystem _toolSystem = default!;
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, ExaminedEvent>(OnExamined);
|
||||
|
||||
SubscribeLocalEvent<TurbineComponent, InteractUsingEvent>(RepairTurbine);
|
||||
SubscribeLocalEvent<TurbineComponent, RepairDoAfterEvent>(OnRepairTurbineFinished);
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<TurbineComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
var comp = ent.Comp;
|
||||
if (!Comp<TransformComponent>(ent).Anchored || !args.IsInDetailsRange) // Not anchored? Out of range? No status.
|
||||
return;
|
||||
|
||||
using (args.PushGroup(nameof(TurbineComponent)))
|
||||
{
|
||||
if(comp.CurrentStator == null)
|
||||
args.PushMarkup(Loc.GetString("gas-turbine-examine-stator-null"));
|
||||
|
||||
if (comp.CurrentBlade == null)
|
||||
args.PushMarkup(Loc.GetString("gas-turbine-examine-blade-null"));
|
||||
else
|
||||
{
|
||||
switch (comp.RPM)
|
||||
{
|
||||
case float n when n is >= 0 and <= 1:
|
||||
args.PushMarkup(Loc.GetString("turbine-spinning-0")); // " The blades are not spinning."
|
||||
break;
|
||||
case float n when n is > 1 and <= 60:
|
||||
args.PushMarkup(Loc.GetString("turbine-spinning-1")); // " The blades are turning slowly."
|
||||
break;
|
||||
case float n when n > 60 && n <= comp.BestRPM * 0.5:
|
||||
args.PushMarkup(Loc.GetString("turbine-spinning-2")); // " The blades are spinning."
|
||||
break;
|
||||
case float n when n > comp.BestRPM * 0.5 && n <= comp.BestRPM * 1.2:
|
||||
args.PushMarkup(Loc.GetString("turbine-spinning-3")); // " The blades are spinning quickly."
|
||||
break;
|
||||
case float n when n > comp.BestRPM * 1.2 && n <= float.PositiveInfinity:
|
||||
args.PushMarkup(Loc.GetString("turbine-spinning-4")); // " The blades are spinning out of control!"
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (comp.Ruined)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("turbine-ruined")); // " It's completely broken!"
|
||||
}
|
||||
else if (comp.BladeHealth <= 0.25 * comp.BladeHealthMax)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("turbine-damaged-3")); // " It's critically damaged!"
|
||||
}
|
||||
else if (comp.BladeHealth <= 0.5 * comp.BladeHealthMax)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("turbine-damaged-2")); // " The turbine looks badly damaged."
|
||||
}
|
||||
else if (comp.BladeHealth <= 0.75 * comp.BladeHealthMax)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("turbine-damaged-1")); // " The turbine looks a bit scuffed."
|
||||
}
|
||||
else
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("turbine-damaged-0")); // " It appears to be in good condition."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void UpdateAppearance(EntityUid uid, TurbineComponent? comp = null, AppearanceComponent? appearance = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp, ref appearance, false))
|
||||
return;
|
||||
|
||||
_appearance.SetData(uid, TurbineVisuals.TurbineRuined, comp.Ruined);
|
||||
|
||||
_appearance.SetData(uid, TurbineVisuals.DamageSpark, comp.IsSparking);
|
||||
_appearance.SetData(uid, TurbineVisuals.DamageSmoke, comp.IsSmoking);
|
||||
}
|
||||
|
||||
protected void PlayAudio(SoundSpecifier? sound, EntityUid uid, out EntityUid? audioStream, AudioParams? audioParams = null)
|
||||
{
|
||||
if (sound == null || audioParams == null)
|
||||
{
|
||||
audioStream = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var loop = audioParams.Value.WithLoop(true);
|
||||
var stream = false
|
||||
? _audio.PlayPredicted(sound, uid, uid, loop)
|
||||
: _audio.PlayPvs(sound, uid, loop);
|
||||
audioStream = stream?.Entity is { } entity ? entity : null;
|
||||
}
|
||||
|
||||
protected static bool AdjustStatorLoad(TurbineComponent turbine, float change)
|
||||
{
|
||||
var newSet = Math.Max(turbine.StatorLoad + change, 1000f);
|
||||
if (turbine.StatorLoad != newSet)
|
||||
{
|
||||
turbine.StatorLoad = newSet;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Repairs
|
||||
private void RepairTurbine(EntityUid uid, TurbineComponent comp, ref InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if(_toolSystem.HasQuality(args.Used, comp.RepairTool))
|
||||
{
|
||||
if (comp.CurrentBlade == null)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("gas-turbine-repair-fail-blade"), args.User, args.User, PopupType.Medium);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (comp.CurrentStator == null)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("gas-turbine-repair-fail-stator"), args.User, args.User, PopupType.Medium);
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (comp.BladeHealth >= comp.BladeHealthMax && !comp.Ruined)
|
||||
return;
|
||||
|
||||
args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, comp.RepairDelay, comp.RepairTool, new RepairDoAfterEvent(), comp.RepairFuelCost);
|
||||
}
|
||||
}
|
||||
|
||||
//Gotta love server/client desync
|
||||
protected virtual void OnRepairTurbineFinished(EntityUid uid, TurbineComponent comp, ref RepairDoAfterEvent args)
|
||||
{
|
||||
if (comp.Ruined)
|
||||
{
|
||||
comp.Ruined = false;
|
||||
if (comp.BladeHealth <= 0) { comp.BladeHealth = 1; }
|
||||
UpdateHealthIndicators(uid, comp);
|
||||
}
|
||||
else if (comp.BladeHealth < comp.BladeHealthMax)
|
||||
{
|
||||
comp.BladeHealth++;
|
||||
UpdateHealthIndicators(uid, comp);
|
||||
}
|
||||
else if (comp.BladeHealth >= comp.BladeHealthMax)
|
||||
{
|
||||
// This should technically never occur, but just in case...
|
||||
}
|
||||
|
||||
if (!_entityManager.TryGetComponent<DamageableComponent>(uid, out var damageableComponent))
|
||||
return;
|
||||
|
||||
_damageableSystem.SetAllDamage((uid, damageableComponent), 0);
|
||||
}
|
||||
|
||||
protected void UpdateHealthIndicators(EntityUid uid, TurbineComponent comp)
|
||||
{
|
||||
if (comp.BladeHealth <= 0.75 * comp.BladeHealthMax && !comp.IsSparking)
|
||||
{
|
||||
comp.IsSparking = true;
|
||||
_audio.PlayPvs(new SoundPathSpecifier("/Audio/Effects/PowerSink/electric.ogg"), uid, AudioParams.Default.WithPitchScale(0.75f));
|
||||
_popupSystem.PopupEntity(Loc.GetString("turbine-spark", ("owner", uid)), uid, PopupType.MediumCaution);
|
||||
}
|
||||
else if (comp.BladeHealth > 0.75 * comp.BladeHealthMax && comp.IsSparking)
|
||||
{
|
||||
comp.IsSparking = false;
|
||||
_popupSystem.PopupEntity(Loc.GetString("turbine-spark-stop", ("owner", uid)), uid, PopupType.Medium);
|
||||
}
|
||||
|
||||
if (comp.BladeHealth <= 0.5 * comp.BladeHealthMax && !comp.IsSmoking)
|
||||
{
|
||||
comp.IsSmoking = true;
|
||||
_popupSystem.PopupEntity(Loc.GetString("turbine-smoke", ("owner", uid)), uid, PopupType.MediumCaution);
|
||||
}
|
||||
else if (comp.BladeHealth > 0.5 * comp.BladeHealthMax && comp.IsSmoking)
|
||||
{
|
||||
comp.IsSmoking = false;
|
||||
_popupSystem.PopupEntity(Loc.GetString("turbine-smoke-stop", ("owner", uid)), uid, PopupType.Medium);
|
||||
}
|
||||
|
||||
_entityManager.EnsureComponent<ElectrifiedComponent>(uid).Enabled = comp.IsSparking;
|
||||
|
||||
UpdateAppearance(uid, comp);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
/// <summary>
|
||||
/// Appearance keys for the turbine.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum TurbineVisuals
|
||||
{
|
||||
TurbineRuined,
|
||||
DamageSpark,
|
||||
DamageSmoke,
|
||||
TurbineSpeed,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Visual sprite layers for the turbine.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum TurbineVisualLayers
|
||||
{
|
||||
TurbineRuined,
|
||||
DamageSpark,
|
||||
DamageSmoke,
|
||||
TurbineSpeed,
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.GameStates;
|
||||
using Content.Shared.Tools;
|
||||
using Content.Shared.Atmos;
|
||||
using Content.Shared.DeviceLinking;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Shared._FarHorizons.Power.Generation.FissionGenerator;
|
||||
|
||||
// Ported and modified from goonstation by Jhrushbe.
|
||||
// CC-BY-NC-SA-3.0
|
||||
// https://github.com/goonstation/goonstation/blob/ff86b044/code/obj/nuclearreactor/turbine.dm
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class TurbineComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Power generated last tick
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float LastGen = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Watts per revolution
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float StatorLoad = 35000;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum setting of stator load
|
||||
/// </summary>
|
||||
// [DataField]
|
||||
// public float StatorLoadMax = 500000;
|
||||
|
||||
/// <summary>
|
||||
/// Current RPM of turbine
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||
public float RPM = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Turbine's resistance to change in RPM
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float TurbineMass = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Most efficient power generation at this value, overspeed at 1.2*this
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float BestRPM = 600;
|
||||
|
||||
/// <summary>
|
||||
/// RPM the animation is playing at
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public float AnimRPM = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Volume of gas to process per tick for power generation
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float FlowRate = Atmospherics.MaxTransferRate;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum volume of gas to process per tick
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float FlowRateMax = Atmospherics.MaxTransferRate * 5;
|
||||
|
||||
[DataField]
|
||||
public float OutputPressure = Atmospherics.MaxOutputPressure * 3;
|
||||
|
||||
/// <summary>
|
||||
/// Max/min temperatures
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float MaxTemp = 3000;
|
||||
[DataField]
|
||||
public float MinTemp = Atmospherics.T20C;
|
||||
|
||||
/// <summary>
|
||||
/// Health of the turbine
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public int BladeHealth = 15;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum health of the turbine
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public int BladeHealthMax = 15;
|
||||
|
||||
/// <summary>
|
||||
/// If the turbine is functional or not
|
||||
/// </summary>
|
||||
[DataField, ViewVariables, AutoNetworkedField]
|
||||
public bool Ruined = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating the turbine is sparking
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool IsSparking = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag indicating the turbine is smoking
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool IsSmoking = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag for indicating that energy available is less than needed to turn the turbine
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Stalling = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag for RPM being > BestRPM*1.2
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Overspeed = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag for gas temperature being > MaxTemp - 500
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Overtemp = false;
|
||||
|
||||
/// <summary>
|
||||
/// Flag for gas temperature being < MinTemp
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Undertemp = false;
|
||||
|
||||
/// <summary>
|
||||
/// Adjustment for power generation
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float PowerMultiplier = 1;
|
||||
|
||||
[ViewVariables, AutoNetworkedField]
|
||||
public EntityUid? AlarmAudioOvertemp;
|
||||
[ViewVariables, AutoNetworkedField]
|
||||
public EntityUid? AlarmAudioUnderspeed;
|
||||
|
||||
/// <summary>
|
||||
/// Length of repair do-after, in seconds
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float RepairDelay = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Amount of fuel consumed for repair
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float RepairFuelCost = 15;
|
||||
|
||||
/// <summary>
|
||||
/// Tool capability needed to repair
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public ProtoId<ToolQualityPrototype> RepairTool = "Welding";
|
||||
|
||||
/// <summary>
|
||||
/// The blade currently installed in the turbine
|
||||
/// </summary>
|
||||
[ViewVariables, AutoNetworkedField]
|
||||
public EntityUid? CurrentBlade;
|
||||
|
||||
/// <summary>
|
||||
/// The stator currently installed in the turbine
|
||||
/// </summary>
|
||||
[ViewVariables, AutoNetworkedField]
|
||||
public EntityUid? CurrentStator;
|
||||
|
||||
#region Pipe Connections
|
||||
/// <summary>
|
||||
/// Name of the pipe node
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string PipeName { get; set; } = "pipe";
|
||||
|
||||
/// <summary>
|
||||
/// Inlet entity
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public EntityUid? InletEnt;
|
||||
|
||||
/// <summary>
|
||||
/// Position of the inlet entity
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Vector2 InletPos = new(-1, -1);
|
||||
|
||||
/// <summary>
|
||||
/// Rotation of the inlet entity, in degrees
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float InletRot = -90;
|
||||
|
||||
/// <summary>
|
||||
/// Outlet entity
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public EntityUid? OutletEnt;
|
||||
|
||||
/// <summary>
|
||||
/// Position of the outlet entity
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Vector2 OutletPos = new(1, -1);
|
||||
|
||||
/// <summary>
|
||||
/// Rotation of the outlet entity, in degrees
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float OutletRot = 90;
|
||||
|
||||
/// <summary>
|
||||
/// Name of the prototype of the arrows that indicate flow on inspect
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId ArrowPrototype = "TurbineFlowArrow";
|
||||
|
||||
/// <summary>
|
||||
/// Name of the prototype of the pipes the turbine uses to connect to the pipe network
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntProtoId PipePrototype = "TurbineGasPipe";
|
||||
#endregion
|
||||
|
||||
#region Device Network
|
||||
/// <summary>
|
||||
/// The proto ID of the "Speed: High" source port
|
||||
/// </summary>
|
||||
[DataField("speedHighPort", customTypeSerializer: typeof(PrototypeIdSerializer<SourcePortPrototype>))]
|
||||
public string SpeedHighPort = "TurbineSpeedHigh";
|
||||
|
||||
/// <summary>
|
||||
/// The proto ID of the "Speed: Low" source port
|
||||
/// </summary>
|
||||
[DataField("speedLowPort", customTypeSerializer: typeof(PrototypeIdSerializer<SourcePortPrototype>))]
|
||||
public string SpeedLowPort = "TurbineSpeedLow";
|
||||
|
||||
/// <summary>
|
||||
/// The proto ID of the "Turbine Data" source port
|
||||
/// </summary>
|
||||
[DataField("turbineDataPort", customTypeSerializer: typeof(PrototypeIdSerializer<SourcePortPrototype>))]
|
||||
public string TurbineDataPort = "GasTurbineDataSender";
|
||||
|
||||
/// <summary>
|
||||
/// The proto ID of the "Increase Stator Load" sink port
|
||||
/// </summary>
|
||||
[DataField("statorLoadIncreasePort", customTypeSerializer: typeof(PrototypeIdSerializer<SinkPortPrototype>))]
|
||||
public string StatorLoadIncreasePort = "IncreaseStatorLoad";
|
||||
|
||||
/// <summary>
|
||||
/// The proto ID of the "Decrease Stator Load" sink port
|
||||
/// </summary>
|
||||
[DataField("statorLoadDecreasePort", customTypeSerializer: typeof(PrototypeIdSerializer<SinkPortPrototype>))]
|
||||
public string StatorLoadDecreasePort = "DecreaseStatorLoad";
|
||||
|
||||
/// <summary>
|
||||
/// The signal state of the increase stator load port
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SignalState IncreasePortState = SignalState.Low;
|
||||
|
||||
/// <summary>
|
||||
/// The signal state of the decrease stator load port
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SignalState DecreasePortState = SignalState.Low;
|
||||
#endregion
|
||||
|
||||
#region Debug
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool HasPipes = false;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float SupplierMaxSupply = 0;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float SupplierLastSupply = 0;
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public float LastVolumeTransfer = 0;
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
- files: ["turbine_room.ogg"]
|
||||
license: "CC-BY-3.0"
|
||||
copyright: "Created by Sea Fury, clipped and converted Mono and .ogg by Jhrushbe"
|
||||
source: https://freesound.org/people/Sea%20Fury/sounds/54638/
|
||||
|
||||
- files: ["electrical_hum.ogg"]
|
||||
license: "CC-BY-4.0"
|
||||
copyright: "Created by Zabuhailo, clipped and converted Mono and .ogg by Jhrushbe"
|
||||
source: https://freesound.org/people/Zabuhailo/sounds/167673/
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,34 @@
|
||||
- files: ["alarm_beep.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: "Created by JW_Audio, clipped and converted Mono and .ogg by Jhrushbe"
|
||||
source: https://freesound.org/people/JW_Audio/sounds/816661/
|
||||
|
||||
- files: ["alarm_buzzer.ogg"]
|
||||
license: "CC-BY-4.0"
|
||||
copyright: "Created by NoahBangs, clipped and converted Mono and .ogg by Jhrushbe"
|
||||
source: https://freesound.org/people/NoahBangs/sounds/587950/
|
||||
|
||||
- files: ["meltdown_siren.ogg"]
|
||||
license: "CC-BY-NC-SA-3.0"
|
||||
copyright: "Taken from Goonstation"
|
||||
source: https://github.com/goonstation/goonstation/blob/ff86b044/sound/machines/meltdown_siren.ogg
|
||||
|
||||
- files: ["reactor_alarm_1.ogg"]
|
||||
license: "CC-BY-4.0"
|
||||
copyright: "Created by Tecc_Source, clipped and converted Mono by Jhrushbe"
|
||||
source: https://freesound.org/people/Tecc_Source/sounds/746816/
|
||||
|
||||
- files: ["reactor_alarm_2.ogg"]
|
||||
license: "CC-BY-4.0"
|
||||
copyright: "Created by Tecc_Source, clipped and converted Mono by Jhrushbe"
|
||||
source: https://freesound.org/people/Tecc_Source/sounds/746818/
|
||||
|
||||
- files: ["reactor_alarm_3.ogg"]
|
||||
license: "CC-BY-4.0"
|
||||
copyright: "Created by Tecc_Source, converted Mono by Jhrushbe"
|
||||
source: https://freesound.org/people/Tecc_Source/sounds/746819/
|
||||
|
||||
- files: ["relay_click.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: "Created by bassmosphere, remixed and converted Mono and .ogg by Jhrushbe"
|
||||
source: https://freesound.org/people/bassmosphere/sounds/384698/
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
- files: ["orange.ogg"]
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Made by Conflee"
|
||||
source: "https://bsky.app/profile/conflee.bsky.social"
|
||||
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
nuclear-centrifuge-insert-item = {CAPITALIZE(THE($user))} inserted {THE($item)} into {THE($machine)}.
|
||||
|
||||
nuclear-centrifuge-wrong-item = You can't put {THE($item)} in here, it doesn't fit.
|
||||
nuclear-centrifuge-unfit-item = {THE($item)} isn't ready for reprocessing.
|
||||
@@ -0,0 +1,47 @@
|
||||
### Popups
|
||||
reactor-smoke-start = The {$owner} begins to smoke!
|
||||
reactor-smoke-stop = The {$owner} stops smoking.
|
||||
reactor-fire-start = The {$owner} begins to burn!
|
||||
reactor-fire-stop = The {$owner} stops burning.
|
||||
|
||||
reactor-unanchor-melted = You cannot unanchor the nuclear reactor, it's melted into the hull!
|
||||
reactor-unanchor-warning = You cannot unanchor the nuclear reactor while it's not empty or hotter than 80C!
|
||||
reactor-anchor-warning = Invalid anchor position.
|
||||
|
||||
### Messages
|
||||
reactor-smoke-start-message = ALERT: The {$owner} has reached a dangerous temperature: {$temperature}K. Intervene immediately to prevent meltdown.
|
||||
reactor-smoke-stop-message = The {$owner} has cooled below dangerous temperature. Have a nice day.
|
||||
reactor-fire-start-message = ALERT: The {$owner} has reached CRITICAL temperature: {$temperature}K. MELTDOWN IMMINENT.
|
||||
reactor-fire-stop-message = The {$owner} has cooled below critical temperature. Meltdown averted.
|
||||
|
||||
reactor-temperature-dangerous-message = The {$owner} is at dangerous temperature: {$temperature}K.
|
||||
reactor-temperature-critical-message = The {$owner} is at critical temperature: {$temperature}K.
|
||||
reactor-temperature-cooling-message = The {$owner} is cooling: {$temperature}K.
|
||||
|
||||
reactor-melting-announcement = A nuclear reactor aboard the station is beginning to meltdown. Evacuation of the surrounding area is advised.
|
||||
reactor-melting-announcement-sender = Nuclear Emergency
|
||||
|
||||
reactor-meltdown-announcement = A nuclear reactor aboard the station has catastrophically overloaded. Radioactive debris, nuclear fallout, and coolant fires are likely. Immediate evacuation of the surrounding area is strongly advised.
|
||||
reactor-meltdown-announcement-sender = Nuclear Meltdown
|
||||
|
||||
### UI
|
||||
comp-nuclear-reactor-ui-locked = Locked
|
||||
comp-nuclear-reactor-ui-insert-button = Insert
|
||||
comp-nuclear-reactor-ui-remove-button = Remove
|
||||
comp-nuclear-reactor-ui-eject-button = Eject
|
||||
|
||||
comp-nuclear-reactor-ui-view-change = Change View
|
||||
comp-nuclear-reactor-ui-view-temp = Temperature View
|
||||
comp-nuclear-reactor-ui-view-neutron = Neutron View
|
||||
comp-nuclear-reactor-ui-view-target = Target View
|
||||
comp-nuclear-reactor-ui-view-fuel = Fuel View
|
||||
|
||||
comp-nuclear-reactor-ui-status-panel = Reactor Status
|
||||
comp-nuclear-reactor-ui-reactor-temp = Temperature
|
||||
comp-nuclear-reactor-ui-reactor-rads = Radiation
|
||||
comp-nuclear-reactor-ui-reactor-therm = Thermal Power
|
||||
comp-nuclear-reactor-ui-reactor-control = Control Rods
|
||||
comp-nuclear-reactor-ui-therm-format = { POWERWATTS($power) }t
|
||||
|
||||
comp-nuclear-reactor-ui-footer-left = Danger: high radiation.
|
||||
comp-nuclear-reactor-ui-footer-right = 0.8 REV 3
|
||||
@@ -0,0 +1,16 @@
|
||||
reactor-part-nrad-0 = It's glowing slightly blue.
|
||||
reactor-part-nrad-1 = It's glowing somewhat blue.
|
||||
reactor-part-nrad-2 = It's glowing blue.
|
||||
reactor-part-nrad-3 = It's brightly glowing blue.
|
||||
reactor-part-nrad-4 = It's brilliantly glowing blue.
|
||||
reactor-part-nrad-5 = It's blindingly glowing blue.
|
||||
|
||||
reactor-part-rad-0 = It's slightly radioactive.
|
||||
reactor-part-rad-1 = It's somewhat radioactive.
|
||||
reactor-part-rad-2 = It's radioactive.
|
||||
reactor-part-rad-3 = It's very radioactive.
|
||||
reactor-part-rad-4 = It's extremely radioactive.
|
||||
reactor-part-rad-5 = It's impossibly radioactive.
|
||||
|
||||
reactor-part-hot = [color=yellow]It's hot to the touch.[/color]
|
||||
reactor-part-burning = [color=red]Heat distorts the air around it.[/color]
|
||||
@@ -0,0 +1,77 @@
|
||||
### Examine
|
||||
|
||||
gas-turbine-examine-stator-null = It seems to be missing a stator.
|
||||
gas-turbine-examine-stator = It has a stator.
|
||||
|
||||
gas-turbine-examine-blade-null = It seems to be missing a turbine blade.
|
||||
gas-turbine-examine-blade = It has a turbine blade.
|
||||
|
||||
turbine-spinning-0 = The blades are not spinning.
|
||||
turbine-spinning-1 = The blades are turning slowly.
|
||||
turbine-spinning-2 = The blades are spinning.
|
||||
turbine-spinning-3 = The blades are spinning quickly.
|
||||
turbine-spinning-4 = [color=red]The blades are spinning out of control![/color]
|
||||
|
||||
turbine-damaged-0 = It appears to be in good condition.[/color]
|
||||
turbine-damaged-1 = The turbine looks a bit scuffed.[/color]
|
||||
turbine-damaged-2 = [color=yellow]The turbine looks badly damaged.[/color]
|
||||
turbine-damaged-3 = [color=orange]It's critically damaged![/color]
|
||||
|
||||
turbine-ruined = [color=red]It's completely broken![/color]
|
||||
|
||||
### Popups
|
||||
|
||||
# Shown when an event occurs
|
||||
turbine-overheat = {$owner} triggers the emergency overheat dump valve!
|
||||
turbine-explode = The {$owner} tears itself apart!
|
||||
|
||||
# Shown when damage occurs
|
||||
turbine-spark = The {$owner} starts sparking!
|
||||
turbine-spark-stop = The {$owner} stops sparking.
|
||||
turbine-smoke = The {$owner} begins to smoke!
|
||||
turbine-smoke-stop = The {$owner} stops smoking.
|
||||
|
||||
# Shown during repairs
|
||||
gas-turbine-repair-fail-blade = You need to replace the turbine blade before this can be repaired.
|
||||
gas-turbine-repair-fail-stator = You need to replace the stator before this can be repaired.
|
||||
turbine-repair-ruined = You repair the {$target}'s casing with the {$tool}.
|
||||
turbine-repair = You repair some of the damage to the {$target} using the {$tool}.
|
||||
turbine-no-damage = There is no damage to repair on the {$target} using the {$tool}.
|
||||
turbine-show-damage = BladeHealth {$health}, BladeHealthMax {$healthMax}.
|
||||
|
||||
# Anchoring warnings
|
||||
turbine-unanchor-warning = You cannot unanchor the gas turbine while the turbine is spinning!
|
||||
turbine-anchor-warning = Invalid anchor position.
|
||||
|
||||
gas-turbine-eject-fail-speed = You cannot remove turbine parts while the turbine is spinning!
|
||||
gas-turbine-insert-fail-speed = You cannot insert turbine parts while the turbine is spinning!
|
||||
|
||||
### UI
|
||||
|
||||
# Shown when using the UI
|
||||
comp-turbine-ui-tab-main = Controls
|
||||
comp-turbine-ui-tab-parts = Parts
|
||||
|
||||
comp-turbine-ui-rpm = RPM
|
||||
|
||||
comp-turbine-ui-overspeed = OVERSPEED
|
||||
comp-turbine-ui-overtemp = OVERTEMP
|
||||
comp-turbine-ui-stalling = STALLING
|
||||
comp-turbine-ui-undertemp = UNDERTEMP
|
||||
|
||||
comp-turbine-ui-flow-rate = Flow Rate
|
||||
comp-turbine-ui-stator-load = Stator Load
|
||||
|
||||
comp-turbine-ui-blade = Turbine Blade
|
||||
comp-turbine-ui-blade-integrity = Integrity
|
||||
comp-turbine-ui-blade-stress = Stress
|
||||
|
||||
comp-turbine-ui-stator = Turbine Stator
|
||||
comp-turbine-ui-stator-potential = Potential
|
||||
comp-turbine-ui-stator-supply = Supply
|
||||
|
||||
comp-turbine-ui-power = { POWERWATTS($power) }
|
||||
|
||||
comp-turbine-ui-locked-message = Controls locked.
|
||||
comp-turbine-ui-footer-left = Danger: fast-moving machinery.
|
||||
comp-turbine-ui-footer-right = 2.0 REV 1
|
||||
@@ -0,0 +1,6 @@
|
||||
ghost-role-information-plutonium-rod-name = Plutonium Fuel Rod
|
||||
ghost-role-information-plutonium-rod-description = Does not want to become power.
|
||||
ghost-role-information-plutonium-rod-rules = You are a [color={role-type-free-agent-color}][bold]{ghost-role-information-plutonium-rod-name}[/bold][/color]. Your one goal is not to be put into the nuclear reactor or centrifuge, because if you are, you [color=red]die[/color].
|
||||
You don't remember any of your previous life, and you don't remember anything you learned as a ghost.
|
||||
You [color=red]don't[/color] remember knowledge about the game in general, such as how to cook, how to use objects, etc.
|
||||
You are absolutely [color=red]NOT[/color] allowed to remember, say, the name, appearance, etc. of your previous character.
|
||||
@@ -0,0 +1,2 @@
|
||||
guide-entry-nuclear-reactor = Nuclear Reactor
|
||||
guide-entry-nuclear-materials = Material Effects
|
||||
@@ -0,0 +1,17 @@
|
||||
signal-port-name-nuclear-reactor-data-receiver = Reactor Monitor
|
||||
signal-port-description-nuclear-reactor-data-receiver = Receiving info about a nuclear reactor.
|
||||
|
||||
signal-port-name-nuclear-reactor-receiver-insert = Control Rods In
|
||||
signal-port-description-nuclear-reactor-receiver-insert = Increases the insertion level of the control rods.
|
||||
|
||||
signal-port-name-nuclear-reactor-receiver-retract = Control Rods Out
|
||||
signal-port-description-nuclear-reactor-receiver-retract = Decreases the insertion level of the control rods.
|
||||
|
||||
signal-port-name-gas-turbine-data-receiver = Turbine Monitor
|
||||
signal-port-description-gas-turbine-data-receiver = Receiving info about a gas turbine.
|
||||
|
||||
signal-port-name-gas-turbine-receiver-increase = Increase Load
|
||||
signal-port-description-gas-turbine-receiver-increase = Increases the stator load of the turbine.
|
||||
|
||||
signal-port-name-gas-turbine-receiver-decrease = Decrease Load
|
||||
signal-port-description-gas-turbine-receiver-decrease = Decreases the stator load of the turbine.
|
||||
@@ -0,0 +1,11 @@
|
||||
signal-port-name-nuclear-reactor-data-sender = Nuclear Reactor
|
||||
signal-port-description-nuclear-reactor-data-sender = Sending info about a nuclear reactor to a monitor.
|
||||
|
||||
signal-port-name-gas-turbine-data-sender = Gas Turbine
|
||||
signal-port-description-gas-turbine-data-sender = Sending info about a gas turbine to a monitor.
|
||||
|
||||
signal-port-name-gas-turbine-speed-high = High Speed
|
||||
signal-port-description-gas-turbine-speed-high = Speed is higher than optimal.
|
||||
|
||||
signal-port-name-gas-turbine-speed-low = Low Speed
|
||||
signal-port-description-gas-turbine-speed-low = Speed is lower than optimal.
|
||||
@@ -0,0 +1,3 @@
|
||||
materials-cerenkite = cerenkite
|
||||
materials-plutonium = plutonium
|
||||
materials-bohrum = bohrum
|
||||
@@ -0,0 +1,3 @@
|
||||
# Thief Collection
|
||||
|
||||
steal-target-groups-reactorfuelrod = reactor fuel rod
|
||||
@@ -0,0 +1,2 @@
|
||||
research-technology-nuclear-power = Nuclear Power
|
||||
research-technology-nuclear-recycling = Nuclear Waste Recycling
|
||||
@@ -0,0 +1 @@
|
||||
stack-plutonium = plutonium
|
||||
@@ -0,0 +1,3 @@
|
||||
alert-level-orange = Orange
|
||||
alert-level-orange-announcement = There is a critical station-wide structural or atmospheric threat and recovery is unlikely. Engineering staff are advised to minimize hazards and secure the Evacuation Dock. Crewmembers are advised to stay away from hazardous areas, and prepare for Evacuation. MAYDAY signals have been activated
|
||||
alert-level-orange-instructions = Avoid hazards and prepare for Evacuation.
|
||||
@@ -43,6 +43,17 @@
|
||||
emergencyLightColor: Red
|
||||
forceEnableEmergencyLights: true
|
||||
shuttleTime: 600 #No reduction in time as we don't have swiping for red alert like in /tg/. Shuttle times are intended to create friction, so having a way to brainlessly bypass that would be dumb.
|
||||
# Begin Starlight Additions
|
||||
orange:
|
||||
announcement: alert-level-orange-announcement
|
||||
selectable: true
|
||||
sound:
|
||||
path: /Audio/_Starlight/misc/orange.ogg
|
||||
color: "#ff8119"
|
||||
emergencyLightColor: "#ff8119"
|
||||
forceEnableEmergencyLights: true
|
||||
shuttleTime: 480
|
||||
# End Starlight Additions
|
||||
gamma:
|
||||
announcement: alert-level-gamma-announcement
|
||||
selectable: false
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
- id: DrinkVodkaBottleFull
|
||||
- id: DrinkShotGlass
|
||||
amount: 2
|
||||
- id: RadiationBlockingProjector # Far Horizons
|
||||
|
||||
- type: entity
|
||||
parent: CratePlastic
|
||||
|
||||
@@ -210,6 +210,7 @@
|
||||
- id: LunchboxEngineeringFilledRandom # DeltaV - Lunchboxes!
|
||||
prob: 0.3
|
||||
- id: HolotapeProjector # DeltaV - engineering tape
|
||||
- id: PillCanisterPotassiumIodide # Far Horizons / Nuclear Reactor Port
|
||||
|
||||
- type: entityTable
|
||||
id: FillEngineerHardsuit
|
||||
@@ -237,9 +238,11 @@
|
||||
- id: ClothingOuterSuitRad
|
||||
amount: 2
|
||||
- id: GeigerCounter
|
||||
amount: 2
|
||||
- id: PillCanisterPotassiumIodide
|
||||
prob: 0.75
|
||||
amount: !type:ConstantNumberSelector
|
||||
value: 2
|
||||
- id: PillCanisterPotassiumIodide # Far Horizons / Nuclear Reactor Port Start
|
||||
amount: !type:ConstantNumberSelector
|
||||
value: 2 # Far Horizons / Nuclear Reactor Port End
|
||||
|
||||
- type: entity
|
||||
parent: LockerEvacRepair
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
boardName: wires-board-name-autolathe
|
||||
layoutId: Fabicator
|
||||
alwaysRandomize: true
|
||||
- type: StationAiWhitelist
|
||||
- type: StationAiWhitelist
|
||||
- type: MaterialStorageMagnetPickup
|
||||
magnetEnabled: True
|
||||
range: 0.30
|
||||
@@ -297,6 +297,7 @@
|
||||
- MechBoards
|
||||
- ShuttleBoards
|
||||
- EngineeringBoardsGoob #Goob Factorio port
|
||||
- ReactorCircuitboards # FH edit
|
||||
- type: EmagLatheRecipes
|
||||
emagDynamicPacks:
|
||||
- SecurityBoards
|
||||
|
||||
@@ -320,6 +320,7 @@
|
||||
- PortableGenerator
|
||||
- AME
|
||||
- SingularityTeslaEngine
|
||||
- NuclearReactor # FH edit
|
||||
- TEG
|
||||
- RTG
|
||||
- SolarPanels
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
MailStealCollectionObjective: 1 #cargo
|
||||
IDCardsStealCollectionObjective: 1
|
||||
LAMPStealCollectionObjective: 2 #only for moth
|
||||
ReactorFuelRodStealCollectionObjective: 1 #Far Horizons/Nuclear Reactor Port
|
||||
|
||||
- type: weightedRandom
|
||||
id: ThiefObjectiveGroupItem
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
icon: { sprite: Objects/Materials/Sheets/glass.rsi, state: glass }
|
||||
color: "#a8ccd7"
|
||||
price: 0.15 # $15 for one unit
|
||||
properties: # FH edit
|
||||
electrical: 3
|
||||
thermal: 3
|
||||
hard: 3
|
||||
density: 2
|
||||
chemical: 5
|
||||
|
||||
- type: material
|
||||
id: ReinforcedGlass
|
||||
@@ -13,6 +19,13 @@
|
||||
icon: { sprite: Objects/Materials/Sheets/glass.rsi, state: rglass }
|
||||
color: "#549bb0"
|
||||
price: 0.225 # 1-0.5 mix of glass and metal.
|
||||
# Interpolated properties
|
||||
properties: # FH edit
|
||||
electrical: 3.66
|
||||
thermal: 4
|
||||
hard: 3
|
||||
density: 2.66
|
||||
chemical: 5.33
|
||||
|
||||
- type: material
|
||||
id: PlasmaGlass
|
||||
@@ -21,6 +34,12 @@
|
||||
icon: { sprite: Objects/Materials/Sheets/glass.rsi, state: pglass }
|
||||
color: "#b35989"
|
||||
price: 0.50 # 1-1 mix of plasma and glass.
|
||||
properties: # FH edit
|
||||
electrical: 3
|
||||
thermal: 3
|
||||
hard: 7
|
||||
density: 3
|
||||
chemical: 5
|
||||
|
||||
- type: material
|
||||
id: ReinforcedPlasmaGlass
|
||||
@@ -29,6 +48,13 @@
|
||||
icon: { sprite: Objects/Materials/Sheets/glass.rsi, state: rpglass }
|
||||
color: "#8c4069"
|
||||
price: 0.575 # 1-1-0.5 mix of plasma, glass, and metal.
|
||||
# Interpolated properties
|
||||
properties: # FH edit
|
||||
electrical: 3.66
|
||||
thermal: 4
|
||||
hard: 5.66
|
||||
density: 3.33
|
||||
chemical: 5.33
|
||||
|
||||
- type: material
|
||||
id: BrassGlass
|
||||
@@ -37,6 +63,13 @@
|
||||
icon: { sprite: Objects/Materials/Sheets/glass.rsi, state: cglass }
|
||||
color: "#9b6f07"
|
||||
price: 0.225 # average of glass and brass.
|
||||
# Interpolated properties
|
||||
properties: # FH edit
|
||||
electrical: 4
|
||||
thermal: 4.5
|
||||
hard: 3
|
||||
density: 3
|
||||
chemical: 5.5
|
||||
|
||||
- type: material
|
||||
id: UraniumGlass
|
||||
@@ -45,6 +78,15 @@
|
||||
icon: { sprite: Objects/Materials/Sheets/glass.rsi, state: uglass }
|
||||
color: "#3cab38"
|
||||
price: 1.0 # 1-1 mix of uranium and glass.
|
||||
# Interpolated properties
|
||||
properties: # FH edit
|
||||
electrical: 3.5
|
||||
thermal: 3
|
||||
hard: 4
|
||||
density: 4.5
|
||||
chemical: 5.5
|
||||
radioactive: 2 # Making something out of uranium is radioactive... imagine that
|
||||
n_radioactive: 1.5
|
||||
|
||||
- type: material
|
||||
id: ReinforcedUraniumGlass
|
||||
@@ -53,3 +95,12 @@
|
||||
icon: { sprite: Objects/Materials/Sheets/glass.rsi, state: ruglass }
|
||||
color: "#2d872a"
|
||||
price: 1.075 # 2-2-1 mix of uranium, glass, and metal.
|
||||
# Interpolated properties
|
||||
properties: # FH edit
|
||||
electrical: 3.8
|
||||
thermal: 3.6
|
||||
hard: 3.8
|
||||
density: 3.3
|
||||
chemical: 5.6
|
||||
radioactive: 1.6
|
||||
n_radioactive: 1.2
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
name: materials-steel
|
||||
icon: { sprite: Objects/Materials/Sheets/metal.rsi, state: steel }
|
||||
price: 0.15 # $15 for 1 unit
|
||||
properties: # FH edit
|
||||
electrical: 5
|
||||
thermal: 6
|
||||
hard: 3
|
||||
density: 4
|
||||
chemical: 6
|
||||
|
||||
- type: material
|
||||
id: Gold
|
||||
@@ -13,6 +19,13 @@
|
||||
icon: { sprite: Objects/Materials/ingots.rsi, state: gold }
|
||||
color: "#FFD700"
|
||||
price: 0.75 # $75 for 1 unit
|
||||
properties: # FH edit
|
||||
electrical: 7
|
||||
thermal: 7
|
||||
hard: 2
|
||||
density: 6
|
||||
reflective: 6
|
||||
chemical: 6
|
||||
|
||||
- type: material
|
||||
id: Silver
|
||||
@@ -22,6 +35,13 @@
|
||||
icon: { sprite: Objects/Materials/ingots.rsi, state: silver }
|
||||
color: "#C0C0C0"
|
||||
price: 0.60 # $60 for 1 unit
|
||||
properties: # FH edit
|
||||
electrical: 6
|
||||
thermal: 6
|
||||
hard: 2
|
||||
density: 4
|
||||
reflective: 6
|
||||
chemical: 6
|
||||
|
||||
- type: material
|
||||
id: Brass
|
||||
@@ -30,6 +50,12 @@
|
||||
icon: { sprite: _DV/Objects/Materials/Sheets/metal.rsi, state: brass } # DeltaV - new brass textures
|
||||
color: "#b18b25"
|
||||
price: 0.30 # $30 for 1 unit
|
||||
properties: # FH edit
|
||||
electrical: 6
|
||||
thermal: 7
|
||||
hard: 2
|
||||
density: 5
|
||||
chemical: 7
|
||||
|
||||
- type: material
|
||||
id: Plasteel
|
||||
@@ -38,3 +64,9 @@
|
||||
icon: { sprite: Objects/Materials/Sheets/metal.rsi, state: plasteel }
|
||||
color: "#696969" #Okay, this is epic
|
||||
price: 0.5 # 1-1 mix of plasma and steel.
|
||||
properties: # FH edit
|
||||
electrical: 5
|
||||
thermal: 6
|
||||
hard: 3
|
||||
density: 7
|
||||
chemical: 6
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
- type: cargoProduct
|
||||
id: NuclearReactorFlatpackPurchase
|
||||
icon:
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/cargo_icons.rsi
|
||||
state: reactor
|
||||
product: NuclearReactorFlatpack
|
||||
cost: 15000
|
||||
category: cargoproduct-category-name-engineering
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: GasTurbineFlatpackPurchase
|
||||
icon:
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/cargo_icons.rsi
|
||||
state: turbine
|
||||
product: GasTurbineFlatpack
|
||||
cost: 10000
|
||||
category: cargoproduct-category-name-engineering
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: CerenkiteFuelRodPurchase
|
||||
icon:
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_parts.rsi
|
||||
state: default_rod
|
||||
product: CrateCerenkiteFuelRod
|
||||
cost: 4000
|
||||
category: cargoproduct-category-name-engineering
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: BohrumControlRodPurchase
|
||||
icon:
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_parts.rsi
|
||||
state: default_rod
|
||||
product: CrateBohrumControlRod
|
||||
cost: 2000
|
||||
category: cargoproduct-category-name-engineering
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: SteelGasChannelPurchase
|
||||
icon:
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_parts.rsi
|
||||
state: default_rod
|
||||
product: CrateSteelGasChannel
|
||||
cost: 1000
|
||||
category: cargoproduct-category-name-engineering
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: SteelHeatExhangerPurchase
|
||||
icon:
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_parts.rsi
|
||||
state: default_rod
|
||||
product: CrateSteelHeatExhanger
|
||||
cost: 1000
|
||||
category: cargoproduct-category-name-engineering
|
||||
group: market
|
||||
@@ -0,0 +1,43 @@
|
||||
- type: entity
|
||||
id: CrateCerenkiteFuelRod
|
||||
parent: CrateEngineeringSecure
|
||||
name: fuel rod crate
|
||||
description: 3 cerenkite fuel rods, for fuelling a nuclear reactor.
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: CerenkiteReactorFuelRod
|
||||
amount: 3
|
||||
|
||||
- type: entity
|
||||
id: CrateBohrumControlRod
|
||||
parent: CrateEngineeringSecure
|
||||
name: control rod crate
|
||||
description: 2 bohrum control rods for a nuclear reactor.
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: BohrumReactorControlRod
|
||||
amount: 2
|
||||
|
||||
- type: entity
|
||||
id: CrateSteelGasChannel
|
||||
parent: CrateEngineeringSecure
|
||||
name: gas channel rod crate
|
||||
description: 4 steel gas channel rods for a nuclear reactor.
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: SteelReactorGasChannel
|
||||
amount: 4
|
||||
|
||||
- type: entity
|
||||
id: CrateSteelHeatExhanger
|
||||
parent: CrateEngineeringSecure
|
||||
name: heat exchanger rod crate
|
||||
description: 4 steel heat exchanger rods for a nuclear reactor.
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: SteelReactorHeatExchanger
|
||||
amount: 4
|
||||
@@ -0,0 +1,15 @@
|
||||
- type: damageModifierSet
|
||||
id: StructuralReactorCasing # StructuralMetallicStrong(er), it's going to take more than a mere baseball bat to do any real damage
|
||||
coefficients:
|
||||
Blunt: 0.1 # you
|
||||
Slash: 0.1 # aint
|
||||
Piercing: 0.1 # gonna
|
||||
Shock: 0.2 # do
|
||||
Heat: 0.1 # shit
|
||||
Structural: 0.25
|
||||
flatReductions:
|
||||
Blunt: 10
|
||||
Slash: 10
|
||||
Piercing: 10
|
||||
Heat: 10
|
||||
Structural: 10
|
||||
@@ -0,0 +1,31 @@
|
||||
# Nuclear Reactor
|
||||
- type: sinkPort
|
||||
id: InsertControlRods
|
||||
name: signal-port-name-nuclear-reactor-receiver-insert
|
||||
description: signal-port-description-nuclear-reactor-receiver-insert
|
||||
|
||||
- type: sinkPort
|
||||
id: RetractControlRods
|
||||
name: signal-port-name-nuclear-reactor-receiver-retract
|
||||
description: signal-port-description-nuclear-reactor-receiver-retract
|
||||
|
||||
- type: sinkPort
|
||||
id: NuclearReactorDataReceiver
|
||||
name: signal-port-name-nuclear-reactor-data-receiver
|
||||
description: signal-port-description-nuclear-reactor-data-receiver
|
||||
|
||||
# Gas Turbine
|
||||
- type: sinkPort
|
||||
id: IncreaseStatorLoad
|
||||
name: signal-port-name-gas-turbine-receiver-increase
|
||||
description: signal-port-description-gas-turbine-receiver-increase
|
||||
|
||||
- type: sinkPort
|
||||
id: DecreaseStatorLoad
|
||||
name: signal-port-name-gas-turbine-receiver-decrease
|
||||
description: signal-port-description-gas-turbine-receiver-decrease
|
||||
|
||||
- type: sinkPort
|
||||
id: GasTurbineDataReceiver
|
||||
name: signal-port-name-gas-turbine-data-receiver
|
||||
description: signal-port-description-gas-turbine-data-receiver
|
||||
@@ -0,0 +1,23 @@
|
||||
# Nuclear Reactor
|
||||
- type: sourcePort
|
||||
id: NuclearReactorDataSender
|
||||
name: signal-port-name-nuclear-reactor-data-sender
|
||||
description: signal-port-description-nuclear-reactor-data-sender
|
||||
defaultLinks: [ NuclearReactorDataReceiver ]
|
||||
|
||||
# Gas Turbine
|
||||
- type: sourcePort
|
||||
id: GasTurbineDataSender
|
||||
name: signal-port-name-gas-turbine-data-sender
|
||||
description: signal-port-description-gas-turbine-data-sender
|
||||
defaultLinks: [ GasTurbineDataReceiver ]
|
||||
|
||||
- type: sourcePort
|
||||
id: TurbineSpeedHigh
|
||||
name: signal-port-name-gas-turbine-speed-high
|
||||
description: signal-port-description-gas-turbine-speed-high
|
||||
|
||||
- type: sourcePort
|
||||
id: TurbineSpeedLow
|
||||
name: signal-port-name-gas-turbine-speed-low
|
||||
description: signal-port-description-gas-turbine-speed-low
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
- type: entity
|
||||
id: NuclearFabricatorMachineCircuitboard
|
||||
parent: BaseMachineCircuitboard
|
||||
name: nuclear fabricator machine board
|
||||
description: A machine printed circuit board for a nuclear fabricator.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: engineering
|
||||
- type: MachineBoard
|
||||
prototype: NuclearFabricator
|
||||
stackRequirements:
|
||||
Manipulator: 5
|
||||
Glass: 3
|
||||
|
||||
- type: entity
|
||||
id: NuclearCentrifugeMachineCircuitboard
|
||||
parent: BaseMachineCircuitboard
|
||||
name: nuclear centrifuge machine board
|
||||
description: A machine printed circuit board for a nuclear centrifuge.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: engineering
|
||||
- type: MachineBoard
|
||||
prototype: NuclearCentrifuge
|
||||
stackRequirements:
|
||||
Manipulator: 5
|
||||
Plasteel: 5
|
||||
@@ -0,0 +1,21 @@
|
||||
- type: entity
|
||||
parent: BaseComputerCircuitboard
|
||||
id: NuclearReactorMonitorComputerCircuitboard
|
||||
name: nuclear reactor monitor computer board
|
||||
description: A computer printed circuit board for a nuclear reactor monitor.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: cpu_engineering
|
||||
- type: ComputerBoard
|
||||
prototype: NuclearReactorMonitor
|
||||
|
||||
- type: entity
|
||||
parent: BaseComputerCircuitboard
|
||||
id: GasTurbineMonitorComputerCircuitboard
|
||||
name: gas turbine monitor computer board
|
||||
description: A computer printed circuit board for a gas turbine monitor.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: cpu_engineering
|
||||
- type: ComputerBoard
|
||||
prototype: GasTurbineMonitor
|
||||
@@ -0,0 +1,25 @@
|
||||
- type: entity
|
||||
parent: CrateEngineering
|
||||
id: NuclearReactorFlatpack
|
||||
name: nuclear reactor flatpack
|
||||
description: A flatpack used for constructing a nuclear reactor. Parts sold separately.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/flatpack.rsi
|
||||
layers:
|
||||
- state: large
|
||||
- type: Flatpack
|
||||
entity: NuclearReactorEmpty
|
||||
|
||||
- type: entity
|
||||
parent: CrateEngineering
|
||||
id: GasTurbineFlatpack
|
||||
name: gas turbine flatpack
|
||||
description: A flatpack used for constructing a gas turbine.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Devices/flatpack.rsi
|
||||
layers:
|
||||
- state: large
|
||||
- type: Flatpack
|
||||
entity: Turbine
|
||||
@@ -0,0 +1,22 @@
|
||||
- type: entity
|
||||
parent: Holoprojector
|
||||
id: RadiationBlockingProjector
|
||||
name: radiation barrier projector
|
||||
description: Stop the deadly radiation from a delamination or meltdown, at least for a little while.
|
||||
components:
|
||||
- type: HolosignProjector
|
||||
signProto: HolosignRadiationBlocking
|
||||
chargeUse: 60
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Objects/Devices/Holoprojectors/radiation.rsi
|
||||
state: icon
|
||||
- type: Tag
|
||||
tags:
|
||||
- HolofanProjector
|
||||
# - type: StaticPrice
|
||||
# price: 50
|
||||
# - type: GuideHelp
|
||||
# guides:
|
||||
# - AtmosTools
|
||||
# - Fires
|
||||
# - Spacing
|
||||
@@ -0,0 +1,52 @@
|
||||
- type: entity
|
||||
parent: IngotBase
|
||||
id: IngotPlutonium
|
||||
name: plutonium bar
|
||||
suffix: Full
|
||||
components:
|
||||
- type: Material
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Plutonium: 100
|
||||
- type: Stack
|
||||
stackType: Plutonium
|
||||
baseLayer: base
|
||||
layerStates:
|
||||
- iron # Why iron? Because I haven't gotten a spriter to make better
|
||||
- iron_2
|
||||
- iron_3
|
||||
- type: Sprite
|
||||
state: iron_3
|
||||
layers:
|
||||
- state: iron_3
|
||||
map: ["base"]
|
||||
- type: Item
|
||||
heldPrefix: plutonium
|
||||
- type: Appearance
|
||||
# - type: Extractable
|
||||
# grindableSolutionName: gold
|
||||
# - type: SolutionContainerManager
|
||||
# solutions:
|
||||
# gold:
|
||||
# reagents:
|
||||
# - ReagentId: Silver
|
||||
# Quantity: 10
|
||||
- type: RadiationSource
|
||||
intensity: 0.08
|
||||
slope: 3
|
||||
- type: PointLight
|
||||
radius: 1.2
|
||||
energy: 0.8
|
||||
castShadows: false
|
||||
color: "#22bbff"
|
||||
|
||||
- type: entity
|
||||
parent: IngotPlutonium
|
||||
id: IngotPlutonium1
|
||||
name: plutonium bar
|
||||
suffix: Single
|
||||
components:
|
||||
- type: Sprite
|
||||
state: iron
|
||||
- type: Stack
|
||||
count: 1
|
||||
@@ -0,0 +1,20 @@
|
||||
- type: entity
|
||||
id: HolosignRadiationBlocking
|
||||
parent: HolosignWetFloor
|
||||
name: holographic radiation barrier
|
||||
description: A barrier of hard light that blocks light and radiation, but nothing else.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Holo/radiation.rsi
|
||||
state: icon
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.5,-0.5,0.5,0.5"
|
||||
- type: TimedDespawn
|
||||
lifetime: 180
|
||||
- type: Occluder
|
||||
- type: RadiationBlocker
|
||||
resistance: 50
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
- type: entity
|
||||
parent: BaseComputerAiAccess
|
||||
id: NuclearReactorMonitor
|
||||
name: nuclear reactor monitor
|
||||
description: A device that monitors the state of a connected nuclear reactor.
|
||||
components:
|
||||
- type: ApcPowerReceiver
|
||||
powerLoad: 500
|
||||
- type: PointLight
|
||||
radius: 1.5
|
||||
energy: 1.6
|
||||
color: "#c9c042"
|
||||
- type: Sprite
|
||||
sprite: Structures/Machines/computers.rsi
|
||||
layers:
|
||||
- map: ["computerLayerBody"]
|
||||
state: computer
|
||||
- map: ["computerLayerScreen"]
|
||||
state: power_monitor
|
||||
- type: NuclearReactorMonitor
|
||||
- type: ActivatableUI
|
||||
key: enum.NuclearReactorUiKey.Key
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.NuclearReactorUiKey.Key:
|
||||
type: NuclearReactorBoundUserInterface
|
||||
- type: AccessReader # You got a permit for that meltdown?
|
||||
access: [["Engineering"]]
|
||||
- type: Lock
|
||||
unlockOnClick: false
|
||||
- type: DeviceList
|
||||
- type: DeviceNetwork
|
||||
deviceNetId: Wireless
|
||||
- type: DeviceLinkSink
|
||||
ports:
|
||||
- NuclearReactorDataReceiver
|
||||
- type: Computer
|
||||
board: NuclearReactorMonitorComputerCircuitboard
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
board: !type:Container
|
||||
machine_board: !type:Container
|
||||
machine_parts: !type:Container
|
||||
|
||||
- type: entity
|
||||
parent: BaseComputerAiAccess
|
||||
id: GasTurbineMonitor
|
||||
name: gas turbine monitor
|
||||
description: A device that monitors the state of a connected gas turbine.
|
||||
components:
|
||||
- type: ApcPowerReceiver
|
||||
powerLoad: 500
|
||||
- type: PointLight
|
||||
radius: 1.5
|
||||
energy: 1.6
|
||||
color: "#c9c042"
|
||||
- type: Sprite
|
||||
sprite: Structures/Machines/computers.rsi
|
||||
layers:
|
||||
- map: ["computerLayerBody"]
|
||||
state: computer
|
||||
- map: ["computerLayerScreen"]
|
||||
state: turbinecomp
|
||||
- type: GasTurbineMonitor
|
||||
- type: ActivatableUI
|
||||
key: enum.TurbineUiKey.Key
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.TurbineUiKey.Key:
|
||||
type: TurbineBoundUserInterface
|
||||
- type: AccessReader # Keeps some random tider from blowing up the turbine
|
||||
access: [["Engineering"]]
|
||||
- type: Lock
|
||||
unlockOnClick: false
|
||||
- type: DeviceList
|
||||
- type: DeviceNetwork
|
||||
deviceNetId: Wireless
|
||||
- type: DeviceLinkSink
|
||||
ports:
|
||||
- GasTurbineDataReceiver
|
||||
- type: Computer
|
||||
board: GasTurbineMonitorComputerCircuitboard
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
board: !type:Container
|
||||
machine_board: !type:Container
|
||||
machine_parts: !type:Container
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
- type: navMapBlip
|
||||
id: NuclearReactor
|
||||
scale: 2.75
|
||||
color: LightGray
|
||||
texturePaths:
|
||||
- "/Textures/Interface/NavMap/beveled_hexagon.png"
|
||||
|
||||
- type: navMapBlip
|
||||
id: GasTurbine
|
||||
scale: 1.75
|
||||
color: LightGray
|
||||
texturePaths:
|
||||
- "/Textures/Interface/NavMap/beveled_hexagon.png"
|
||||
@@ -0,0 +1,33 @@
|
||||
- type: entity
|
||||
id: NuclearCentrifuge
|
||||
parent: [ BaseMachinePowered, ConstructibleMachine ]
|
||||
name: nuclear centrifuge
|
||||
description: A large machine that can be used to separate radioactive isotopes from spent fuel.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Machines/nuclear_centrifuge.rsi
|
||||
snapCardinals: true
|
||||
layers:
|
||||
- state: centrifuge
|
||||
map: ["enum.NuclearCentrifugeVisualLayers.Processing"]
|
||||
# - state: panel
|
||||
# map: ["enum.WiresVisualLayers.MaintenancePanel"]
|
||||
# visible: false
|
||||
- state: centrifuge_onlight
|
||||
map: ["enum.PowerDeviceVisualLayers.Powered"]
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.NuclearCentrifugeVisuals.Processing:
|
||||
enum.NuclearCentrifugeVisualLayers.Processing:
|
||||
True: { state: centrifuge_process }
|
||||
False: { state: centrifuge }
|
||||
enum.PowerDeviceVisuals.Powered:
|
||||
enum.PowerDeviceVisualLayers.Powered:
|
||||
True: { visible: True }
|
||||
False: { visible: False }
|
||||
- type: Appearance
|
||||
- type: Machine
|
||||
board: NuclearCentrifugeMachineCircuitboard
|
||||
- type: WiresPanel
|
||||
- type: WiresVisuals
|
||||
- type: NuclearCentrifuge
|
||||
@@ -0,0 +1,55 @@
|
||||
- type: entity
|
||||
id: NuclearFabricator
|
||||
parent: BaseLatheLube
|
||||
name: nuclear fabricator
|
||||
description: It makes nuclear parts.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Structures/Machines/protolathe.rsi
|
||||
snapCardinals: true
|
||||
layers:
|
||||
- state: icon
|
||||
map: ["enum.LatheVisualLayers.IsRunning"]
|
||||
- state: unlit
|
||||
shader: unshaded
|
||||
map: ["enum.PowerDeviceVisualLayers.Powered"]
|
||||
- state: inserting
|
||||
map: ["enum.MaterialStorageVisualLayers.Inserting"]
|
||||
- state: panel
|
||||
map: ["enum.WiresVisualLayers.MaintenancePanel"]
|
||||
- type: Machine
|
||||
board: NuclearFabricatorMachineCircuitboard
|
||||
- type: MaterialStorage
|
||||
whitelist:
|
||||
tags:
|
||||
- Sheet
|
||||
- RawMaterial
|
||||
- Ingot
|
||||
- type: OreSiloClient
|
||||
- type: Lathe
|
||||
idleState: icon
|
||||
runningState: building
|
||||
unlitIdleState: unlit
|
||||
unlitRunningState: unlit-building
|
||||
staticPacks:
|
||||
- ReactorPartsBasic
|
||||
dynamicPacks:
|
||||
- ReactorFuelRods
|
||||
- ReactorControlRods
|
||||
- ReactorGasChannels
|
||||
- ReactorHeatExchangers
|
||||
- GasTurbineBlades
|
||||
- GasTurbineStators
|
||||
# - type: EmagLatheRecipes
|
||||
# emagStaticPacks:
|
||||
# - StarlightSecurityEmagWeaponsStatic
|
||||
# - StarlightSecurityAmmoStatic
|
||||
# - StarlightSecurityAmmoEmagStatic
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
machine_board: !type:Container
|
||||
machine_parts: !type:Container
|
||||
blueprint: !type:Container
|
||||
- type: EmptyOnMachineDeconstruct
|
||||
containers:
|
||||
- blueprint
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
- type: entity
|
||||
id: BaseGasTurbinePart
|
||||
parent: BaseItem
|
||||
abstract: true
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/turbine_parts.rsi
|
||||
state: turbine_blade
|
||||
- type: Item
|
||||
size: Huge
|
||||
- type: MultiHandedItem
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- NuclearReactor
|
||||
- Power
|
||||
|
||||
# Blades
|
||||
- type: entity
|
||||
id: BaseGasTurbineBlade
|
||||
parent: BaseGasTurbinePart
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: gas turbine blade
|
||||
description: A replacement blade for the gas turbine.
|
||||
components:
|
||||
- type: GasTurbineBlade
|
||||
- type: Tag
|
||||
tags:
|
||||
- GasTurbineBlade
|
||||
|
||||
- type: entity
|
||||
id: SteelGasTurbineBlade
|
||||
parent: BaseGasTurbineBlade
|
||||
name: steel gas turbine blade
|
||||
components:
|
||||
- type: GasTurbineBlade
|
||||
material: Steel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 1000
|
||||
|
||||
- type: entity
|
||||
id: BrassGasTurbineBlade
|
||||
parent: BaseGasTurbineBlade
|
||||
name: brass gas turbine blade
|
||||
components:
|
||||
- type: GasTurbineBlade
|
||||
material: Brass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Brass: 1000
|
||||
|
||||
- type: entity
|
||||
id: DiamondGasTurbineBlade
|
||||
parent: BaseGasTurbineBlade
|
||||
name: diamond gas turbine blade
|
||||
components:
|
||||
- type: GasTurbineBlade
|
||||
material: Diamond
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Diamond: 1000
|
||||
|
||||
- type: entity
|
||||
id: GoldGasTurbineBlade
|
||||
parent: BaseGasTurbineBlade
|
||||
name: gold gas turbine blade
|
||||
components:
|
||||
- type: GasTurbineBlade
|
||||
material: Gold
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Gold: 1000
|
||||
|
||||
- type: entity
|
||||
id: PlasteelGasTurbineBlade
|
||||
parent: BaseGasTurbineBlade
|
||||
name: plasteel gas turbine blade
|
||||
components:
|
||||
- type: GasTurbineBlade
|
||||
material: Plasteel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Plasteel: 1000
|
||||
|
||||
# Stators
|
||||
- type: entity
|
||||
id: BaseGasTurbineStator
|
||||
parent: BaseGasTurbinePart
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: gas turbine stator
|
||||
description: A replacement stator for the gas turbine.
|
||||
components:
|
||||
- type: Sprite
|
||||
state: turbine_stator
|
||||
- type: GasTurbineStator
|
||||
- type: Tag
|
||||
tags:
|
||||
- GasTurbineStator
|
||||
|
||||
- type: entity
|
||||
id: SteelGasTurbineStator
|
||||
parent: BaseGasTurbineStator
|
||||
name: steel gas turbine stator
|
||||
components:
|
||||
- type: GasTurbineStator
|
||||
material: Steel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 1000
|
||||
|
||||
- type: entity
|
||||
id: SilverGasTurbineStator
|
||||
parent: BaseGasTurbineStator
|
||||
name: silver gas turbine stator
|
||||
components:
|
||||
- type: GasTurbineStator
|
||||
material: Silver
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Silver: 1000
|
||||
|
||||
- type: entity
|
||||
id: GoldGasTurbineStator
|
||||
parent: BaseGasTurbineStator
|
||||
name: gold gas turbine stator
|
||||
components:
|
||||
- type: GasTurbineStator
|
||||
material: Gold
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Gold: 1000
|
||||
+511
@@ -0,0 +1,511 @@
|
||||
- type: entity
|
||||
id: BaseNuclearReactor
|
||||
parent: BaseStructure
|
||||
abstract: true
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: nuclear reactor
|
||||
description: A nuclear reactor vessel, with slots for fuel rods and other components. Hey wait, didn't one of these explode once?
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/nuclear_reactor.rsi
|
||||
layers:
|
||||
- state: reactor
|
||||
visible: true
|
||||
map: [ "enum.ReactorVisualLayers.Sprite" ]
|
||||
- state: reactor_status_active
|
||||
shader: unshaded
|
||||
visible: false
|
||||
map: [ "enum.ReactorVisualLayers.Status" ]
|
||||
- state: reactor_gas_input_lights
|
||||
shader: unshaded
|
||||
visible: false
|
||||
map: [ "enum.ReactorVisualLayers.Input" ]
|
||||
- state: reactor_gas_output_lights
|
||||
shader: unshaded
|
||||
visible: false
|
||||
map: [ "enum.ReactorVisualLayers.Output" ]
|
||||
- state: reactor_lights_warning
|
||||
shader: unshaded
|
||||
visible: false
|
||||
map: [ "enum.ReactorVisualLayers.Lights" ]
|
||||
- state: reactor_fire
|
||||
visible: false
|
||||
map: [ "enum.ReactorVisualLayers.Smoke" ]
|
||||
- state: reactor_smoke
|
||||
visible: false
|
||||
map: [ "enum.ReactorVisualLayers.Fire" ]
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.ReactorVisuals.Sprite:
|
||||
enum.ReactorVisualLayers.Sprite:
|
||||
Normal: { state: reactor }
|
||||
Melted: { state: reactorbroken }
|
||||
enum.ReactorVisuals.Status:
|
||||
enum.ReactorVisualLayers.Status:
|
||||
Off: { visible: false}
|
||||
Active: { state: reactor_status_active, visible: true }
|
||||
Overheat: { state: reactor_status_overheat, visible: true }
|
||||
Meltdown: { state: reactor_status_meltdown, visible: true }
|
||||
enum.ReactorVisuals.Input:
|
||||
enum.ReactorVisualLayers.Input:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.ReactorVisuals.Output:
|
||||
enum.ReactorVisualLayers.Output:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.ReactorVisuals.Lights:
|
||||
enum.ReactorVisualLayers.Lights:
|
||||
LightsOff: { visible: false }
|
||||
LightsWarning: { state: reactor_lights_warning, visible: true }
|
||||
LightsMeltdown: { state: reactor_lights_meltdown, visible: true }
|
||||
enum.ReactorVisuals.Smoke:
|
||||
enum.ReactorVisualLayers.Smoke:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.ReactorVisuals.Fire:
|
||||
enum.ReactorVisualLayers.Fire:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
- type: Appearance
|
||||
- type: InteractionOutline
|
||||
- type: Rotatable
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-2.5,-2.5,2.5,2"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- HighImpassable
|
||||
- type: Damageable
|
||||
damageContainer: StructuralInorganic
|
||||
damageModifierSet: StructuralReactorCasing
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 1000
|
||||
behaviors:
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
NuclearReactorMelted:
|
||||
min: 1
|
||||
max: 1
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: MetalBreak
|
||||
- type: Anchorable
|
||||
delay: 10
|
||||
- type: AtmosDevice
|
||||
- type: AtmosMonitoringConsoleDevice # TODO: this doesn't work?
|
||||
navMapBlip: Thermoregulator
|
||||
- type: RadiationSource
|
||||
intensity: 0
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
part_slot: !type:ContainerSlot {}
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
part_slot:
|
||||
whitelist:
|
||||
components:
|
||||
- ReactorPart
|
||||
- type: NuclearReactor
|
||||
- type: DeviceNetwork
|
||||
deviceNetId: Wireless
|
||||
receiveFrequencyId: BasicDevice
|
||||
- type: WirelessNetworkConnection
|
||||
range: 200
|
||||
- type: DeviceLinkSource
|
||||
range: 1000 # DeltaV - Was 50
|
||||
ports:
|
||||
- NuclearReactorDataSender
|
||||
- type: DeviceLinkSink
|
||||
ports:
|
||||
- InsertControlRods
|
||||
- RetractControlRods
|
||||
- type: ActivatableUI
|
||||
key: enum.NuclearReactorUiKey.Key
|
||||
- type: ActivatableUIRequiresAnchor
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.NuclearReactorUiKey.Key:
|
||||
type: NuclearReactorBoundUserInterface
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- NuclearReactor
|
||||
- Power
|
||||
|
||||
# Crew nuclear reactors
|
||||
- type: entity
|
||||
id: NuclearReactorCrew
|
||||
parent: BaseNuclearReactor
|
||||
abstract: true
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: AccessReader # You got a permit for that meltdown?
|
||||
access: [["Engineering"]]
|
||||
- type: Lock
|
||||
unlockOnClick: false
|
||||
- type: WarpPoint
|
||||
location: Nuclear Reactor
|
||||
blacklist:
|
||||
tags:
|
||||
- GhostOnlyWarp
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorNormal
|
||||
parent: NuclearReactorCrew
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorEmpty
|
||||
parent: NuclearReactorCrew
|
||||
suffix: Empty
|
||||
components:
|
||||
- type: NuclearReactor
|
||||
prefab: ReactorPrefabEmpty
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorRandom
|
||||
parent: NuclearReactorCrew
|
||||
suffix: Random
|
||||
components:
|
||||
- type: NuclearReactor
|
||||
prefab: random
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorMeltdown
|
||||
parent: NuclearReactorCrew
|
||||
suffix: Meltdown
|
||||
components:
|
||||
- type: NuclearReactor
|
||||
prefab: ReactorPrefab7x7Meltdown
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorMelted # This is more of a decoration than anything else
|
||||
parent: BaseStructure
|
||||
suffix: Melted
|
||||
name: nuclear reactor
|
||||
description: A broken nuclear reactor vessel. It glows with heat and radiation.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/nuclear_reactor.rsi
|
||||
layers:
|
||||
- state: reactorbroken
|
||||
- type: Rotatable
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-2.5,-2.5,2.5,2"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- HighImpassable
|
||||
- type: RadiationSource
|
||||
intensity: 7
|
||||
- type: InteractionOutline
|
||||
- type: PointLight
|
||||
energy: 0.1
|
||||
falloff: 2
|
||||
radius: 3.5
|
||||
color: "#FFAAAAFF"
|
||||
|
||||
# Small crew nuclear reactors
|
||||
- type: entity
|
||||
id: NuclearReactorSmall
|
||||
parent: NuclearReactorCrew
|
||||
name: small nuclear reactor
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/small_nuclear_reactor.rsi
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-1.5,-1.5,1.5,1.5"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- HighImpassable
|
||||
- type: NuclearReactor
|
||||
thermalMass: 302400
|
||||
reactorGridWidth: 5
|
||||
reactorGridHeight: 5
|
||||
prefab: ReactorPrefab5x5Normal
|
||||
inletPos: -1, 1
|
||||
inletRot: 180
|
||||
outletPos: 1, 1
|
||||
outletRot: 180
|
||||
arrowPrototype: ReactorSmallFlowArrow
|
||||
gridbounds: [ 12, 11, 0, 0 ]
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 700
|
||||
behaviors:
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
NuclearReactorSmallMelted:
|
||||
min: 1
|
||||
max: 1
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: MetalBreak
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorSmallRandom
|
||||
parent: NuclearReactorSmall
|
||||
suffix: Random
|
||||
components:
|
||||
- type: NuclearReactor
|
||||
prefab: random
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorSmallMelted
|
||||
parent: NuclearReactorMelted
|
||||
suffix: Melted
|
||||
name: small nuclear reactor
|
||||
description: A broken nuclear reactor vessel. It glows with heat and radiation.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/small_nuclear_reactor.rsi
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-1.5,-1.5,1.5,1.5"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- HighImpassable
|
||||
- type: RadiationSource
|
||||
intensity: 5
|
||||
- type: PointLight
|
||||
radius: 2.5
|
||||
|
||||
# Salvage nuclear reactors
|
||||
- type: entity
|
||||
id: NuclearReactorSalvage
|
||||
parent: BaseNuclearReactor
|
||||
abstract: true
|
||||
categories: [ HideSpawnMenu ]
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorNormalSalvage
|
||||
parent: NuclearReactorSalvage
|
||||
suffix: Salvage
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorEmptySalvage
|
||||
parent: NuclearReactorSalvage
|
||||
suffix: "Empty, Salvage"
|
||||
components:
|
||||
- type: NuclearReactor
|
||||
prefab: ReactorPrefabEmpty
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorRandomSalvage
|
||||
parent: NuclearReactorSalvage
|
||||
suffix: "Random, Salvage"
|
||||
components:
|
||||
- type: NuclearReactor
|
||||
prefab: random
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorMeltedSalvage
|
||||
parent: NuclearReactorMelted
|
||||
suffix: "Melted, Salvage"
|
||||
description: A nuclear reactor vessel, long since melted down. It still glows with residual heat and radiation.
|
||||
components:
|
||||
- type: RadiationSource
|
||||
intensity: 3.5
|
||||
- type: PointLight
|
||||
energy: 0.025
|
||||
|
||||
# Small salvage nuclear reactors
|
||||
- type: entity
|
||||
id: NuclearReactorSmallSalvage
|
||||
parent: NuclearReactorSalvage
|
||||
suffix: Salvage
|
||||
name: small nuclear reactor
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/small_nuclear_reactor.rsi
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-1.5,-1.5,1.5,1.5"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- HighImpassable
|
||||
- type: NuclearReactor
|
||||
thermalMass: 302400
|
||||
reactorGridWidth: 5
|
||||
reactorGridHeight: 5
|
||||
prefab: ReactorPrefab5x5Normal
|
||||
inletPos: -1, 1
|
||||
inletRot: 180
|
||||
outletPos: 1, 1
|
||||
outletRot: 180
|
||||
arrowPrototype: ReactorSmallFlowArrow
|
||||
gridbounds: [ 12, 11, 0, 0 ]
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorSmallRandomSalvage
|
||||
parent: NuclearReactorSmallSalvage
|
||||
suffix: "Random, Salvage"
|
||||
components:
|
||||
- type: NuclearReactor
|
||||
prefab: random
|
||||
|
||||
- type: entity
|
||||
id: NuclearReactorSmallMeltedSalvage
|
||||
parent: NuclearReactorSmallMelted
|
||||
suffix: "Melted, Salvage"
|
||||
description: A nuclear reactor vessel, long since melted down. It still glows with residual heat and radiation.
|
||||
components:
|
||||
- type: RadiationSource
|
||||
intensity: 2.5
|
||||
- type: PointLight
|
||||
energy: 0.025
|
||||
|
||||
# Nuclear debris resultant from a meltdown
|
||||
- type: entity
|
||||
id: NuclearDebrisChunk
|
||||
parent: BaseItem
|
||||
name: nuclear debris
|
||||
description: You do not see the graphite on the floor. You're in shock. Report to medical.
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/nuclear_debris.rsi
|
||||
layers:
|
||||
- state: graphite_damaged_0
|
||||
map: [ "base" ]
|
||||
- type: Item
|
||||
size: Huge
|
||||
- type: RandomSprite
|
||||
available:
|
||||
- base:
|
||||
graphite_damaged_0: ""
|
||||
graphite_damaged_0_mirrored: ""
|
||||
graphite_damaged_1: ""
|
||||
graphite_damaged_1_mirrored: ""
|
||||
graphite_damaged_2: ""
|
||||
graphite_damaged_2_mirrored: ""
|
||||
graphite_damaged_3: ""
|
||||
graphite_damaged_3_mirrored: ""
|
||||
graphite_damaged_4: ""
|
||||
graphite_damaged_4_mirrored: ""
|
||||
- type: RadiationSource
|
||||
intensity: 1.6
|
||||
|
||||
# Arrows to indicate flow
|
||||
- type: entity
|
||||
id: ReactorFlowArrow
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Markers/teg_arrow.rsi
|
||||
color: "#FFFFFFBB"
|
||||
layers:
|
||||
- state: arrow
|
||||
rotation: 90
|
||||
offset: 3, 1
|
||||
- state: arrow
|
||||
rotation: 90
|
||||
offset: -3, -1
|
||||
- type: TimedDespawn
|
||||
lifetime: 2
|
||||
- type: Tag
|
||||
tags:
|
||||
- HideContextMenu
|
||||
|
||||
- type: entity
|
||||
id: ReactorSmallFlowArrow
|
||||
parent: ReactorFlowArrow
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: arrow
|
||||
rotation: 0
|
||||
offset: -1, 2
|
||||
- state: arrow
|
||||
rotation: 180
|
||||
offset: 1, 2
|
||||
|
||||
# Pipes the reactor uses to connect to the pipe network
|
||||
- type: entity
|
||||
id: ReactorGasPipe
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Transform
|
||||
anchored: true
|
||||
- type: Anchorable
|
||||
- type: NodeContainer
|
||||
nodes:
|
||||
pipe:
|
||||
!type:PipeNode
|
||||
nodeGroupID: Pipe
|
||||
pipeDirection: South
|
||||
volume: 1000
|
||||
pipeLayer: 0
|
||||
pipe1:
|
||||
!type:PipeNode
|
||||
nodeGroupID: Pipe
|
||||
pipeDirection: South
|
||||
volume: 1000
|
||||
pipeLayer: 1
|
||||
pipe2:
|
||||
!type:PipeNode
|
||||
nodeGroupID: Pipe
|
||||
pipeDirection: South
|
||||
volume: 1000
|
||||
pipeLayer: 2
|
||||
- type: GasPipeManifold
|
||||
inlets:
|
||||
- pipe1
|
||||
- pipe2
|
||||
outlets:
|
||||
- pipe
|
||||
- type: PipeRestrictOverlap
|
||||
- type: Tag
|
||||
tags:
|
||||
- HideContextMenu
|
||||
|
||||
- type: entity
|
||||
id: ReactorAlarmEntity
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: AmbientSound
|
||||
volume: -3
|
||||
range: 15
|
||||
enabled: false
|
||||
sound:
|
||||
path: /Audio/_FarHorizons/Machines/reactor_alarm_1.ogg
|
||||
+254
@@ -0,0 +1,254 @@
|
||||
- type: nuclearReactorPrefab
|
||||
id: ReactorPrefabEmpty
|
||||
parts:
|
||||
-1,-1: BaseReactorPart # Can't be empty, so I'll put this nothing part in an inaccessible spot
|
||||
|
||||
- type: nuclearReactorPrefab
|
||||
id: ReactorPrefab7x7Normal
|
||||
parts:
|
||||
2,0: SteelReactorGasChannel
|
||||
2,2: SteelReactorGasChannel
|
||||
2,4: SteelReactorGasChannel
|
||||
2,6: SteelReactorGasChannel
|
||||
4,0: SteelReactorGasChannel
|
||||
4,2: SteelReactorGasChannel
|
||||
4,4: SteelReactorGasChannel
|
||||
4,6: SteelReactorGasChannel
|
||||
|
||||
2,1: SteelReactorHeatExchanger
|
||||
2,3: SteelReactorHeatExchanger
|
||||
2,5: SteelReactorHeatExchanger
|
||||
3,0: SteelReactorHeatExchanger
|
||||
3,6: SteelReactorHeatExchanger
|
||||
4,1: SteelReactorHeatExchanger
|
||||
4,3: SteelReactorHeatExchanger
|
||||
4,5: SteelReactorHeatExchanger
|
||||
|
||||
3,2: BohrumReactorControlRod
|
||||
3,4: BohrumReactorControlRod
|
||||
|
||||
- type: nuclearReactorPrefab
|
||||
id: ReactorPrefab7x7Debug
|
||||
parts:
|
||||
2,0: SteelReactorGasChannel
|
||||
2,2: SteelReactorGasChannel
|
||||
2,4: SteelReactorGasChannel
|
||||
2,6: SteelReactorGasChannel
|
||||
4,0: SteelReactorGasChannel
|
||||
4,2: SteelReactorGasChannel
|
||||
4,4: SteelReactorGasChannel
|
||||
4,6: SteelReactorGasChannel
|
||||
|
||||
2,1: SteelReactorHeatExchanger
|
||||
2,3: SteelReactorHeatExchanger
|
||||
2,5: SteelReactorHeatExchanger
|
||||
3,0: SteelReactorHeatExchanger
|
||||
3,6: SteelReactorHeatExchanger
|
||||
4,1: SteelReactorHeatExchanger
|
||||
4,3: SteelReactorHeatExchanger
|
||||
4,5: SteelReactorHeatExchanger
|
||||
|
||||
3,2: BohrumReactorControlRod
|
||||
3,4: BohrumReactorControlRod
|
||||
|
||||
3,1: CerenkiteReactorFuelRod
|
||||
3,3: CerenkiteReactorFuelRod
|
||||
3,5: CerenkiteReactorFuelRod
|
||||
|
||||
- type: nuclearReactorPrefab
|
||||
id: ReactorPrefab7x7Meltdown
|
||||
parts:
|
||||
0,0: PlutoniumReactorFuelRod
|
||||
1,0: PlutoniumReactorFuelRod
|
||||
2,0: PlutoniumReactorFuelRod
|
||||
3,0: PlutoniumReactorFuelRod
|
||||
4,0: PlutoniumReactorFuelRod
|
||||
5,0: PlutoniumReactorFuelRod
|
||||
6,0: PlutoniumReactorFuelRod
|
||||
|
||||
0,1: PlutoniumReactorFuelRod
|
||||
1,1: PlutoniumReactorFuelRod
|
||||
2,1: PlutoniumReactorFuelRod
|
||||
3,1: PlutoniumReactorFuelRod
|
||||
4,1: PlutoniumReactorFuelRod
|
||||
5,1: PlutoniumReactorFuelRod
|
||||
6,1: PlutoniumReactorFuelRod
|
||||
|
||||
0,2: PlutoniumReactorFuelRod
|
||||
1,2: PlutoniumReactorFuelRod
|
||||
2,2: PlutoniumReactorFuelRod
|
||||
3,2: PlutoniumReactorFuelRod
|
||||
4,2: PlutoniumReactorFuelRod
|
||||
5,2: PlutoniumReactorFuelRod
|
||||
6,2: PlutoniumReactorFuelRod
|
||||
|
||||
0,3: PlutoniumReactorFuelRod
|
||||
1,3: PlutoniumReactorFuelRod
|
||||
2,3: PlutoniumReactorFuelRod
|
||||
3,3: PlutoniumReactorFuelRod
|
||||
4,3: PlutoniumReactorFuelRod
|
||||
5,3: PlutoniumReactorFuelRod
|
||||
6,3: PlutoniumReactorFuelRod
|
||||
|
||||
0,4: PlutoniumReactorFuelRod
|
||||
1,4: PlutoniumReactorFuelRod
|
||||
2,4: PlutoniumReactorFuelRod
|
||||
3,4: PlutoniumReactorFuelRod
|
||||
4,4: PlutoniumReactorFuelRod
|
||||
5,4: PlutoniumReactorFuelRod
|
||||
6,4: PlutoniumReactorFuelRod
|
||||
|
||||
0,5: PlutoniumReactorFuelRod
|
||||
1,5: PlutoniumReactorFuelRod
|
||||
2,5: PlutoniumReactorFuelRod
|
||||
3,5: PlutoniumReactorFuelRod
|
||||
4,5: PlutoniumReactorFuelRod
|
||||
5,5: PlutoniumReactorFuelRod
|
||||
6,5: PlutoniumReactorFuelRod
|
||||
|
||||
0,6: PlutoniumReactorFuelRod
|
||||
1,6: PlutoniumReactorFuelRod
|
||||
2,6: PlutoniumReactorFuelRod
|
||||
3,6: PlutoniumReactorFuelRod
|
||||
4,6: PlutoniumReactorFuelRod
|
||||
5,6: PlutoniumReactorFuelRod
|
||||
6,6: PlutoniumReactorFuelRod
|
||||
|
||||
- type: nuclearReactorPrefab
|
||||
id: ReactorPrefab7x7Arachne
|
||||
parts:
|
||||
0,0: SteelReactorGasChannel
|
||||
0,2: SteelReactorGasChannel
|
||||
0,4: SteelReactorGasChannel
|
||||
0,6: SteelReactorGasChannel
|
||||
2,0: SteelReactorGasChannel
|
||||
2,3: SteelReactorGasChannel
|
||||
2,6: SteelReactorGasChannel
|
||||
3,2: SteelReactorGasChannel
|
||||
3,4: SteelReactorGasChannel
|
||||
4,0: SteelReactorGasChannel
|
||||
4,3: SteelReactorGasChannel
|
||||
4,6: SteelReactorGasChannel
|
||||
6,0: SteelReactorGasChannel
|
||||
6,2: SteelReactorGasChannel
|
||||
6,4: SteelReactorGasChannel
|
||||
6,6: SteelReactorGasChannel
|
||||
|
||||
0,1: SteelReactorHeatExchanger
|
||||
0,3: SteelReactorHeatExchanger
|
||||
0,5: SteelReactorHeatExchanger
|
||||
1,0: SteelReactorHeatExchanger
|
||||
1,6: SteelReactorHeatExchanger
|
||||
3,0: SteelReactorHeatExchanger
|
||||
3,6: SteelReactorHeatExchanger
|
||||
5,0: SteelReactorHeatExchanger
|
||||
5,6: SteelReactorHeatExchanger
|
||||
6,1: SteelReactorHeatExchanger
|
||||
6,3: SteelReactorHeatExchanger
|
||||
6,5: SteelReactorHeatExchanger
|
||||
|
||||
1,2: BohrumReactorControlRod
|
||||
1,4: BohrumReactorControlRod
|
||||
2,1: BohrumReactorControlRod
|
||||
2,2: BohrumReactorControlRod
|
||||
2,4: BohrumReactorControlRod
|
||||
2,5: BohrumReactorControlRod
|
||||
3,3: BohrumReactorControlRod
|
||||
4,1: BohrumReactorControlRod
|
||||
4,2: BohrumReactorControlRod
|
||||
4,4: BohrumReactorControlRod
|
||||
4,5: BohrumReactorControlRod
|
||||
5,2: BohrumReactorControlRod
|
||||
5,4: BohrumReactorControlRod
|
||||
|
||||
1,1: CerenkiteReactorFuelRod
|
||||
1,3: CerenkiteReactorFuelRod
|
||||
1,5: CerenkiteReactorFuelRod
|
||||
3,1: CerenkiteReactorFuelRod
|
||||
3,5: CerenkiteReactorFuelRod
|
||||
5,1: CerenkiteReactorFuelRod
|
||||
5,3: CerenkiteReactorFuelRod
|
||||
5,5: CerenkiteReactorFuelRod
|
||||
|
||||
- type: nuclearReactorPrefab
|
||||
id: ReactorPrefab7x7Lens
|
||||
parts:
|
||||
0,0: SteelReactorGasChannel
|
||||
0,2: SteelReactorGasChannel
|
||||
0,4: SteelReactorGasChannel
|
||||
0,6: SteelReactorGasChannel
|
||||
1,3: SteelReactorGasChannel
|
||||
2,0: SteelReactorGasChannel
|
||||
2,6: SteelReactorGasChannel
|
||||
3,1: SteelReactorGasChannel
|
||||
3,5: SteelReactorGasChannel
|
||||
4,0: SteelReactorGasChannel
|
||||
4,6: SteelReactorGasChannel
|
||||
5,3: SteelReactorGasChannel
|
||||
6,0: SteelReactorGasChannel
|
||||
6,2: SteelReactorGasChannel
|
||||
6,4: SteelReactorGasChannel
|
||||
6,6: SteelReactorGasChannel
|
||||
|
||||
0,1: SteelReactorHeatExchanger
|
||||
0,3: SteelReactorHeatExchanger
|
||||
0,5: SteelReactorHeatExchanger
|
||||
1,0: SteelReactorHeatExchanger
|
||||
1,6: SteelReactorHeatExchanger
|
||||
2,3: SteelReactorHeatExchanger
|
||||
3,0: SteelReactorHeatExchanger
|
||||
3,2: SteelReactorHeatExchanger
|
||||
3,4: SteelReactorHeatExchanger
|
||||
3,6: SteelReactorHeatExchanger
|
||||
4,3: SteelReactorHeatExchanger
|
||||
5,0: SteelReactorHeatExchanger
|
||||
5,6: SteelReactorHeatExchanger
|
||||
6,1: SteelReactorHeatExchanger
|
||||
6,3: SteelReactorHeatExchanger
|
||||
6,5: SteelReactorHeatExchanger
|
||||
|
||||
1,2: BohrumReactorControlRod
|
||||
1,4: BohrumReactorControlRod
|
||||
2,1: BohrumReactorControlRod
|
||||
2,2: BohrumReactorControlRod
|
||||
2,4: BohrumReactorControlRod
|
||||
2,5: BohrumReactorControlRod
|
||||
4,1: BohrumReactorControlRod
|
||||
4,2: BohrumReactorControlRod
|
||||
4,4: BohrumReactorControlRod
|
||||
4,5: BohrumReactorControlRod
|
||||
5,2: BohrumReactorControlRod
|
||||
5,4: BohrumReactorControlRod
|
||||
|
||||
1,1: CerenkiteReactorFuelRod
|
||||
1,5: CerenkiteReactorFuelRod
|
||||
3,3: CerenkiteReactorFuelRod
|
||||
5,1: CerenkiteReactorFuelRod
|
||||
5,5: CerenkiteReactorFuelRod
|
||||
|
||||
- type: nuclearReactorPrefab
|
||||
id: ReactorPrefab5x5Normal
|
||||
parts:
|
||||
0,0: SteelReactorGasChannel
|
||||
0,2: SteelReactorGasChannel
|
||||
0,4: SteelReactorGasChannel
|
||||
2,0: SteelReactorGasChannel
|
||||
2,4: SteelReactorGasChannel
|
||||
4,0: SteelReactorGasChannel
|
||||
4,2: SteelReactorGasChannel
|
||||
4,4: SteelReactorGasChannel
|
||||
|
||||
0,1: SteelReactorHeatExchanger
|
||||
0,3: SteelReactorHeatExchanger
|
||||
1,0: SteelReactorHeatExchanger
|
||||
1,4: SteelReactorHeatExchanger
|
||||
3,0: SteelReactorHeatExchanger
|
||||
3,4: SteelReactorHeatExchanger
|
||||
4,1: SteelReactorHeatExchanger
|
||||
4,3: SteelReactorHeatExchanger
|
||||
|
||||
1,2: BohrumReactorControlRod
|
||||
2,1: BohrumReactorControlRod
|
||||
2,2: BohrumReactorControlRod
|
||||
2,3: BohrumReactorControlRod
|
||||
3,2: BohrumReactorControlRod
|
||||
+525
@@ -0,0 +1,525 @@
|
||||
- type: entity
|
||||
id: BaseReactorPart
|
||||
parent: BaseItem
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: ReactorPart
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_parts.rsi
|
||||
state: default_rod
|
||||
- type: Item
|
||||
size: Huge
|
||||
- type: MultiHandedItem
|
||||
- type: Tag
|
||||
tags:
|
||||
- ReactorPart
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- NuclearReactor
|
||||
- Power
|
||||
|
||||
# Fuel Rods
|
||||
- type: entity
|
||||
id: BaseReactorFuelRod
|
||||
parent: [ BaseReactorPart, BaseEngineeringContraband ]
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: fuel rod
|
||||
description: A fuel rod for a nuclear reactor.
|
||||
components:
|
||||
- type: ReactorPart
|
||||
rodType: 1
|
||||
iconStateInserted: "fuel"
|
||||
iconStateCap: "fuel_cap"
|
||||
neutronCrossSection: 1.0
|
||||
thermalCrossSection: 10
|
||||
thermalMass: 420000 # specific heat capacity of steel (420 J/KgK) * mass of component (1000Kg)
|
||||
- type: Edible # Blame Abby for making them edible
|
||||
transferAmount: null
|
||||
delay: 30
|
||||
forceFeedDelay: 60
|
||||
- type: FlavorProfile
|
||||
flavors:
|
||||
- metal
|
||||
- electrons
|
||||
- type: BadFood
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
reagents:
|
||||
- ReagentId: Uranium
|
||||
Quantity: 800
|
||||
- ReagentId: Radium
|
||||
Quantity: 200
|
||||
canReact: false
|
||||
- type: StealTarget
|
||||
stealGroup: ReactorFuelRodSteal
|
||||
- type: SentienceTarget
|
||||
flavorKind: station-event-random-sentience-flavor-inanimate
|
||||
weight: 0.2
|
||||
|
||||
- type: entity
|
||||
id: CerenkiteReactorFuelRod
|
||||
parent: BaseReactorFuelRod
|
||||
name: cerenkite fuel rod # These are your basic, semi-harmless fuel rods
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Cerenkite
|
||||
|
||||
- type: entity
|
||||
id: UraniumReactorFuelRod
|
||||
parent: BaseReactorFuelRod
|
||||
name: uranium fuel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Uranium
|
||||
|
||||
- type: entity
|
||||
id: PlutoniumReactorFuelRod
|
||||
parent: BaseReactorFuelRod
|
||||
name: plutonium fuel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Plutonium
|
||||
- type: GhostRole
|
||||
makeSentient: true
|
||||
allowSpeech: true
|
||||
allowMovement: false
|
||||
name: ghost-role-information-plutonium-rod-name
|
||||
description: ghost-role-information-plutonium-rod-description
|
||||
rules: ghost-role-information-plutonium-rod-rules
|
||||
mindRoles:
|
||||
- MindRoleGhostRoleFreeAgentHarmless
|
||||
- type: GhostTakeoverAvailable
|
||||
- type: SentienceTarget
|
||||
weight: 2
|
||||
|
||||
- type: entity
|
||||
id: BananiumReactorFuelRod
|
||||
parent: BaseReactorFuelRod
|
||||
name: bananium fuel rod
|
||||
description: A honk rod for a nuclear reactor.
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Bananium
|
||||
|
||||
- type: entity
|
||||
id: PlasmaReactorFuelRod
|
||||
parent: BaseReactorFuelRod
|
||||
name: plasma fuel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Plasma
|
||||
|
||||
- type: entity
|
||||
id: UraniumGlassReactorFuelRod
|
||||
parent: BaseReactorFuelRod
|
||||
name: uranium glass fuel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: UraniumGlass
|
||||
|
||||
- type: entity
|
||||
id: MeatReactorFuelRod
|
||||
parent: BaseReactorFuelRod
|
||||
name: meat fuel rod
|
||||
description: A fuel rod fo- wait, is it alive?
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Meaterial
|
||||
properties:
|
||||
electrical: 4
|
||||
hard: 1
|
||||
density: 3
|
||||
flammable: 3
|
||||
radioactive: 5
|
||||
|
||||
# Control Rods
|
||||
- type: entity
|
||||
id: BaseReactorControlRod
|
||||
parent: BaseReactorPart
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: control rod
|
||||
description: A control rod assembly for a nuclear reactor.
|
||||
components:
|
||||
- type: ReactorPart
|
||||
rodType: 2
|
||||
iconStateInserted: "control"
|
||||
iconStateCap: "control_cap"
|
||||
isControlRod: true
|
||||
neutronCrossSection: 2.0
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
|
||||
- type: entity
|
||||
id: BohrumReactorControlRod
|
||||
parent: BaseReactorControlRod # what the crew start with
|
||||
name: bohrum control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Bohrum
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 500
|
||||
Plasteel: 250
|
||||
|
||||
- type: entity
|
||||
id: SteelReactorControlRod
|
||||
parent: BaseReactorControlRod
|
||||
name: steel control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Steel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 1500
|
||||
|
||||
- type: entity
|
||||
id: GoldReactorControlRod
|
||||
parent: BaseReactorControlRod
|
||||
name: gold control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Gold
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Gold: 500
|
||||
|
||||
- type: entity
|
||||
id: SilverReactorControlRod
|
||||
parent: BaseReactorControlRod
|
||||
name: silver control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Silver
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Silver: 500
|
||||
|
||||
- type: entity
|
||||
id: BrassReactorControlRod
|
||||
parent: BaseReactorControlRod
|
||||
name: brass control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Brass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Brass: 500
|
||||
|
||||
- type: entity
|
||||
id: PlasteelReactorControlRod
|
||||
parent: BaseReactorControlRod
|
||||
name: plasteel control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Plasteel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Plasteel: 500
|
||||
|
||||
- type: entity
|
||||
id: GlassReactorControlRod
|
||||
parent: BaseReactorControlRod
|
||||
name: glass control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Glass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Glass: 500
|
||||
|
||||
- type: entity
|
||||
id: PlasmaGlassReactorControlRod
|
||||
parent: BaseReactorControlRod
|
||||
name: plasma glass control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: PlasmaGlass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
PlasmaGlass: 500
|
||||
|
||||
- type: entity
|
||||
id: DiamondReactorControlRod
|
||||
parent: BaseReactorControlRod
|
||||
name: diamond control rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Diamond
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Diamond: 500
|
||||
|
||||
# Gas Channel Rods
|
||||
- type: entity
|
||||
id: BaseReactorGasChannel
|
||||
parent: BaseReactorPart
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: gas channel rod
|
||||
description: A gas channel for a nuclear reactor.
|
||||
components:
|
||||
- type: ReactorPart
|
||||
rodType: 4
|
||||
iconStateInserted: "gas"
|
||||
iconStateCap: "gas_cap"
|
||||
thermalCrossSection: 15
|
||||
gasVolume: 100
|
||||
thermalMass: 21000
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
|
||||
- type: entity
|
||||
id: SteelReactorGasChannel
|
||||
parent: BaseReactorGasChannel
|
||||
name: steel gas channel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Steel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 500
|
||||
|
||||
- type: entity
|
||||
id: GoldReactorGasChannel
|
||||
parent: BaseReactorGasChannel
|
||||
name: gold gas channel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Gold
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Gold: 250
|
||||
|
||||
- type: entity
|
||||
id: SilverReactorGasChannel
|
||||
parent: BaseReactorGasChannel
|
||||
name: silver gas channel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Silver
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Silver: 250
|
||||
|
||||
- type: entity
|
||||
id: BrassReactorGasChannel
|
||||
parent: BaseReactorGasChannel
|
||||
name: brass gas channel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Brass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Brass: 250
|
||||
|
||||
- type: entity
|
||||
id: PlasteelReactorGasChannel
|
||||
parent: BaseReactorGasChannel
|
||||
name: plasteel gas channel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Plasteel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Plasteel: 250
|
||||
|
||||
- type: entity
|
||||
id: GlassReactorGasChannel
|
||||
parent: BaseReactorGasChannel
|
||||
name: glass gas channel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Glass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Glass: 250
|
||||
|
||||
- type: entity
|
||||
id: PlasmaGlassReactorGasChannel
|
||||
parent: BaseReactorGasChannel
|
||||
name: plasma glass gas channel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: PlasmaGlass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
PlasmaGlass: 250
|
||||
|
||||
- type: entity
|
||||
id: DiamondReactorGasChannel
|
||||
parent: BaseReactorGasChannel
|
||||
name: diamond gas channel rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Diamond
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Diamond: 250
|
||||
|
||||
# Heat Exchanger Rods
|
||||
- type: entity
|
||||
id: BaseReactorHeatExchanger
|
||||
parent: BaseReactorPart
|
||||
categories: [ HideSpawnMenu ]
|
||||
name: heat exchanger rod
|
||||
description: A heat exchanger for a nuclear reactor.
|
||||
components:
|
||||
- type: ReactorPart
|
||||
iconStateInserted: "heat"
|
||||
iconStateCap: "heat_cap"
|
||||
neutronCrossSection: 0.1
|
||||
thermalCrossSection: 25
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
|
||||
- type: entity
|
||||
id: SteelReactorHeatExchanger
|
||||
parent: BaseReactorHeatExchanger
|
||||
name: steel heat exchanger rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Steel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 625
|
||||
|
||||
- type: entity
|
||||
id: GoldReactorHeatExchanger
|
||||
parent: BaseReactorHeatExchanger
|
||||
name: gold heat exchanger rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Gold
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Gold: 275
|
||||
|
||||
- type: entity
|
||||
id: SilverReactorHeatExchanger
|
||||
parent: BaseReactorHeatExchanger
|
||||
name: silver heat exchanger rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Silver
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Silver: 275
|
||||
|
||||
- type: entity
|
||||
id: BrassReactorHeatExchanger
|
||||
parent: BaseReactorHeatExchanger
|
||||
name: brass heat exchanger rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Brass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Brass: 275
|
||||
|
||||
- type: entity
|
||||
id: PlasteelReactorHeatExchanger
|
||||
parent: BaseReactorHeatExchanger
|
||||
name: plasteel heat exchanger rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Plasteel
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Plasteel: 275
|
||||
|
||||
- type: entity
|
||||
id: GlassReactorHeatExchanger
|
||||
parent: BaseReactorHeatExchanger
|
||||
name: glass heat exchanger rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Glass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Glass: 275
|
||||
|
||||
- type: entity
|
||||
id: PlasmaGlassReactorHeatExchanger
|
||||
parent: BaseReactorHeatExchanger
|
||||
name: plasma glass heat exchanger rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: PlasmaGlass
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
PlasmaGlass: 275
|
||||
|
||||
- type: entity
|
||||
id: DiamondReactorHeatExchanger
|
||||
parent: BaseReactorHeatExchanger
|
||||
name: diamond heat exchanger rod
|
||||
components:
|
||||
- type: ReactorPart
|
||||
material: Diamond
|
||||
- type: PhysicalComposition
|
||||
materialComposition:
|
||||
Steel: 250
|
||||
Diamond: 275
|
||||
|
||||
# Parts to chose from for a random prefab
|
||||
- type: weightedRandom
|
||||
id: NuclearReactorRandomParts
|
||||
weights:
|
||||
# Fuel rods (0.125 total)
|
||||
CerenkiteReactorFuelRod: 0.0625
|
||||
UraniumReactorFuelRod: 0.03125
|
||||
PlutoniumReactorFuelRod: 0.0015625
|
||||
BananiumReactorFuelRod: 0.00625
|
||||
PlasmaReactorFuelRod: 0.015625
|
||||
UraniumGlassReactorFuelRod: 0.0078125
|
||||
# Control rods (5 total)
|
||||
BohrumReactorControlRod: 1.25
|
||||
SteelReactorControlRod: 1.25
|
||||
GoldReactorControlRod: 0.125
|
||||
SilverReactorControlRod: 0.25
|
||||
BrassReactorControlRod: 0.5
|
||||
PlasteelReactorControlRod: 0.75
|
||||
GlassReactorControlRod: 0.5
|
||||
PlasmaGlassReactorControlRod: 0.25
|
||||
DiamondReactorControlRod: 0.125
|
||||
# Gas channels (40 total)
|
||||
SteelReactorGasChannel: 20
|
||||
GoldReactorGasChannel: 1
|
||||
SilverReactorGasChannel: 2
|
||||
BrassReactorGasChannel: 4
|
||||
PlasteelReactorGasChannel: 6
|
||||
GlassReactorGasChannel: 4
|
||||
PlasmaGlassReactorGasChannel: 2
|
||||
DiamondReactorGasChannel: 1
|
||||
# Heat exchangers (40 total)
|
||||
SteelReactorHeatExchanger: 20
|
||||
GoldReactorHeatExchanger: 1
|
||||
SilverReactorHeatExchanger: 2
|
||||
BrassReactorHeatExchanger: 4
|
||||
PlasteelReactorHeatExchanger: 6
|
||||
GlassReactorHeatExchanger: 4
|
||||
PlasmaGlassReactorHeatExchanger: 2
|
||||
DiamondReactorHeatExchanger: 1
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
- type: entity
|
||||
id: Turbine
|
||||
parent: BaseStructure
|
||||
name: gas turbine
|
||||
description: A large turbine used for generating power using hot gas.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/turbine.rsi
|
||||
layers:
|
||||
- state: turbine
|
||||
visible: true
|
||||
map: [ "enum.TurbineVisualLayers.TurbineSpeed" ]
|
||||
- state: turbinebroken
|
||||
visible: false
|
||||
map: [ "enum.TurbineVisualLayers.TurbineRuined" ]
|
||||
- state: turbine_sparks
|
||||
visible: false
|
||||
map: [ "enum.TurbineVisualLayers.DamageSpark" ]
|
||||
- state: turbine_smoke
|
||||
visible: false
|
||||
map: [ "enum.TurbineVisualLayers.DamageSmoke" ]
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.TurbineVisuals.TurbineRuined:
|
||||
enum.TurbineVisualLayers.TurbineRuined:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.TurbineVisuals.DamageSpark:
|
||||
enum.TurbineVisualLayers.DamageSpark:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
enum.TurbineVisuals.DamageSmoke:
|
||||
enum.TurbineVisualLayers.DamageSmoke:
|
||||
True: { visible: true }
|
||||
False: { visible: false }
|
||||
- type: Appearance
|
||||
- type: Physics
|
||||
bodyType: Static
|
||||
- type: InteractionOutline
|
||||
- type: Rotatable
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-1.5,-2.5,1.5,2.5"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: Damageable
|
||||
damageContainer: StructuralInorganic
|
||||
damageModifierSet: StructuralMetallicStrong
|
||||
- type: Anchorable
|
||||
delay: 10
|
||||
- type: NodeContainer
|
||||
examinable: true
|
||||
nodes:
|
||||
output:
|
||||
!type:CableDeviceNode
|
||||
nodeGroupID: HVPower
|
||||
- type: PowerMonitoringDevice
|
||||
group: Generator
|
||||
loadNode: output
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/turbine.rsi
|
||||
state: static
|
||||
- type: PowerSupplier
|
||||
supplyRampRate: 75000
|
||||
supplyRampTolerance: 5000
|
||||
- type: AtmosDevice
|
||||
- type: AtmosMonitoringConsoleDevice
|
||||
navMapBlip: Thermoregulator
|
||||
- type: Electrified
|
||||
enabled: false
|
||||
requirePower: false
|
||||
- type: ContainerContainer
|
||||
containers:
|
||||
blade_slot: !type:ContainerSlot {}
|
||||
stator_slot: !type:ContainerSlot {}
|
||||
- type: ItemSlots
|
||||
slots:
|
||||
blade_slot:
|
||||
startingItem: SteelGasTurbineBlade
|
||||
whitelist:
|
||||
components:
|
||||
- GasTurbineBlade
|
||||
stator_slot:
|
||||
startingItem: SteelGasTurbineStator
|
||||
whitelist:
|
||||
components:
|
||||
- GasTurbineStator
|
||||
- type: Turbine
|
||||
- type: DeviceNetwork
|
||||
deviceNetId: Wireless
|
||||
receiveFrequencyId: BasicDevice
|
||||
- type: WirelessNetworkConnection
|
||||
range: 200
|
||||
- type: DeviceLinkSource
|
||||
range: 1000 # DeltaV - Was 50
|
||||
ports:
|
||||
- GasTurbineDataSender
|
||||
- TurbineSpeedHigh
|
||||
- TurbineSpeedLow
|
||||
- type: DeviceLinkSink
|
||||
ports:
|
||||
- IncreaseStatorLoad
|
||||
- DecreaseStatorLoad
|
||||
- type: ActivatableUI
|
||||
key: enum.TurbineUiKey.Key
|
||||
- type: ActivatableUIRequiresAnchor
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.TurbineUiKey.Key:
|
||||
type: TurbineBoundUserInterface
|
||||
- type: AccessReader # Keeps some random tider from blowing up the turbine
|
||||
access: [["Engineering"]]
|
||||
- type: Lock
|
||||
unlockOnClick: false
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- NuclearReactor
|
||||
- Power
|
||||
|
||||
- type: entity
|
||||
id: TurbineSmall
|
||||
parent: Turbine
|
||||
name: small gas turbine
|
||||
description: A small turbine used for generating power using hot gas.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/small_turbine.rsi
|
||||
offset: 0, -0.5
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-1.5,-1.5,1.5,0.5"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: PowerMonitoringDevice
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/small_turbine.rsi
|
||||
- type: Turbine
|
||||
turbineMass: 400
|
||||
powerMultiplier: 0.4
|
||||
inletPos: 1, -1
|
||||
inletRot: 0
|
||||
outletPos: -1, -1
|
||||
outletRot: 0
|
||||
arrowPrototype: TurbineSmallFlowArrow
|
||||
|
||||
# Arrow to indicate flow
|
||||
- type: entity
|
||||
id: TurbineFlowArrow
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Markers/teg_arrow.rsi
|
||||
color: "#FFFFFFBB"
|
||||
layers:
|
||||
- state: arrow
|
||||
rotation: 90
|
||||
offset: 2, -1
|
||||
- state: arrow
|
||||
rotation: 90
|
||||
offset: -2, -1
|
||||
- type: TimedDespawn
|
||||
lifetime: 2
|
||||
- type: Tag
|
||||
tags:
|
||||
- HideContextMenu
|
||||
|
||||
- type: entity
|
||||
id: TurbineSmallFlowArrow
|
||||
parent: TurbineFlowArrow
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: arrow
|
||||
rotation: 180
|
||||
offset: 1, -2
|
||||
- state: arrow
|
||||
rotation: 0
|
||||
offset: -1, -2
|
||||
|
||||
# Pipes the turbine uses to connect to the pipe network
|
||||
- type: entity
|
||||
id: TurbineGasPipe
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: Transform
|
||||
anchored: true
|
||||
- type: Anchorable
|
||||
- type: NodeContainer
|
||||
nodes:
|
||||
pipe:
|
||||
!type:PipeNode
|
||||
nodeGroupID: Pipe
|
||||
pipeDirection: South
|
||||
volume: 1000
|
||||
pipeLayer: 0
|
||||
pipe1:
|
||||
!type:PipeNode
|
||||
nodeGroupID: Pipe
|
||||
pipeDirection: South
|
||||
volume: 1000
|
||||
pipeLayer: 1
|
||||
pipe2:
|
||||
!type:PipeNode
|
||||
nodeGroupID: Pipe
|
||||
pipeDirection: South
|
||||
volume: 1000
|
||||
pipeLayer: 2
|
||||
- type: GasPipeManifold
|
||||
inlets:
|
||||
- pipe1
|
||||
- pipe2
|
||||
outlets:
|
||||
- pipe
|
||||
- type: PipeRestrictOverlap
|
||||
- type: Tag
|
||||
tags:
|
||||
- HideContextMenu
|
||||
|
||||
- type: entity
|
||||
id: GasTurbineAlarmEntity
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: AmbientSound
|
||||
volume: -2
|
||||
range: 15
|
||||
enabled: false
|
||||
sound:
|
||||
path: /Audio/_FarHorizons/Machines/alarm_buzzer.ogg
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
- type: entity
|
||||
id: TurbineBladeShrapnel
|
||||
name: turbine blade
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: FlyBySound
|
||||
- type: Sprite
|
||||
noRot: false
|
||||
sprite: Objects/Materials/Scrap/generic.rsi
|
||||
state: metal-1
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
linearDamping: 0
|
||||
angularDamping: 0
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
projectile:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.1,-0.1,0.1,0.1"
|
||||
hard: false
|
||||
mask:
|
||||
- Impassable
|
||||
- BulletImpassable
|
||||
fly-by: &flybyfixture
|
||||
shape: !type:PhysShapeCircle
|
||||
radius: 1.5
|
||||
layer:
|
||||
- Impassable
|
||||
- MidImpassable
|
||||
- HighImpassable
|
||||
- LowImpassable
|
||||
hard: False
|
||||
- type: Projectile
|
||||
impactEffect: BulletImpactEffect
|
||||
deleteOnCollide: false
|
||||
damage:
|
||||
types: # hit hard ye
|
||||
Piercing: 25
|
||||
Slash: 75
|
||||
Structural: 400
|
||||
soundHit:
|
||||
path: /Audio/Effects/metal_crunch.ogg
|
||||
penetrationThreshold: 400
|
||||
penetrationDamageTypeRequirement:
|
||||
- Structural
|
||||
- type: TimedDespawn
|
||||
lifetime: 0.3
|
||||
@@ -0,0 +1,11 @@
|
||||
- type: guideEntry
|
||||
id: NuclearReactor
|
||||
name: guide-entry-nuclear-reactor
|
||||
text: "/ServerInfo/_FarHorizons/Guidebook/Engineering/NuclearReactor.xml"
|
||||
children:
|
||||
- NuclearMaterials
|
||||
|
||||
- type: guideEntry
|
||||
id: NuclearMaterials
|
||||
name: guide-entry-nuclear-materials
|
||||
text: "/ServerInfo/_FarHorizons/Guidebook/Engineering/NuclearMaterials.xml"
|
||||
@@ -0,0 +1,8 @@
|
||||
# Thief Collection
|
||||
|
||||
- type: stealTargetGroup
|
||||
id: ReactorFuelRodSteal
|
||||
name: steal-target-groups-reactorfuelrod
|
||||
sprite:
|
||||
sprite: _FarHorizons/Structures/Power/Generation/FissionGenerator/reactor_parts.rsi
|
||||
state: default_rod
|
||||
@@ -0,0 +1,12 @@
|
||||
- type: entity
|
||||
parent: BaseThiefStealCollectionObjective
|
||||
id: ReactorFuelRodStealCollectionObjective
|
||||
components:
|
||||
- type: NotJobRequirement
|
||||
jobs: [StationEngineer, AtmosphericTechnician]
|
||||
- type: StealCondition
|
||||
stealGroup: ReactorFuelRodSteal
|
||||
minCollectionSize: 1
|
||||
maxCollectionSize: 3
|
||||
- type: Objective
|
||||
difficulty: 2 # Large and radioactive
|
||||
@@ -0,0 +1,44 @@
|
||||
- type: material
|
||||
parent: Steel # TODO: Materials
|
||||
id: Bohrum
|
||||
name: materials-bohrum
|
||||
color: "#566558"
|
||||
price: 0.45 # $45 for 1 unit, arbitrary
|
||||
properties:
|
||||
electrical: 5
|
||||
thermal: 6
|
||||
hard: 5
|
||||
density: 6
|
||||
chemical: 7
|
||||
|
||||
- type: material
|
||||
id: Cerenkite
|
||||
stackEntity: SheetUranium1 # TODO: Materials
|
||||
name: materials-cerenkite
|
||||
icon: { sprite: Objects/Materials/Sheets/other.rsi, state: uranium } # TODO: Materials
|
||||
color: "#828aa4"
|
||||
price: 0.65 # $65 for 1 unit, arbitrary
|
||||
properties:
|
||||
electrical: 6
|
||||
thermal: 6
|
||||
hard: 2
|
||||
density: 4
|
||||
chemical: 6
|
||||
radioactive: 5
|
||||
|
||||
- type: material
|
||||
id: Plutonium
|
||||
stackEntity: IngotPlutonium1
|
||||
name: materials-plutonium
|
||||
unit: materials-unit-bar
|
||||
icon: { sprite: Objects/Materials/ingots.rsi, state: iron } # Why iron? Because I haven't gotten a spriter to make better
|
||||
color: "#404888"
|
||||
price: 1.75 # $175 for 1 unit, arbitrary
|
||||
properties:
|
||||
electrical: 7
|
||||
thermal: 6
|
||||
hard: 7
|
||||
density: 8
|
||||
chemical: 6
|
||||
radioactive: 3
|
||||
n_radioactive: 5
|
||||
@@ -0,0 +1,74 @@
|
||||
- type: latheRecipePack
|
||||
id: ReactorCircuitboards
|
||||
recipes:
|
||||
- NuclearFabricatorMachineCircuitboard
|
||||
- NuclearCentrifugeMachineCircuitboard
|
||||
- NuclearReactorMonitorComputerCircuitboard
|
||||
- GasTurbineMonitorComputerCircuitboard
|
||||
|
||||
- type: latheRecipePack
|
||||
id: ReactorPartsBasic
|
||||
recipes:
|
||||
- CerenkiteReactorFuelRod
|
||||
- BohrumReactorControlRod
|
||||
- SteelReactorControlRod
|
||||
- BrassReactorControlRod
|
||||
- GlassReactorControlRod
|
||||
- SteelReactorGasChannel
|
||||
- BrassReactorGasChannel
|
||||
- GlassReactorGasChannel
|
||||
- SteelReactorHeatExchanger
|
||||
- BrassReactorHeatExchanger
|
||||
- GlassReactorHeatExchanger
|
||||
- SteelGasTurbineBlade
|
||||
- SteelGasTurbineStator
|
||||
|
||||
- type: latheRecipePack
|
||||
id: ReactorFuelRods
|
||||
recipes:
|
||||
- UraniumReactorFuelRod
|
||||
- PlutoniumReactorFuelRod
|
||||
- BananiumReactorFuelRod
|
||||
- PlasmaReactorFuelRod
|
||||
- UraniumGlassReactorFuelRod
|
||||
|
||||
- type: latheRecipePack
|
||||
id: ReactorControlRods
|
||||
recipes:
|
||||
- GoldReactorControlRod
|
||||
- SilverReactorControlRod
|
||||
- PlasteelReactorControlRod
|
||||
- PlasmaGlassReactorControlRod
|
||||
- DiamondReactorControlRod
|
||||
|
||||
- type: latheRecipePack
|
||||
id: ReactorGasChannels
|
||||
recipes:
|
||||
- GoldReactorGasChannel
|
||||
- SilverReactorGasChannel
|
||||
- PlasteelReactorGasChannel
|
||||
- PlasmaGlassReactorGasChannel
|
||||
- DiamondReactorGasChannel
|
||||
|
||||
- type: latheRecipePack
|
||||
id: ReactorHeatExchangers
|
||||
recipes:
|
||||
- GoldReactorHeatExchanger
|
||||
- SilverReactorHeatExchanger
|
||||
- PlasteelReactorHeatExchanger
|
||||
- PlasmaGlassReactorHeatExchanger
|
||||
- DiamondReactorHeatExchanger
|
||||
|
||||
- type: latheRecipePack
|
||||
id: GasTurbineBlades
|
||||
recipes:
|
||||
- BrassGasTurbineBlade
|
||||
- DiamondGasTurbineBlade
|
||||
- GoldGasTurbineBlade
|
||||
- PlasteelGasTurbineBlade
|
||||
|
||||
- type: latheRecipePack
|
||||
id: GasTurbineStators
|
||||
recipes:
|
||||
- SilverGasTurbineStator
|
||||
- GoldGasTurbineStator
|
||||
@@ -0,0 +1,9 @@
|
||||
- type: latheRecipe
|
||||
parent: [ BaseCircuitboardRecipe, BaseEngineeringComputerRecipeCategory ]
|
||||
id: NuclearReactorMonitorComputerCircuitboard
|
||||
result: NuclearReactorMonitorComputerCircuitboard
|
||||
|
||||
- type: latheRecipe
|
||||
parent: [ BaseCircuitboardRecipe, BaseEngineeringComputerRecipeCategory ]
|
||||
id: GasTurbineMonitorComputerCircuitboard
|
||||
result: GasTurbineMonitorComputerCircuitboard
|
||||
@@ -0,0 +1,9 @@
|
||||
- type: latheRecipe
|
||||
parent: [ BaseCircuitboardRecipe, BaseEngineeringMachineRecipeCategory ]
|
||||
id: NuclearFabricatorMachineCircuitboard
|
||||
result: NuclearFabricatorMachineCircuitboard
|
||||
|
||||
- type: latheRecipe
|
||||
parent: [ BaseCircuitboardRecipe, BaseEngineeringMachineRecipeCategory ]
|
||||
id: NuclearCentrifugeMachineCircuitboard
|
||||
result: NuclearCentrifugeMachineCircuitboard
|
||||
@@ -0,0 +1,265 @@
|
||||
# Base prototypes
|
||||
|
||||
- type: latheRecipe
|
||||
abstract: true
|
||||
id: BaseReactorPartRecipe
|
||||
categories:
|
||||
- Engineering
|
||||
completetime: 10
|
||||
|
||||
## Recipes
|
||||
|
||||
# Fuel Rods
|
||||
# 5 Steel + 3 Fuel
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: CerenkiteReactorFuelRod
|
||||
result: CerenkiteReactorFuelRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Plasma: 200
|
||||
Uranium: 100
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: UraniumReactorFuelRod
|
||||
result: UraniumReactorFuelRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Uranium: 300
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: PlutoniumReactorFuelRod
|
||||
result: PlutoniumReactorFuelRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Plutonium: 300
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: BananiumReactorFuelRod
|
||||
result: BananiumReactorFuelRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Bananium: 300
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: PlasmaReactorFuelRod
|
||||
result: PlasmaReactorFuelRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Plasma: 300
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: UraniumGlassReactorFuelRod
|
||||
result: UraniumGlassReactorFuelRod
|
||||
materials:
|
||||
Steel: 500
|
||||
UraniumGlass: 300
|
||||
|
||||
# Control Rods
|
||||
# 5 Steel + 10 Material
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: BohrumReactorControlRod
|
||||
result: BohrumReactorControlRod
|
||||
materials:
|
||||
Steel: 1000
|
||||
Plasteel: 500
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: SteelReactorControlRod
|
||||
result: SteelReactorControlRod
|
||||
materials:
|
||||
Steel: 1500
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: GoldReactorControlRod
|
||||
result: GoldReactorControlRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Gold: 1000
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: SilverReactorControlRod
|
||||
result: SilverReactorControlRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Silver: 1000
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: BrassReactorControlRod
|
||||
result: BrassReactorControlRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Brass: 1000
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: PlasteelReactorControlRod
|
||||
result: PlasteelReactorControlRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Plasteel: 1000
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: GlassReactorControlRod
|
||||
result: GlassReactorControlRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Glass: 1000
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: PlasmaGlassReactorControlRod
|
||||
result: PlasmaGlassReactorControlRod
|
||||
materials:
|
||||
Steel: 500
|
||||
PlasmaGlass: 1000
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: DiamondReactorControlRod
|
||||
result: DiamondReactorControlRod
|
||||
materials:
|
||||
Steel: 500
|
||||
Diamond: 1000
|
||||
|
||||
|
||||
# Gas Channel Rods
|
||||
# 5 Steel + 5 Material
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: SteelReactorGasChannel
|
||||
result: SteelReactorGasChannel
|
||||
materials:
|
||||
Steel: 1000
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: GoldReactorGasChannel
|
||||
result: GoldReactorGasChannel
|
||||
materials:
|
||||
Steel: 500
|
||||
Gold: 500
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: SilverReactorGasChannel
|
||||
result: SilverReactorGasChannel
|
||||
materials:
|
||||
Steel: 500
|
||||
Silver: 500
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: BrassReactorGasChannel
|
||||
result: BrassReactorGasChannel
|
||||
materials:
|
||||
Steel: 500
|
||||
Brass: 500
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: PlasteelReactorGasChannel
|
||||
result: PlasteelReactorGasChannel
|
||||
materials:
|
||||
Steel: 500
|
||||
Plasteel: 500
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: GlassReactorGasChannel
|
||||
result: GlassReactorGasChannel
|
||||
materials:
|
||||
Steel: 500
|
||||
Glass: 500
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: PlasmaGlassReactorGasChannel
|
||||
result: PlasmaGlassReactorGasChannel
|
||||
materials:
|
||||
Steel: 500
|
||||
PlasmaGlass: 500
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: DiamondReactorGasChannel
|
||||
result: DiamondReactorGasChannel
|
||||
materials:
|
||||
Steel: 500
|
||||
Diamond: 500
|
||||
|
||||
# Heat Exchanger Rods
|
||||
# 5 Steel + 7.5 Material
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: SteelReactorHeatExchanger
|
||||
result: SteelReactorHeatExchanger
|
||||
materials:
|
||||
Steel: 1250
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: GoldReactorHeatExchanger
|
||||
result: GoldReactorHeatExchanger
|
||||
materials:
|
||||
Steel: 500
|
||||
Gold: 750
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: SilverReactorHeatExchanger
|
||||
result: SilverReactorHeatExchanger
|
||||
materials:
|
||||
Steel: 500
|
||||
Silver: 750
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: BrassReactorHeatExchanger
|
||||
result: BrassReactorHeatExchanger
|
||||
materials:
|
||||
Steel: 500
|
||||
Brass: 750
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: PlasteelReactorHeatExchanger
|
||||
result: PlasteelReactorHeatExchanger
|
||||
materials:
|
||||
Steel: 500
|
||||
Plasteel: 750
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: GlassReactorHeatExchanger
|
||||
result: GlassReactorHeatExchanger
|
||||
materials:
|
||||
Steel: 500
|
||||
Glass: 750
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: PlasmaGlassReactorHeatExchanger
|
||||
result: PlasmaGlassReactorHeatExchanger
|
||||
materials:
|
||||
Steel: 500
|
||||
PlasmaGlass: 750
|
||||
|
||||
- type: latheRecipe
|
||||
parent: BaseReactorPartRecipe
|
||||
id: DiamondReactorHeatExchanger
|
||||
result: DiamondReactorHeatExchanger
|
||||
materials:
|
||||
Steel: 500
|
||||
Diamond: 750
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user