diff --git a/Content.Client/Power/SMES/SmesComponent.cs b/Content.Client/Power/SMES/SmesComponent.cs
new file mode 100644
index 0000000000..155a40c8e2
--- /dev/null
+++ b/Content.Client/Power/SMES/SmesComponent.cs
@@ -0,0 +1,28 @@
+namespace Content.Client.Power.SMES;
+
+[RegisterComponent]
+public sealed class SmesComponent : Component
+{
+ ///
+ /// The prefix used for the RSI states of the sprite layers indicating the charge level of the SMES.
+ ///
+ [DataField("chargeOverlayPrefix")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public string ChargeOverlayPrefix = "smes-og";
+
+ ///
+ /// The prefix used for the RSI states of the sprite layers indicating the input state of the SMES.
+ /// Actually bundled together with the output indicator light.
+ ///
+ [DataField("inputOverlayPrefix")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public string InputOverlayPrefix = "smes-oc";
+
+ ///
+ /// The prefix used for the RSI states of the sprite layers indicating the output state of the SMES.
+ /// Actually bundled together with the input indicator light.
+ ///
+ [DataField("outputOverlayPrefix")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public string OutputOverlayPrefix = "smes-op";
+}
diff --git a/Content.Client/Power/SMES/SmesSystem.cs b/Content.Client/Power/SMES/SmesSystem.cs
new file mode 100644
index 0000000000..a555bedcac
--- /dev/null
+++ b/Content.Client/Power/SMES/SmesSystem.cs
@@ -0,0 +1,50 @@
+using Content.Shared.Power;
+using Content.Shared.SMES;
+using Robust.Client.GameObjects;
+
+namespace Content.Client.Power.SMES;
+
+public sealed class SmesVisualizerSystem : VisualizerSystem
+{
+ protected override void OnAppearanceChange(EntityUid uid, SmesComponent comp, ref AppearanceChangeEvent args)
+ {
+ if (args.Sprite == null)
+ return;
+
+ if (!AppearanceSystem.TryGetData(uid, SmesVisuals.LastChargeLevel, out var level, args.Component) || level == 0)
+ {
+ args.Sprite.LayerSetVisible(SmesVisualLayers.Charge, false);
+ }
+ else
+ {
+ args.Sprite.LayerSetVisible(SmesVisualLayers.Charge, true);
+ args.Sprite.LayerSetState(SmesVisualLayers.Charge, $"{comp.ChargeOverlayPrefix}{level}");
+ }
+
+ if (!AppearanceSystem.TryGetData(uid, SmesVisuals.LastChargeState, out var state, args.Component))
+ state = ChargeState.Still;
+
+ switch (state)
+ {
+ case ChargeState.Still:
+ args.Sprite.LayerSetState(SmesVisualLayers.Input, $"{comp.InputOverlayPrefix}0");
+ args.Sprite.LayerSetState(SmesVisualLayers.Output, $"{comp.OutputOverlayPrefix}1");
+ break;
+ case ChargeState.Charging:
+ args.Sprite.LayerSetState(SmesVisualLayers.Input, $"{comp.InputOverlayPrefix}1");
+ args.Sprite.LayerSetState(SmesVisualLayers.Output, $"{comp.OutputOverlayPrefix}1");
+ break;
+ case ChargeState.Discharging:
+ args.Sprite.LayerSetState(SmesVisualLayers.Input, $"{comp.InputOverlayPrefix}0");
+ args.Sprite.LayerSetState(SmesVisualLayers.Output, $"{comp.OutputOverlayPrefix}2");
+ break;
+ }
+ }
+}
+
+enum SmesVisualLayers : byte
+{
+ Input,
+ Charge,
+ Output,
+}
diff --git a/Content.Client/Power/SMES/SmesVisualizer.cs b/Content.Client/Power/SMES/SmesVisualizer.cs
deleted file mode 100644
index 7682671002..0000000000
--- a/Content.Client/Power/SMES/SmesVisualizer.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using Content.Shared.Power;
-using Content.Shared.SMES;
-using JetBrains.Annotations;
-using Robust.Client.GameObjects;
-using Robust.Shared.GameObjects;
-using Robust.Shared.IoC;
-
-namespace Content.Client.Power.SMES
-{
- [UsedImplicitly]
- public sealed class SmesVisualizer : AppearanceVisualizer
- {
- [Obsolete("Subscribe to your component being initialised instead.")]
- public override void InitializeEntity(EntityUid entity)
- {
- base.InitializeEntity(entity);
-
- var sprite = IoCManager.Resolve().GetComponent(entity);
-
- sprite.LayerMapSet(Layers.Input, sprite.AddLayerState("smes-oc0"));
- sprite.LayerSetShader(Layers.Input, "unshaded");
- sprite.LayerMapSet(Layers.Charge, sprite.AddLayerState("smes-og1"));
- sprite.LayerSetShader(Layers.Charge, "unshaded");
- sprite.LayerSetVisible(Layers.Charge, false);
- sprite.LayerMapSet(Layers.Output, sprite.AddLayerState("smes-op0"));
- sprite.LayerSetShader(Layers.Output, "unshaded");
- }
-
- [Obsolete("Subscribe to AppearanceChangeEvent instead.")]
- public override void OnChangeData(AppearanceComponent component)
- {
- base.OnChangeData(component);
-
- var sprite = IoCManager.Resolve().GetComponent(component.Owner);
- if (!component.TryGetData(SmesVisuals.LastChargeLevel, out var level) || level == 0)
- {
- sprite.LayerSetVisible(Layers.Charge, false);
- }
- else
- {
- sprite.LayerSetVisible(Layers.Charge, true);
- sprite.LayerSetState(Layers.Charge, $"smes-og{level}");
- }
-
- if (component.TryGetData(SmesVisuals.LastChargeState, out var state))
- {
- switch (state)
- {
- case ChargeState.Still:
- sprite.LayerSetState(Layers.Input, "smes-oc0");
- sprite.LayerSetState(Layers.Output, "smes-op1");
- break;
- case ChargeState.Charging:
- sprite.LayerSetState(Layers.Input, "smes-oc1");
- sprite.LayerSetState(Layers.Output, "smes-op1");
- break;
- case ChargeState.Discharging:
- sprite.LayerSetState(Layers.Input, "smes-oc0");
- sprite.LayerSetState(Layers.Output, "smes-op2");
- break;
- }
- }
- else
- {
- sprite.LayerSetState(Layers.Input, "smes-oc0");
- sprite.LayerSetState(Layers.Output, "smes-op1");
- }
- }
-
- enum Layers : byte
- {
- Input,
- Charge,
- Output,
- }
- }
-}
diff --git a/Content.Server/Power/SMES/SmesComponent.cs b/Content.Server/Power/SMES/SmesComponent.cs
index c812fc9836..29e1dbd7cb 100644
--- a/Content.Server/Power/SMES/SmesComponent.cs
+++ b/Content.Server/Power/SMES/SmesComponent.cs
@@ -1,16 +1,12 @@
using Content.Server.Power.Components;
using Content.Shared.Power;
-using Content.Shared.Rounding;
-using Content.Shared.SMES;
-using Robust.Server.GameObjects;
-using Robust.Shared.Timing;
namespace Content.Server.Power.SMES;
///
/// Handles the "user-facing" side of the actual SMES object.
/// This is operations that are specific to the SMES, like UI and visuals.
-/// Logic is handled in
+/// Logic is handled in
/// Code interfacing with the powernet is handled in and .
///
[RegisterComponent, Access(typeof(SmesSystem))]
@@ -26,4 +22,23 @@ public sealed class SmesComponent : Component
public TimeSpan LastChargeLevelTime;
[ViewVariables]
public TimeSpan VisualsChangeDelay = TimeSpan.FromSeconds(1);
+
+ ///
+ /// The number of distinct charge levels a SMES has.
+ /// 0 is empty max is full.
+ ///
+ [DataField("numChargeLevels")]
+ public int NumChargeLevels = 6;
+
+ ///
+ /// The charge level of the SMES as of the most recent update.
+ ///
+ [ViewVariables]
+ public int ChargeLevel = 0;
+
+ ///
+ /// Whether the SMES is being charged/discharged/neither.
+ ///
+ [ViewVariables]
+ public ChargeState ChargeState = ChargeState.Still;
}
diff --git a/Content.Server/Power/SMES/SmesSystem.cs b/Content.Server/Power/SMES/SmesSystem.cs
index e9a07fa03e..7da8eb0688 100644
--- a/Content.Server/Power/SMES/SmesSystem.cs
+++ b/Content.Server/Power/SMES/SmesSystem.cs
@@ -57,7 +57,7 @@ internal sealed class SmesSystem : EntitySystem
private int CalcChargeLevel(EntityUid uid, BatteryComponent? battery = null)
{
- if (!Resolve(uid, ref battery))
+ if (!Resolve(uid, ref battery))
return 0;
return ContentHelpers.RoundToLevels(battery.CurrentCharge, battery.MaxCharge, 6);
@@ -65,7 +65,7 @@ internal sealed class SmesSystem : EntitySystem
private ChargeState CalcChargeState(EntityUid uid, PowerNetworkBatteryComponent? netBattery = null)
{
- if (!Resolve(uid, ref netBattery))
+ if (!Resolve(uid, ref netBattery))
return ChargeState.Still;
return (netBattery.CurrentSupply - netBattery.CurrentReceiving) switch
diff --git a/Content.Shared/Power/SharedPower.cs b/Content.Shared/Power/SharedPower.cs
index 481dcf7dc9..5dd366fd68 100644
--- a/Content.Shared/Power/SharedPower.cs
+++ b/Content.Shared/Power/SharedPower.cs
@@ -3,11 +3,11 @@
namespace Content.Shared.Power
{
[Serializable, NetSerializable]
- public enum ChargeState
+ public enum ChargeState : byte
{
- Still,
- Charging,
- Discharging,
+ Still = 0,
+ Charging = 1,
+ Discharging = 2,
}
[Serializable, NetSerializable]
diff --git a/Content.Shared/SMES/SharedSmesComponent.cs b/Content.Shared/SMES/SharedSmesComponent.cs
index 720e346a79..3fe9dd8f5f 100644
--- a/Content.Shared/SMES/SharedSmesComponent.cs
+++ b/Content.Shared/SMES/SharedSmesComponent.cs
@@ -1,11 +1,10 @@
using Robust.Shared.Serialization;
-namespace Content.Shared.SMES
+namespace Content.Shared.SMES;
+
+[Serializable, NetSerializable]
+public enum SmesVisuals
{
- [Serializable, NetSerializable]
- public enum SmesVisuals
- {
- LastChargeState,
- LastChargeLevel,
- }
+ LastChargeState,
+ LastChargeLevel,
}
diff --git a/Resources/Prototypes/Entities/Structures/Power/smes.yml b/Resources/Prototypes/Entities/Structures/Power/smes.yml
index 54f9270fd7..9b934dea02 100644
--- a/Resources/Prototypes/Entities/Structures/Power/smes.yml
+++ b/Resources/Prototypes/Entities/Structures/Power/smes.yml
@@ -19,13 +19,21 @@
snapCardinals: true
layers:
- state: smes
+ - map: ["enum.SmesVisualLayers.Charge"]
+ state: "smes-og1" # -og0 does not exist
+ shader: unshaded
+ visible: false
+ - map: ["enum.SmesVisualLayers.Input"]
+ state: "smes-oc0"
+ shader: unshaded
+ - map: ["enum.SmesVisualLayers.Output"]
+ state: "smes-op1"
+ shader: unshaded
- type: Smes
- type: UpgradeBattery
maxChargeMultiplier: 2
baseMaxCharge: 8000000
- type: Appearance
- visuals:
- - type: SmesVisualizer
- type: Battery
startingCharge: 0
- type: ExaminableBattery