Material generators from Afterlight (#18387)

This commit is contained in:
Nemanja 2023-07-31 14:42:38 -04:00 committed by GitHub
parent b9af7d3668
commit 2d08f02d23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 639 additions and 29 deletions

View File

@ -0,0 +1,26 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="350 130"
SetSize="360 180"
Title="{Loc 'generator-ui-title'}">
<BoxContainer Margin="4 0" Orientation="Horizontal">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" SizeFlagsStretchRatio="2" VerticalAlignment="Center" Margin="5">
<GridContainer Margin="2 0 0 0" Columns="2" HorizontalExpand="True">
<!-- Power -->
<Label Text="{Loc 'generator-ui-target-power-label'}"/>
<SpinBox Name="TargetPower" HorizontalExpand="True"/>
<Label Text="{Loc 'generator-ui-efficiency-label'}"/>
<Label Name="Efficiency" Text="???%" HorizontalExpand="True"/>
<Label Text="{Loc 'generator-ui-fuel-use-label'}"/>
<ProgressBar Name="FuelFraction" MinValue="0" MaxValue="1" HorizontalExpand="True"/>
<Label Text="{Loc 'generator-ui-fuel-left-label'}"/>
<Label Name="FuelLeft" Text="0" HorizontalExpand="True"/>
</GridContainer>
</BoxContainer>
<cc:VSeparator StyleClasses="LowDivider"/>
<PanelContainer Margin="12 0 0 0" StyleClasses="Inset" VerticalAlignment="Center">
<SpriteView Name="EntityView" SetSize="64 64" Scale="2 2" OverrideDirection="South" Margin="15"/>
</PanelContainer>
</BoxContainer>
</controls:FancyWindow>

View File

@ -0,0 +1,57 @@
using Content.Client.UserInterface.Controls;
using Content.Shared.Power.Generator;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Power.Generator;
[GenerateTypedNameReferences]
public sealed partial class GeneratorWindow : FancyWindow
{
[Dependency] private readonly IEntityManager _entityManager = default!;
private readonly FuelGeneratorComponent? _component;
private SolidFuelGeneratorComponentBuiState? _lastState;
public GeneratorWindow(SolidFuelGeneratorBoundUserInterface bui, EntityUid vis)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_entityManager.TryGetComponent(vis, out _component);
EntityView.SetEntity(vis);
TargetPower.IsValid += IsValid;
TargetPower.ValueChanged += (args) =>
{
bui.SetTargetPower(args.Value);
};
}
private bool IsValid(int arg)
{
if (arg < 0)
return false;
if (arg > (_lastState?.MaximumPower / 1000.0f ?? 0))
return false;
return true;
}
public void Update(SolidFuelGeneratorComponentBuiState state)
{
if (_component == null)
return;
var oldState = _lastState;
_lastState = state;
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (oldState?.TargetPower != state.TargetPower)
TargetPower.OverrideValue((int)(state.TargetPower / 1000.0f));
Efficiency.Text = SharedGeneratorSystem.CalcFuelEfficiency(state.TargetPower, state.OptimalPower, _component).ToString("P1");
FuelFraction.Value = state.RemainingFuel - (int) state.RemainingFuel;
FuelLeft.Text = ((int) MathF.Floor(state.RemainingFuel)).ToString();
}
}

View File

@ -0,0 +1,42 @@
using Content.Shared.Power.Generator;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.Power.Generator;
[UsedImplicitly]
public sealed class SolidFuelGeneratorBoundUserInterface : BoundUserInterface
{
private GeneratorWindow? _window;
public SolidFuelGeneratorBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_window = new GeneratorWindow(this, Owner);
_window.OpenCenteredLeft();
_window.OnClose += Close;
}
protected override void UpdateState(BoundUserInterfaceState state)
{
if (state is not SolidFuelGeneratorComponentBuiState msg)
return;
_window?.Update(msg);
}
protected override void Dispose(bool disposing)
{
_window?.Dispose();
}
public void SetTargetPower(int target)
{
SendMessage(new SetTargetPowerMessage(target));
}
}

View File

@ -27,4 +27,10 @@ public sealed class UpgradePowerSupplierComponent : Component
/// </summary> /// </summary>
[DataField("scaling", required: true), ViewVariables(VVAccess.ReadWrite)] [DataField("scaling", required: true), ViewVariables(VVAccess.ReadWrite)]
public MachineUpgradeScalingType Scaling; public MachineUpgradeScalingType Scaling;
/// <summary>
/// The current value that the power supply is being scaled by,
/// </summary>
[DataField("actualScalar"), ViewVariables(VVAccess.ReadWrite)]
public float ActualScalar = 1f;
} }

View File

@ -76,8 +76,12 @@ internal sealed class PowerMonitoringConsoleSystem : EntitySystem
} }
foreach (PowerSupplierComponent pcc in netQ.Suppliers) foreach (PowerSupplierComponent pcc in netQ.Suppliers)
{ {
sources.Add(LoadOrSource(pcc, pcc.MaxSupply, false)); var supply = pcc.Enabled
totalSources += pcc.MaxSupply; ? pcc.MaxSupply
: 0f;
sources.Add(LoadOrSource(pcc, supply, false));
totalSources += supply;
} }
foreach (BatteryDischargerComponent pcc in netQ.Dischargers) foreach (BatteryDischargerComponent pcc in netQ.Dischargers)
{ {

View File

@ -43,7 +43,7 @@ public sealed class UpgradePowerSystem : EntitySystem
load *= MathF.Pow(component.PowerDrawMultiplier, rating - 1); load *= MathF.Pow(component.PowerDrawMultiplier, rating - 1);
break; break;
default: default:
Logger.Error($"invalid power scaling type for {ToPrettyString(uid)}."); Log.Error($"invalid power scaling type for {ToPrettyString(uid)}.");
load = 0; load = 0;
break; break;
} }
@ -82,19 +82,19 @@ public sealed class UpgradePowerSystem : EntitySystem
supply *= MathF.Pow(component.PowerSupplyMultiplier, rating - 1); supply *= MathF.Pow(component.PowerSupplyMultiplier, rating - 1);
break; break;
default: default:
Logger.Error($"invalid power scaling type for {ToPrettyString(uid)}."); Log.Error($"invalid power scaling type for {ToPrettyString(uid)}.");
supply = component.BaseSupplyRate; supply = component.BaseSupplyRate;
break; break;
} }
component.ActualScalar = supply / component.BaseSupplyRate;
if (TryComp<PowerSupplierComponent>(uid, out var powa)) if (TryComp<PowerSupplierComponent>(uid, out var powa))
powa.MaxSupply = supply; powa.MaxSupply = supply;
} }
private void OnSupplierUpgradeExamine(EntityUid uid, UpgradePowerSupplierComponent component, UpgradeExamineEvent args) private void OnSupplierUpgradeExamine(EntityUid uid, UpgradePowerSupplierComponent component, UpgradeExamineEvent args)
{ {
// UpgradePowerSupplierComponent.PowerSupplyMultiplier is not the actual multiplier, so we have to do this. args.AddPercentageUpgrade("upgrade-power-supply", component.ActualScalar);
if (TryComp<PowerSupplierComponent>(uid, out var powa))
args.AddPercentageUpgrade("upgrade-power-supply", powa.MaxSupply / component.BaseSupplyRate);
} }
} }

View File

@ -0,0 +1,24 @@
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Whitelist;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
namespace Content.Server.Power.Generator;
/// <summary>
/// This is used for chemical fuel input into generators.
/// </summary>
[RegisterComponent, Access(typeof(GeneratorSystem))]
public sealed class ChemicalFuelGeneratorAdapterComponent : Component
{
/// <summary>
/// The acceptable list of input entities.
/// </summary>
[DataField("whitelist")]
public EntityWhitelist? Whitelist;
/// <summary>
/// The conversion factor for different chems you can put in.
/// </summary>
[DataField("chemConversionFactors", required: true, customTypeSerializer:typeof(PrototypeIdDictionarySerializer<float, ReagentPrototype>))]
public Dictionary<string, float> ChemConversionFactors = default!;
}

View File

@ -0,0 +1,14 @@
namespace Content.Server.Power.Generator;
/// <summary>
/// This is used for stuff that can directly be shoved into a generator.
/// </summary>
[RegisterComponent, Access(typeof(GeneratorSystem))]
public sealed class ChemicalFuelGeneratorDirectSourceComponent : Component
{
/// <summary>
/// The solution to pull fuel material from.
/// </summary>
[DataField("solution", required: true), ViewVariables(VVAccess.ReadWrite)]
public string Solution = default!;
}

View File

@ -0,0 +1,47 @@
using Content.Shared.Atmos;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Power.Generator;
/// <summary>
/// This is used for providing gas power to machinery.
/// </summary>
[RegisterComponent, Access(typeof(GasPowerReceiverSystem))]
public sealed class GasPowerReceiverComponent : Component
{
/// <summary>
/// Past this temperature we assume we're in reaction mass mode and not magic mode.
/// </summary>
[DataField("maxTemperature"), ViewVariables(VVAccess.ReadWrite)]
public float MaxTemperature = 1000.0f;
/// <summary>
/// The gas that fuels this generator
/// </summary>
[DataField("targetGas", required: true), ViewVariables(VVAccess.ReadWrite)]
public Gas TargetGas;
/// <summary>
/// The amount of gas consumed for operation in magic mode.
/// </summary>
[DataField("molesConsumedSec"), ViewVariables(VVAccess.ReadWrite)]
public float MolesConsumedSec = 1.55975875833f / 4;
/// <summary>
/// The amount of kPA "consumed" for operation in pressure mode.
/// </summary>
[DataField("pressureConsumedSec"), ViewVariables(VVAccess.ReadWrite)]
public float PressureConsumedSec = 100f;
/// <summary>
/// Whether the consumed gas should then be ejected directly into the atmosphere.
/// </summary>
[DataField("offVentGas"), ViewVariables(VVAccess.ReadWrite)]
public bool OffVentGas;
[DataField("lastProcess", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan LastProcess = TimeSpan.Zero;
[DataField("powered"), ViewVariables(VVAccess.ReadWrite)]
public bool Powered = true;
}

View File

@ -0,0 +1,92 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Shared.Atmos;
using Robust.Shared.Timing;
namespace Content.Server.Power.Generator;
/// <summary>
/// This handles gas power receivers, allowing devices to accept power in the form of a gas.
/// </summary>
public sealed class GasPowerReceiverSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<GasPowerReceiverComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<GasPowerReceiverComponent, AtmosDeviceUpdateEvent>(OnDeviceUpdated);
}
private void OnMapInit(EntityUid uid, GasPowerReceiverComponent component, MapInitEvent args)
{
component.LastProcess = _gameTiming.CurTime;
}
private void OnDeviceUpdated(EntityUid uid, GasPowerReceiverComponent component, AtmosDeviceUpdateEvent args)
{
var timeDelta = (float)(_gameTiming.CurTime - component.LastProcess).TotalSeconds;
component.LastProcess = _gameTiming.CurTime;
if (!HasComp<AtmosDeviceComponent>(uid)
|| !TryComp<NodeContainerComponent>(uid, out var nodeContainer)
|| !_nodeContainer.TryGetNode<PipeNode>(nodeContainer, "pipe", out var pipe))
{
return;
}
// if we're below the max temperature, then we are simply consuming our target gas
if (pipe.Air.Temperature <= component.MaxTemperature)
{
// we have enough gas, so we consume it and are powered
if (pipe.Air.Moles[(int) component.TargetGas] > component.MolesConsumedSec * timeDelta)
{
pipe.Air.AdjustMoles(component.TargetGas, -component.MolesConsumedSec * timeDelta);
SetPowered(uid, component, true);
}
else // we do not have enough gas, so we power off
{
SetPowered(uid, component, false);
}
}
else // we are exceeding the max temp and are now operating in pressure mode
{
var pres = component.PressureConsumedSec * timeDelta;
if (pipe.Air.Pressure >= pres)
{
// remove gas from the pipe
var res = pipe.Air.Remove(pres * 100.0f / (Atmospherics.R * pipe.Air.Temperature));
if (component.OffVentGas)
{
// eject the gas into the atmosphere
var mix = _atmosphereSystem.GetContainingMixture(uid, false, true);
if (mix is not null)
_atmosphereSystem.Merge(res, mix);
}
SetPowered(uid, component, true);
}
else // if we do not have high enough pressure to operate, power off
{
SetPowered(uid, component, false);
}
}
}
private void SetPowered(EntityUid uid, GasPowerReceiverComponent comp, bool state)
{
if (state != comp.Powered)
{
comp.Powered = state;
var ev = new PowerChangedEvent(state, 0);
RaiseLocalEvent(uid, ref ev);
}
}
}

View File

@ -0,0 +1,123 @@
using Content.Server.Chemistry.Components.SolutionManager;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.Interaction;
using Content.Shared.Materials;
using Content.Shared.Power.Generator;
using Content.Shared.Stacks;
using Robust.Server.GameObjects;
namespace Content.Server.Power.Generator;
/// <inheritdoc/>
public sealed class GeneratorSystem : SharedGeneratorSystem
{
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly SharedStackSystem _stack = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
private EntityQuery<UpgradePowerSupplierComponent> _upgradeQuery;
public override void Initialize()
{
_upgradeQuery = GetEntityQuery<UpgradePowerSupplierComponent>();
SubscribeLocalEvent<SolidFuelGeneratorAdapterComponent, InteractUsingEvent>(OnSolidFuelAdapterInteractUsing);
SubscribeLocalEvent<ChemicalFuelGeneratorAdapterComponent, InteractUsingEvent>(OnChemicalFuelAdapterInteractUsing);
SubscribeLocalEvent<FuelGeneratorComponent, SetTargetPowerMessage>(OnTargetPowerSet);
}
private void OnChemicalFuelAdapterInteractUsing(EntityUid uid, ChemicalFuelGeneratorAdapterComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
if (!TryComp<SolutionContainerManagerComponent>(args.Used, out var solutions) ||
!TryComp<FuelGeneratorComponent>(uid, out var generator))
return;
if (!(component.Whitelist?.IsValid(args.Used) ?? true))
return;
if (TryComp<ChemicalFuelGeneratorDirectSourceComponent>(args.Used, out var source))
{
if (!solutions.Solutions.ContainsKey(source.Solution))
{
Log.Error($"Couldn't get solution {source.Solution} on {ToPrettyString(args.Used)}");
return;
}
var solution = solutions.Solutions[source.Solution];
generator.RemainingFuel += ReagentsToFuel(component, solution);
solution.RemoveAllSolution();
QueueDel(args.Used);
}
}
private float ReagentsToFuel(ChemicalFuelGeneratorAdapterComponent component, Solution solution)
{
var total = 0.0f;
foreach (var reagent in solution.Contents)
{
if (!component.ChemConversionFactors.ContainsKey(reagent.ReagentId))
continue;
total += reagent.Quantity.Float() * component.ChemConversionFactors[reagent.ReagentId];
}
return total;
}
private void OnTargetPowerSet(EntityUid uid, FuelGeneratorComponent component, SetTargetPowerMessage args)
{
component.TargetPower = Math.Clamp(args.TargetPower, 0, component.MaxTargetPower / 1000) * 1000;
}
private void OnSolidFuelAdapterInteractUsing(EntityUid uid, SolidFuelGeneratorAdapterComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
if (!TryComp<PhysicalCompositionComponent>(args.Used, out var mat) ||
!HasComp<MaterialComponent>(args.Used) ||
!TryComp<FuelGeneratorComponent>(uid, out var generator))
return;
if (!mat.MaterialComposition.ContainsKey(component.FuelMaterial))
return;
_popup.PopupEntity(Loc.GetString("generator-insert-material", ("item", args.Used), ("generator", uid)), uid);
generator.RemainingFuel += _stack.GetCount(args.Used) * component.Multiplier;
QueueDel(args.Used);
args.Handled = true;
}
public override void Update(float frameTime)
{
var query = EntityQueryEnumerator<FuelGeneratorComponent, PowerSupplierComponent, TransformComponent>();
while (query.MoveNext(out var uid, out var gen, out var supplier, out var xform))
{
supplier.Enabled = gen.RemainingFuel > 0.0f && xform.Anchored;
var upgradeMultiplier = _upgradeQuery.CompOrNull(uid)?.ActualScalar ?? 1f;
supplier.MaxSupply = gen.TargetPower * upgradeMultiplier;
var eff = 1 / CalcFuelEfficiency(gen.TargetPower, gen.OptimalPower, gen);
gen.RemainingFuel = MathF.Max(gen.RemainingFuel - (gen.OptimalBurnRate * frameTime * eff), 0.0f);
UpdateUi(uid, gen);
}
}
private void UpdateUi(EntityUid uid, FuelGeneratorComponent comp)
{
if (!_uiSystem.IsUiOpen(uid, GeneratorComponentUiKey.Key))
return;
_uiSystem.TrySetUiState(uid, GeneratorComponentUiKey.Key, new SolidFuelGeneratorComponentBuiState(comp));
}
}

View File

@ -0,0 +1,23 @@
using Content.Shared.Materials;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Power.Generator;
/// <summary>
/// This is used for allowing you to insert fuel into gens.
/// </summary>
[RegisterComponent, Access(typeof(GeneratorSystem))]
public sealed class SolidFuelGeneratorAdapterComponent : Component
{
/// <summary>
/// The material to accept as fuel.
/// </summary>
[DataField("fuelMaterial", customTypeSerializer: typeof(PrototypeIdSerializer<MaterialPrototype>)), ViewVariables(VVAccess.ReadWrite)]
public string FuelMaterial = "Plasma";
/// <summary>
/// How much fuel that material should count for.
/// </summary>
[DataField("multiplier"), ViewVariables(VVAccess.ReadWrite)]
public float Multiplier = 1.0f;
}

View File

@ -0,0 +1,87 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Power.Generator;
/// <summary>
/// This is used for generators that run off some kind of fuel.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedGeneratorSystem))]
public sealed class FuelGeneratorComponent : Component
{
/// <summary>
/// The amount of fuel left in the generator.
/// </summary>
[DataField("remainingFuel"), ViewVariables(VVAccess.ReadWrite)]
public float RemainingFuel;
/// <summary>
/// The generator's target power.
/// </summary>
[DataField("targetPower"), ViewVariables(VVAccess.ReadWrite)]
public float TargetPower = 15_000.0f;
/// <summary>
/// The maximum target power.
/// </summary>
[DataField("maxTargetPower"), ViewVariables(VVAccess.ReadWrite)]
public float MaxTargetPower = 30_000.0f;
/// <summary>
/// The "optimal" power at which the generator is considered to be at 100% efficiency.
/// </summary>
[DataField("optimalPower"), ViewVariables(VVAccess.ReadWrite)]
public float OptimalPower = 15_000.0f;
/// <summary>
/// The rate at which one unit of fuel should be consumed.
/// </summary>
[DataField("optimalBurnRate"), ViewVariables(VVAccess.ReadWrite)]
public float OptimalBurnRate = 1 / 60.0f; // Once every 60 seconds.
/// <summary>
/// A constant used to calculate fuel efficiency in relation to target power output and optimal power output
/// </summary>
[DataField("fuelEfficiencyConstant")]
public float FuelEfficiencyConstant = 1.3f;
}
/// <summary>
/// Sent to the server to adjust the targeted power level.
/// </summary>
[Serializable, NetSerializable]
public sealed class SetTargetPowerMessage : BoundUserInterfaceMessage
{
public int TargetPower;
public SetTargetPowerMessage(int targetPower)
{
TargetPower = targetPower;
}
}
/// <summary>
/// Contains network state for FuelGeneratorComponent.
/// </summary>
[Serializable, NetSerializable]
public sealed class SolidFuelGeneratorComponentBuiState : BoundUserInterfaceState
{
public float RemainingFuel;
public float TargetPower;
public float MaximumPower;
public float OptimalPower;
public SolidFuelGeneratorComponentBuiState(FuelGeneratorComponent component)
{
RemainingFuel = component.RemainingFuel;
TargetPower = component.TargetPower;
MaximumPower = component.MaxTargetPower;
OptimalPower = component.OptimalPower;
}
}
[Serializable, NetSerializable]
public enum GeneratorComponentUiKey
{
Key
}

View File

@ -0,0 +1,19 @@
namespace Content.Shared.Power.Generator;
/// <summary>
/// This handles small, portable generators that run off a material fuel.
/// </summary>
public abstract class SharedGeneratorSystem : EntitySystem
{
/// <summary>
/// Calculates the expected fuel efficiency based on the optimal and target power levels.
/// </summary>
/// <param name="targetPower">Target power level</param>
/// <param name="optimalPower">Optimal power level</param>
/// <param name="component"></param>
/// <returns>Expected fuel efficiency as a percentage</returns>
public static float CalcFuelEfficiency(float targetPower, float optimalPower, FuelGeneratorComponent component)
{
return MathF.Pow(optimalPower / targetPower, component.FuelEfficiencyConstant);
}
}

View File

@ -3,7 +3,6 @@ using Content.Shared.Examine;
using Content.Shared.Hands.Components; using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems; using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Item;
using Content.Shared.Popups; using Content.Shared.Popups;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
@ -228,6 +227,17 @@ namespace Content.Shared.Stacks
return merged; return merged;
} }
/// <summary>
/// Gets the amount of items in a stack. If it cannot be stacked, returns 1.
/// </summary>
/// <param name="uid"></param>
/// <param name="component"></param>
/// <returns></returns>
public int GetCount(EntityUid uid, StackComponent? component = null)
{
return Resolve(uid, ref component, false) ? component.Count : 1;
}
/// <summary> /// <summary>
/// Gets the max count for a given entity prototype /// Gets the max count for a given entity prototype
/// </summary> /// </summary>

View File

@ -0,0 +1,7 @@
generator-ui-title = Generator
generator-ui-target-power-label = Target Power (KW):
generator-ui-efficiency-label = Efficiency:
generator-ui-fuel-use-label = Fuel use:
generator-ui-fuel-left-label = Fuel left:
generator-insert-material = Inserted {THE($item)} into {THE($generator)}...

View File

@ -3495,7 +3495,7 @@ entities:
- pos: -12.5,2.5 - pos: -12.5,2.5
parent: 818 parent: 818
type: Transform type: Transform
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 124 - uid: 124
components: components:

View File

@ -1243,7 +1243,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 114 - uid: 114
components: components:

View File

@ -972,7 +972,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 83 - uid: 83
components: components:

View File

@ -4489,7 +4489,7 @@ entities:
- pos: 4.5,-21.5 - pos: 4.5,-21.5
parent: 1 parent: 1
type: Transform type: Transform
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 72 - uid: 72
components: components:

View File

@ -1908,7 +1908,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 239 - uid: 239
components: components:

View File

@ -2874,7 +2874,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 214 - uid: 214
components: components:

View File

@ -2619,7 +2619,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 66 - uid: 66
components: components:

View File

@ -3153,7 +3153,7 @@ entities:
type: AmbientSound type: AmbientSound
- color: '#0335FCFF' - color: '#0335FCFF'
type: AtmosPipeColor type: AtmosPipeColor
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 402 - uid: 402
components: components:

View File

@ -11414,7 +11414,7 @@ entities:
type: AmbientSound type: AmbientSound
- color: '#0055CCFF' - color: '#0055CCFF'
type: AtmosPipeColor type: AtmosPipeColor
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 609 - uid: 609
components: components:

View File

@ -2548,7 +2548,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 344 - uid: 344
components: components:

View File

@ -2434,7 +2434,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 138 - uid: 138
components: components:

View File

@ -982,7 +982,7 @@ entities:
- pos: -1.5,-5.5 - pos: -1.5,-5.5
parent: 181 parent: 181
type: Transform type: Transform
- proto: GeneratorPlasma - proto: GeneratorBasic15kW
entities: entities:
- uid: 67 - uid: 67
components: components:

View File

@ -2883,7 +2883,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 55 - uid: 55
components: components:

View File

@ -1241,7 +1241,7 @@ entities:
type: DeviceNetwork type: DeviceNetwork
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 41 - uid: 41
components: components:

View File

@ -2871,7 +2871,7 @@ entities:
type: Transform type: Transform
- enabled: False - enabled: False
type: AmbientSound type: AmbientSound
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 358 - uid: 358
components: components:

View File

@ -25140,7 +25140,7 @@ entities:
- pos: 32.5,-21.5 - pos: 32.5,-21.5
parent: 1668 parent: 1668
type: Transform type: Transform
- proto: GeneratorUranium - proto: GeneratorBasic15kW
entities: entities:
- uid: 5176 - uid: 5176
components: components:

View File

@ -6031,7 +6031,7 @@ entities:
- pos: -5.7255287,20.539352 - pos: -5.7255287,20.539352
parent: 104 parent: 104
type: Transform type: Transform
- proto: GeneratorPlasma - proto: GeneratorBasic15kW
entities: entities:
- uid: 2326 - uid: 2326
components: components:

View File

@ -167,13 +167,20 @@
- type: PowerSupplier - type: PowerSupplier
supplyRate: 3000 supplyRate: 3000
- type: entity
parent: BaseGenerator
id: GeneratorBasic15kW
suffix: Basic, 15kW
components:
- type: PowerSupplier
supplyRate: 15000
- type: entity - type: entity
parent: [ BaseGenerator, ConstructibleMachine ] parent: [ BaseGenerator, ConstructibleMachine ]
id: GeneratorPlasma id: GeneratorPlasma
suffix: Plasma, 5kW suffix: Plasma, 20kW
components: components:
- type: PowerSupplier - type: PowerSupplier
supplyRate: 5000 # 260 sec / sheet
- type: Sprite - type: Sprite
sprite: Structures/Power/Generation/portable_generator.rsi sprite: Structures/Power/Generation/portable_generator.rsi
state: portgen0_1 state: portgen0_1
@ -186,14 +193,24 @@
- type: UpgradePowerSupplier - type: UpgradePowerSupplier
powerSupplyMultiplier: 1.25 powerSupplyMultiplier: 1.25
scaling: Exponential scaling: Exponential
- type: FuelGenerator
targetPower: 20000
optimalPower: 20000
- type: SolidFuelGeneratorAdapter
fuelMaterial: Plasma
- type: ActivatableUI
key: enum.GeneratorComponentUiKey.Key
- type: UserInterface
interfaces:
- key: enum.GeneratorComponentUiKey.Key
type: SolidFuelGeneratorBoundUserInterface
- type: entity - type: entity
parent: [ BaseGenerator, ConstructibleMachine ] parent: [ BaseGenerator, ConstructibleMachine ]
id: GeneratorUranium id: GeneratorUranium
suffix: Uranium, 15kW suffix: Uranium, 30kW
components: components:
- type: PowerSupplier - type: PowerSupplier
supplyRate: 15000 # 85 sec / sheet
- type: Sprite - type: Sprite
sprite: Structures/Power/Generation/portable_generator.rsi sprite: Structures/Power/Generation/portable_generator.rsi
state: portgen1_1 state: portgen1_1
@ -206,6 +223,18 @@
- type: UpgradePowerSupplier - type: UpgradePowerSupplier
powerSupplyMultiplier: 1.25 powerSupplyMultiplier: 1.25
scaling: Exponential scaling: Exponential
- type: FuelGenerator
targetPower: 30000
optimalPower: 30000
optimalBurnRate: 0.00416666666
- type: SolidFuelGeneratorAdapter
fuelMaterial: Uranium
- type: ActivatableUI
key: enum.GeneratorComponentUiKey.Key
- type: UserInterface
interfaces:
- key: enum.GeneratorComponentUiKey.Key
type: SolidFuelGeneratorBoundUserInterface
- type: entity - type: entity
parent: BaseGeneratorWallmount parent: BaseGeneratorWallmount