Make PACMANs a little better (#24604)
* PACMAN generators show network load/supply. This gives more feedback to players that their PACMAN is properly connected and what the network status is (i.e. you don't have enough generators). * Buff JRPACMAN to 8 kW. Shifted all power values up by +3 kW. They're frequently too weak to power even single rooms so they deserve a buff. * Change unit format helpers number format. Always displays one digit of precision. This avoids jumping around when a value is changing live.
This commit is contained in:
committed by
GitHub
parent
41c0efeaf1
commit
f855cb2b00
@@ -1,8 +1,8 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
MinSize="450 235"
|
MinSize="450 250"
|
||||||
SetSize="450 235"
|
SetSize="450 250"
|
||||||
Resizable="False"
|
Resizable="False"
|
||||||
Title="{Loc 'portable-generator-ui-title'}">
|
Title="{Loc 'portable-generator-ui-title'}">
|
||||||
<BoxContainer Margin="4 0" Orientation="Horizontal">
|
<BoxContainer Margin="4 0" Orientation="Horizontal">
|
||||||
@@ -32,6 +32,11 @@
|
|||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<Label Name="OutputSwitchLabel" Text="{Loc 'portable-generator-ui-switch'}" Visible="False" />
|
<Label Name="OutputSwitchLabel" Text="{Loc 'portable-generator-ui-switch'}" Visible="False" />
|
||||||
<Button Name="OutputSwitchButton" Visible="False" />
|
<Button Name="OutputSwitchButton" Visible="False" />
|
||||||
|
<!-- Network stats menu -->
|
||||||
|
<Label Text="{Loc 'portable-generator-ui-network-stats'}"/>
|
||||||
|
<Control>
|
||||||
|
<Label Name="NetworkStats" />
|
||||||
|
</Control>
|
||||||
</GridContainer>
|
</GridContainer>
|
||||||
<Label Margin="2 0 0 0" Name="CloggedLabel" FontColorOverride="Red" Text="{Loc 'portable-generator-ui-clogged'}" />
|
<Label Margin="2 0 0 0" Name="CloggedLabel" FontColorOverride="Red" Text="{Loc 'portable-generator-ui-clogged'}" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -115,6 +115,22 @@ public sealed partial class GeneratorWindow : FancyWindow
|
|||||||
}
|
}
|
||||||
|
|
||||||
CloggedLabel.Visible = state.Clogged;
|
CloggedLabel.Visible = state.Clogged;
|
||||||
|
|
||||||
|
if (state.NetworkStats is { } netStats)
|
||||||
|
{
|
||||||
|
NetworkStats.Text = Loc.GetString(
|
||||||
|
"portable-generator-ui-network-stats-value",
|
||||||
|
("load", netStats.Load),
|
||||||
|
("supply", netStats.Supply));
|
||||||
|
|
||||||
|
var good = netStats.Load <= netStats.Supply;
|
||||||
|
NetworkStats.SetOnlyStyleClass(good ? "Good" : "Caution");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NetworkStats.Text = Loc.GetString("portable-generator-ui-network-stats-not-connected");
|
||||||
|
NetworkStats.StyleClasses.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryGetStartProgress(out float progress)
|
private bool TryGetStartProgress(out float progress)
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
using Content.Server.DoAfter;
|
using Content.Server.DoAfter;
|
||||||
|
using Content.Server.NodeContainer.NodeGroups;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
|
using Content.Server.Power.Components;
|
||||||
|
using Content.Server.Power.EntitySystems;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Power.Generator;
|
using Content.Shared.Power.Generator;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
@@ -24,6 +27,7 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem
|
|||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly GeneratorSystem _generator = default!;
|
[Dependency] private readonly GeneratorSystem _generator = default!;
|
||||||
[Dependency] private readonly PowerSwitchableSystem _switchable = default!;
|
[Dependency] private readonly PowerSwitchableSystem _switchable = default!;
|
||||||
|
[Dependency] private readonly PowerNetSystem _powerNet = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -31,6 +35,7 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem
|
|||||||
|
|
||||||
// Update UI after main system runs.
|
// Update UI after main system runs.
|
||||||
UpdatesAfter.Add(typeof(GeneratorSystem));
|
UpdatesAfter.Add(typeof(GeneratorSystem));
|
||||||
|
UpdatesAfter.Add(typeof(PowerNetSystem));
|
||||||
|
|
||||||
SubscribeLocalEvent<PortableGeneratorComponent, GetVerbsEvent<AlternativeVerb>>(GetAlternativeVerb);
|
SubscribeLocalEvent<PortableGeneratorComponent, GetVerbsEvent<AlternativeVerb>>(GetAlternativeVerb);
|
||||||
SubscribeLocalEvent<PortableGeneratorComponent, GeneratorStartedEvent>(GeneratorTugged);
|
SubscribeLocalEvent<PortableGeneratorComponent, GeneratorStartedEvent>(GeneratorTugged);
|
||||||
@@ -175,15 +180,19 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem
|
|||||||
|
|
||||||
public override void Update(float frameTime)
|
public override void Update(float frameTime)
|
||||||
{
|
{
|
||||||
var query = EntityQueryEnumerator<PortableGeneratorComponent, FuelGeneratorComponent, AppearanceComponent>();
|
var query = EntityQueryEnumerator<PortableGeneratorComponent, FuelGeneratorComponent, PowerSupplierComponent>();
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out var portGen, out var fuelGen, out var xform))
|
while (query.MoveNext(out var uid, out var portGen, out var fuelGen, out var powerSupplier))
|
||||||
{
|
{
|
||||||
UpdateUI(uid, portGen, fuelGen);
|
UpdateUI(uid, portGen, fuelGen, powerSupplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateUI(EntityUid uid, PortableGeneratorComponent comp, FuelGeneratorComponent fuelComp)
|
private void UpdateUI(
|
||||||
|
EntityUid uid,
|
||||||
|
PortableGeneratorComponent comp,
|
||||||
|
FuelGeneratorComponent fuelComp,
|
||||||
|
PowerSupplierComponent powerSupplier)
|
||||||
{
|
{
|
||||||
if (!_uiSystem.IsUiOpen(uid, GeneratorComponentUiKey.Key))
|
if (!_uiSystem.IsUiOpen(uid, GeneratorComponentUiKey.Key))
|
||||||
return;
|
return;
|
||||||
@@ -191,9 +200,13 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem
|
|||||||
var fuel = _generator.GetFuel(uid);
|
var fuel = _generator.GetFuel(uid);
|
||||||
var clogged = _generator.GetIsClogged(uid);
|
var clogged = _generator.GetIsClogged(uid);
|
||||||
|
|
||||||
|
(float, float)? networkStats = null;
|
||||||
|
if (powerSupplier.Net is { IsConnectedNetwork: true } net)
|
||||||
|
networkStats = (net.NetworkNode.LastCombinedLoad, net.NetworkNode.LastCombinedSupply);
|
||||||
|
|
||||||
_uiSystem.TrySetUiState(
|
_uiSystem.TrySetUiState(
|
||||||
uid,
|
uid,
|
||||||
GeneratorComponentUiKey.Key,
|
GeneratorComponentUiKey.Key,
|
||||||
new PortableGeneratorComponentBuiState(fuelComp, fuel, clogged));
|
new PortableGeneratorComponentBuiState(fuelComp, fuel, clogged, networkStats));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public abstract class BasePowerNet<TNetType> : BaseNetConnectorNodeGroup<TNetTyp
|
|||||||
PowerNetSystem = entMan.EntitySysManager.GetEntitySystem<PowerNetSystem>();
|
PowerNetSystem = entMan.EntitySysManager.GetEntitySystem<PowerNetSystem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsConnectedNetwork => NodeCount > 1;
|
||||||
|
|
||||||
public void AddConsumer(PowerConsumerComponent consumer)
|
public void AddConsumer(PowerConsumerComponent consumer)
|
||||||
{
|
{
|
||||||
DebugTools.Assert(consumer.NetworkLoad.LinkedNetwork == default);
|
DebugTools.Assert(consumer.NetworkLoad.LinkedNetwork == default);
|
||||||
|
|||||||
@@ -5,6 +5,16 @@ namespace Content.Server.Power.NodeGroups
|
|||||||
{
|
{
|
||||||
public interface IBasePowerNet
|
public interface IBasePowerNet
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates whether this network forms some form of connection (more than one node).
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Even "unconnected" power devices form a single-node power network all by themselves.
|
||||||
|
/// To players, this doesn't look like they're connected to anything.
|
||||||
|
/// This property accounts for this and forms a more intuitive check.
|
||||||
|
/// </remarks>
|
||||||
|
bool IsConnectedNetwork { get; }
|
||||||
|
|
||||||
void AddConsumer(PowerConsumerComponent consumer);
|
void AddConsumer(PowerConsumerComponent consumer);
|
||||||
|
|
||||||
void RemoveConsumer(PowerConsumerComponent consumer);
|
void RemoveConsumer(PowerConsumerComponent consumer);
|
||||||
|
|||||||
@@ -98,12 +98,17 @@ public sealed class PortableGeneratorComponentBuiState : BoundUserInterfaceState
|
|||||||
{
|
{
|
||||||
public float RemainingFuel;
|
public float RemainingFuel;
|
||||||
public bool Clogged;
|
public bool Clogged;
|
||||||
|
public (float Load, float Supply)? NetworkStats;
|
||||||
public float TargetPower;
|
public float TargetPower;
|
||||||
public float MaximumPower;
|
public float MaximumPower;
|
||||||
public float OptimalPower;
|
public float OptimalPower;
|
||||||
public bool On;
|
public bool On;
|
||||||
|
|
||||||
public PortableGeneratorComponentBuiState(FuelGeneratorComponent component, float remainingFuel, bool clogged)
|
public PortableGeneratorComponentBuiState(
|
||||||
|
FuelGeneratorComponent component,
|
||||||
|
float remainingFuel,
|
||||||
|
bool clogged,
|
||||||
|
(float Demand, float Supply)? networkStats)
|
||||||
{
|
{
|
||||||
RemainingFuel = remainingFuel;
|
RemainingFuel = remainingFuel;
|
||||||
Clogged = clogged;
|
Clogged = clogged;
|
||||||
@@ -111,6 +116,7 @@ public sealed class PortableGeneratorComponentBuiState : BoundUserInterfaceState
|
|||||||
MaximumPower = component.MaxTargetPower;
|
MaximumPower = component.MaxTargetPower;
|
||||||
OptimalPower = component.OptimalPower;
|
OptimalPower = component.OptimalPower;
|
||||||
On = component.On;
|
On = component.On;
|
||||||
|
NetworkStats = networkStats;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
### Special messages used by internal localizer stuff.
|
### Special messages used by internal localizer stuff.
|
||||||
|
|
||||||
# Used internally by the PRESSURE() function.
|
# Used internally by the PRESSURE() function.
|
||||||
zzzz-fmt-pressure = { TOSTRING($divided, "G4") } { $places ->
|
zzzz-fmt-pressure = { TOSTRING($divided, "F1") } { $places ->
|
||||||
[0] kPa
|
[0] kPa
|
||||||
[1] MPa
|
[1] MPa
|
||||||
[2] GPa
|
[2] GPa
|
||||||
@@ -11,7 +11,7 @@ zzzz-fmt-pressure = { TOSTRING($divided, "G4") } { $places ->
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Used internally by the POWERWATTS() function.
|
# Used internally by the POWERWATTS() function.
|
||||||
zzzz-fmt-power-watts = { TOSTRING($divided, "G4") } { $places ->
|
zzzz-fmt-power-watts = { TOSTRING($divided, "F1") } { $places ->
|
||||||
[0] W
|
[0] W
|
||||||
[1] kW
|
[1] kW
|
||||||
[2] MW
|
[2] MW
|
||||||
@@ -23,7 +23,7 @@ zzzz-fmt-power-watts = { TOSTRING($divided, "G4") } { $places ->
|
|||||||
# Used internally by the POWERJOULES() function.
|
# Used internally by the POWERJOULES() function.
|
||||||
# Reminder: 1 joule = 1 watt for 1 second (multiply watts by seconds to get joules).
|
# Reminder: 1 joule = 1 watt for 1 second (multiply watts by seconds to get joules).
|
||||||
# Therefore 1 kilowatt-hour is equal to 3,600,000 joules (3.6MJ)
|
# Therefore 1 kilowatt-hour is equal to 3,600,000 joules (3.6MJ)
|
||||||
zzzz-fmt-power-joules = { TOSTRING($divided, "G4") } { $places ->
|
zzzz-fmt-power-joules = { TOSTRING($divided, "F1") } { $places ->
|
||||||
[0] J
|
[0] J
|
||||||
[1] kJ
|
[1] kJ
|
||||||
[2] MJ
|
[2] MJ
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ portable-generator-ui-eject = Eject
|
|||||||
portable-generator-ui-eta = (~{ $minutes } min)
|
portable-generator-ui-eta = (~{ $minutes } min)
|
||||||
portable-generator-ui-unanchored = Unanchored
|
portable-generator-ui-unanchored = Unanchored
|
||||||
portable-generator-ui-current-output = Current output: {$voltage}
|
portable-generator-ui-current-output = Current output: {$voltage}
|
||||||
|
portable-generator-ui-network-stats = Network:
|
||||||
|
portable-generator-ui-network-stats-value = { POWERWATTS($supply) } / { POWERWATTS($load) }
|
||||||
|
portable-generator-ui-network-stats-not-connected = Not connected
|
||||||
|
|
||||||
power-switchable-generator-examine = The power output is set to {$voltage}.
|
power-switchable-generator-examine = The power output is set to {$voltage}.
|
||||||
power-switchable-generator-switched = Switched output to {$voltage}!
|
power-switchable-generator-switched = Switched output to {$voltage}!
|
||||||
|
|||||||
@@ -232,11 +232,11 @@
|
|||||||
name: J.R.P.A.C.M.A.N.-type portable generator
|
name: J.R.P.A.C.M.A.N.-type portable generator
|
||||||
description: |-
|
description: |-
|
||||||
A small generator capable of powering individual rooms, in case of emergencies.
|
A small generator capable of powering individual rooms, in case of emergencies.
|
||||||
Runs off welding fuel and is rated for up to 5 kW.
|
Runs off welding fuel and is rated for up to 8 kW.
|
||||||
Rated ages 3 and up.
|
Rated ages 3 and up.
|
||||||
parent: PortableGeneratorBase
|
parent: PortableGeneratorBase
|
||||||
id: PortableGeneratorJrPacman
|
id: PortableGeneratorJrPacman
|
||||||
suffix: Welding Fuel, 5 kW
|
suffix: Welding Fuel, 8 kW
|
||||||
components:
|
components:
|
||||||
- type: AmbientSound
|
- type: AmbientSound
|
||||||
range: 4
|
range: 4
|
||||||
@@ -276,10 +276,10 @@
|
|||||||
- type: Machine
|
- type: Machine
|
||||||
board: PortableGeneratorJrPacmanMachineCircuitboard
|
board: PortableGeneratorJrPacmanMachineCircuitboard
|
||||||
- type: FuelGenerator
|
- type: FuelGenerator
|
||||||
targetPower: 2000
|
targetPower: 5000
|
||||||
minTargetPower: 1000
|
minTargetPower: 4000
|
||||||
optimalPower: 5000
|
optimalPower: 8000
|
||||||
maxTargetPower: 5000
|
maxTargetPower: 8000
|
||||||
# 7.5 minutes at full tank.
|
# 7.5 minutes at full tank.
|
||||||
optimalBurnRate: 0.11111111
|
optimalBurnRate: 0.11111111
|
||||||
# Shallow curve that allows you to just barely eek out 12 minutes at lowest.
|
# Shallow curve that allows you to just barely eek out 12 minutes at lowest.
|
||||||
|
|||||||
Reference in New Issue
Block a user