diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj
index e53fbe21b1..dd5acffae4 100644
--- a/Content.Client/Content.Client.csproj
+++ b/Content.Client/Content.Client.csproj
@@ -72,6 +72,7 @@
+
diff --git a/Content.Client/GameObjects/Components/Power/PowerCellVisualizer2D.cs b/Content.Client/GameObjects/Components/Power/PowerCellVisualizer2D.cs
new file mode 100644
index 0000000000..c2d4769143
--- /dev/null
+++ b/Content.Client/GameObjects/Components/Power/PowerCellVisualizer2D.cs
@@ -0,0 +1,48 @@
+using Content.Shared.GameObjects.Components.Power;
+using Content.Shared.Utility;
+using SS14.Client.GameObjects;
+using SS14.Client.Interfaces.GameObjects.Components;
+using SS14.Shared.Interfaces.GameObjects;
+using SS14.Shared.Utility;
+using YamlDotNet.RepresentationModel;
+
+namespace Content.Client.GameObjects.Components.Power
+{
+ public class PowerCellVisualizer2D : AppearanceVisualizer
+ {
+ private string _prefix;
+
+ public override void LoadData(YamlMappingNode node)
+ {
+ base.LoadData(node);
+
+ _prefix = node.GetNode("prefix").AsString();
+ }
+
+ public override void InitializeEntity(IEntity entity)
+ {
+ base.InitializeEntity(entity);
+
+ var sprite = entity.GetComponent();
+
+ sprite.LayerMapSet(Layers.Charge, sprite.AddLayerState($"{_prefix}_100"));
+ sprite.LayerSetShader(Layers.Charge, "unshaded");
+ }
+
+ public override void OnChangeData(AppearanceComponent component)
+ {
+ base.OnChangeData(component);
+
+ var sprite = component.Owner.GetComponent();
+ if (component.TryGetData(PowerCellVisuals.ChargeLevel, out float fraction))
+ {
+ sprite.LayerSetState(Layers.Charge, $"{_prefix}_{ContentHelpers.RoundToLevels(fraction, 1, 5) * 25}");
+ }
+ }
+
+ private enum Layers
+ {
+ Charge
+ }
+ }
+}
diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj
index 8da4a3565c..5635a0e5ee 100644
--- a/Content.Server/Content.Server.csproj
+++ b/Content.Server/Content.Server.csproj
@@ -80,12 +80,14 @@
+
+
diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs
index 974015ee5e..757e709fb0 100644
--- a/Content.Server/EntryPoint.cs
+++ b/Content.Server/EntryPoint.cs
@@ -86,7 +86,10 @@ namespace Content.Server
factory.Register();
factory.RegisterReference();
factory.Register();
- factory.Register();
+ factory.Register();
+ factory.RegisterReference();
+ factory.Register();
+ factory.RegisterReference();
factory.Register();
factory.Register();
diff --git a/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs
new file mode 100644
index 0000000000..ae53d48de9
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Power/PowerCellComponent.cs
@@ -0,0 +1,48 @@
+using Content.Shared.GameObjects.Components.Power;
+using SS14.Server.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Power
+{
+ public class PowerCellComponent : PowerStorageComponent
+ {
+ public override string Name => "PowerCell";
+
+ private AppearanceComponent _appearance;
+
+ public override float Charge
+ {
+ get => base.Charge;
+ set
+ {
+ base.Charge = value;
+ _updateAppearance();
+ }
+ }
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ Owner.TryGetComponent(out _appearance);
+ }
+
+ public override void DeductCharge(float toDeduct)
+ {
+ base.DeductCharge(toDeduct);
+
+ _updateAppearance();
+ }
+
+ public override void AddCharge(float charge)
+ {
+ base.AddCharge(charge);
+
+ _updateAppearance();
+ }
+
+ private void _updateAppearance()
+ {
+ _appearance?.SetData(PowerCellVisuals.ChargeLevel, Charge / Capacity);
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs b/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
index 2b3f238c5c..ea6f70a78a 100644
--- a/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
@@ -75,7 +75,7 @@ namespace Content.Server.GameObjects.Components.Power
}
}
- if (attacked.TryGetComponent(out var storage))
+ if (attacked.TryGetComponent(out var storage))
{
var stateSeconds = (DateTime.Now - storage.LastChargeStateChange).TotalSeconds;
builder.AppendFormat(@"Power Storage:
diff --git a/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs b/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
index 0880c9cdc5..d108a76cea 100644
--- a/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
@@ -11,12 +11,11 @@ using YamlDotNet.RepresentationModel;
namespace Content.Server.GameObjects.Components.Power
{
///
- /// Feeds energy from the powernet and may have the ability to supply back into it
+ /// Stores electrical energy. Used by power cells and SMESes.
///
- public class PowerStorageComponent : Component
+ public abstract class PowerStorageComponent : Component
{
- public override string Name => "PowerStorage";
-
+ [ViewVariables]
public ChargeState LastChargeState { get; private set; } = ChargeState.Still;
public DateTime LastChargeStateChange { get; private set; }
@@ -31,9 +30,15 @@ namespace Content.Server.GameObjects.Components.Power
///
/// Energy the battery is currently storing.
/// In Joules.
+ /// In most cases you should use and to modify this.
///
- [ViewVariables]
- public float Charge => _charge;
+ [ViewVariables(VVAccess.ReadWrite)]
+ public virtual float Charge
+ {
+ get => _charge;
+ set => _charge = value;
+ }
+
private float _charge = 0;
///
@@ -55,26 +60,6 @@ namespace Content.Server.GameObjects.Components.Power
[ViewVariables]
public bool Full => Charge >= Capacity;
- private bool _chargepowernet = false;
-
- ///
- /// Do we distribute power into the powernet from our stores if the powernet requires it?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public bool ChargePowernet
- {
- get => _chargepowernet;
- set
- {
- _chargepowernet = value;
- if (Owner.TryGetComponent(out PowerNodeComponent node))
- {
- if (node.Parent != null)
- node.Parent.UpdateStorageType(this);
- }
- }
- }
-
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
@@ -83,46 +68,14 @@ namespace Content.Server.GameObjects.Components.Power
serializer.DataField(ref _charge, "charge", 0);
serializer.DataField(ref _chargeRate, "chargerate", 1000);
serializer.DataField(ref _distributionRate, "distributionrate", 1000);
- serializer.DataField(ref _chargepowernet, "chargepowernet", false);
- }
-
- public override void OnAdd()
- {
- base.OnAdd();
-
- if (!Owner.TryGetComponent(out PowerNodeComponent node))
- {
- Owner.AddComponent();
- node = Owner.GetComponent();
- }
- node.OnPowernetConnect += PowernetConnect;
- node.OnPowernetDisconnect += PowernetDisconnect;
- node.OnPowernetRegenerate += PowernetRegenerate;
- }
-
- public override void OnRemove()
- {
- if (Owner.TryGetComponent(out PowerNodeComponent node))
- {
- if (node.Parent != null)
- {
- node.Parent.RemovePowerStorage(this);
- }
-
- node.OnPowernetConnect -= PowernetConnect;
- node.OnPowernetDisconnect -= PowernetDisconnect;
- node.OnPowernetRegenerate -= PowernetRegenerate;
- }
-
- base.OnRemove();
}
///
/// Checks if the storage can supply the amount of charge directly requested
///
- public bool CanDeductCharge(float todeduct)
+ public bool CanDeductCharge(float toDeduct)
{
- if (Charge > todeduct)
+ if (Charge > toDeduct)
return true;
return false;
}
@@ -130,14 +83,14 @@ namespace Content.Server.GameObjects.Components.Power
///
/// Deducts the requested charge from the energy storage
///
- public void DeductCharge(float todeduct)
+ public virtual void DeductCharge(float toDeduct)
{
- _charge = Math.Max(0, Charge - todeduct);
+ _charge = Math.Max(0, Charge - toDeduct);
LastChargeState = ChargeState.Discharging;
LastChargeStateChange = DateTime.Now;
}
- public void AddCharge(float charge)
+ public virtual void AddCharge(float charge)
{
_charge = Math.Min(Capacity, Charge + charge);
LastChargeState = ChargeState.Charging;
@@ -160,6 +113,24 @@ namespace Content.Server.GameObjects.Components.Power
return Math.Min(DistributionRate * frameTime, Charge);
}
+ ///
+ /// Tries to deduct a wattage over a certain amount of time.
+ ///
+ /// The wattage of the power drain.
+ /// The amount of time in this "frame".
+ /// True if the amount of energy was deducted, false.
+ public bool TryDeductWattage(float wattage, float frameTime)
+ {
+ var avail = AvailableCharge(frameTime);
+ if (avail < wattage * frameTime)
+ {
+ return false;
+ }
+
+ DeductCharge(wattage * frameTime);
+ return true;
+ }
+
public ChargeState GetChargeState()
{
return GetChargeState(TimeSpan.FromSeconds(1));
@@ -182,35 +153,5 @@ namespace Content.Server.GameObjects.Components.Power
}
AddCharge(RequestCharge(frameTime));
}
-
- ///
- /// Node has become anchored to a powernet
- ///
- ///
- ///
- private void PowernetConnect(object sender, PowernetEventArgs eventarg)
- {
- eventarg.Powernet.AddPowerStorage(this);
- }
-
- ///
- /// Node has had its powernet regenerated
- ///
- ///
- ///
- private void PowernetRegenerate(object sender, PowernetEventArgs eventarg)
- {
- eventarg.Powernet.AddPowerStorage(this);
- }
-
- ///
- /// Node has become unanchored from a powernet
- ///
- ///
- ///
- private void PowernetDisconnect(object sender, PowernetEventArgs eventarg)
- {
- eventarg.Powernet.RemovePowerStorage(this);
- }
}
}
diff --git a/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs b/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs
new file mode 100644
index 0000000000..bb28c110db
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Power/PowerStorageNetComponent.cs
@@ -0,0 +1,100 @@
+using SS14.Shared.Serialization;
+using SS14.Shared.ViewVariables;
+
+namespace Content.Server.GameObjects.Components.Power
+{
+ ///
+ /// Feeds energy from the powernet and may have the ability to supply back into it
+ ///
+ public class PowerStorageNetComponent : PowerStorageComponent
+ {
+ public override string Name => "PowerStorage";
+
+ private bool _chargePowernet = false;
+
+ ///
+ /// Do we distribute power into the powernet from our stores if the powernet requires it?
+ ///
+ [ViewVariables(VVAccess.ReadWrite)]
+ public bool ChargePowernet
+ {
+ get => _chargePowernet;
+ set
+ {
+ _chargePowernet = value;
+ if (Owner.TryGetComponent(out PowerNodeComponent node))
+ {
+ node.Parent?.UpdateStorageType(this);
+ }
+ }
+ }
+
+ public override void ExposeData(ObjectSerializer serializer)
+ {
+ base.ExposeData(serializer);
+
+ serializer.DataField(ref _chargePowernet, "chargepowernet", false);
+ }
+
+ public override void OnAdd()
+ {
+ base.OnAdd();
+
+ if (!Owner.TryGetComponent(out PowerNodeComponent node))
+ {
+ Owner.AddComponent();
+ node = Owner.GetComponent();
+ }
+ node.OnPowernetConnect += PowernetConnect;
+ node.OnPowernetDisconnect += PowernetDisconnect;
+ node.OnPowernetRegenerate += PowernetRegenerate;
+ }
+
+ public override void OnRemove()
+ {
+ if (Owner.TryGetComponent(out PowerNodeComponent node))
+ {
+ if (node.Parent != null)
+ {
+ node.Parent.RemovePowerStorage(this);
+ }
+
+ node.OnPowernetConnect -= PowernetConnect;
+ node.OnPowernetDisconnect -= PowernetDisconnect;
+ node.OnPowernetRegenerate -= PowernetRegenerate;
+ }
+
+ base.OnRemove();
+ }
+
+ ///
+ /// Node has become anchored to a powernet
+ ///
+ ///
+ ///
+ private void PowernetConnect(object sender, PowernetEventArgs eventarg)
+ {
+ eventarg.Powernet.AddPowerStorage(this);
+ }
+
+ ///
+ /// Node has had its powernet regenerated
+ ///
+ ///
+ ///
+ private void PowernetRegenerate(object sender, PowernetEventArgs eventarg)
+ {
+ eventarg.Powernet.AddPowerStorage(this);
+ }
+
+ ///
+ /// Node has become unanchored from a powernet
+ ///
+ ///
+ ///
+ private void PowernetDisconnect(object sender, PowernetEventArgs eventarg)
+ {
+ eventarg.Powernet.RemovePowerStorage(this);
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Power/Powernet.cs b/Content.Server/GameObjects/Components/Power/Powernet.cs
index 2e8796181d..d30a266418 100644
--- a/Content.Server/GameObjects/Components/Power/Powernet.cs
+++ b/Content.Server/GameObjects/Components/Power/Powernet.cs
@@ -63,7 +63,7 @@ namespace Content.Server.GameObjects.Components.Power
///
/// A list of the energy storage components that will feed the powernet if necessary, and if there is enough power feed itself
///
- private readonly List PowerStorageSupplierList = new List();
+ private readonly List PowerStorageSupplierList = new List();
[ViewVariables]
public int PowerStorageSupplierCount => PowerStorageSupplierList.Count;
@@ -71,7 +71,7 @@ namespace Content.Server.GameObjects.Components.Power
///
/// A list of energy storage components that will never feed the powernet, will try to draw energy to feed themselves if possible
///
- private readonly List PowerStorageConsumerList = new List();
+ private readonly List PowerStorageConsumerList = new List();
[ViewVariables]
public int PowerStorageConsumerCount => PowerStorageConsumerList.Count;
@@ -473,7 +473,7 @@ namespace Content.Server.GameObjects.Components.Power
///
/// Register a power supply from a generator connected to the powernet
///
- public void AddPowerStorage(PowerStorageComponent storage)
+ public void AddPowerStorage(PowerStorageNetComponent storage)
{
if (storage.ChargePowernet)
PowerStorageSupplierList.Add(storage);
@@ -482,7 +482,7 @@ namespace Content.Server.GameObjects.Components.Power
}
//How do I even call this? TODO: fix
- public void UpdateStorageType(PowerStorageComponent storage)
+ public void UpdateStorageType(PowerStorageNetComponent storage)
{
//If our chargepowernet settings change we need to tell the powernet of this new setting and remove traces of our old setting
if (PowerStorageSupplierList.Contains(storage))
@@ -500,7 +500,7 @@ namespace Content.Server.GameObjects.Components.Power
///
/// Remove a power supply from a generator connected to the powernet
///
- public void RemovePowerStorage(PowerStorageComponent storage)
+ public void RemovePowerStorage(PowerStorageNetComponent storage)
{
if (PowerStorageSupplierList.Contains(storage))
{
diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj
index 2601de9536..3de89ebeb9 100644
--- a/Content.Shared/Content.Shared.csproj
+++ b/Content.Shared/Content.Shared.csproj
@@ -67,6 +67,7 @@
+
diff --git a/Content.Shared/GameObjects/Components/Power/SharedPowerCellComponent.cs b/Content.Shared/GameObjects/Components/Power/SharedPowerCellComponent.cs
new file mode 100644
index 0000000000..ed5f81469b
--- /dev/null
+++ b/Content.Shared/GameObjects/Components/Power/SharedPowerCellComponent.cs
@@ -0,0 +1,11 @@
+using System;
+using SS14.Shared.Serialization;
+
+namespace Content.Shared.GameObjects.Components.Power
+{
+ [Serializable, NetSerializable]
+ public enum PowerCellVisuals
+ {
+ ChargeLevel
+ }
+}
diff --git a/Resources/Prototypes/Entities/powercells.yml b/Resources/Prototypes/Entities/powercells.yml
new file mode 100644
index 0000000000..7e50d9e86e
--- /dev/null
+++ b/Resources/Prototypes/Entities/powercells.yml
@@ -0,0 +1,94 @@
+- type: entity
+ id: PowerCellSmallBase
+ abstract: true
+ parent: BaseItem
+ components:
+ - type: BoundingBox
+ aabb: -0.15,-0.3,0.2,0.3
+ - type: PowerCell
+ - type: Appearance
+ - type: Sprite
+ netsync: false
+
+- type: entity
+ name: Small Standard Power Cell
+ id: PowerCellSmallStandard
+ parent: PowerCellSmallBase
+ components:
+ - type: Sprite
+ sprite: Objects/PowerCells/power_cell_small_st.rsi
+ layers:
+ - state: s_st
+ - type: Icon
+ sprite: Objects/PowerCells/power_cell_small_st.rsi
+ state: s_st
+ - type: PowerCell
+ capacity: 1500
+ charge: 1500
+ - type: Appearance
+ visuals:
+ - type: PowerCellVisualizer2D
+ prefix: s_st
+
+
+- type: entity
+ name: Small High-Capacity Power Cell
+ id: PowerCellSmallHigh
+ parent: PowerCellSmallBase
+ components:
+ - type: Sprite
+ sprite: Objects/PowerCells/power_cell_small_hi.rsi
+ layers:
+ - state: s_hi
+ - type: Icon
+ sprite: Objects/PowerCells/power_cell_small_hi.rsi
+ state: s_hi
+ - type: PowerCell
+ capacity: 3000
+ charge: 3000
+ - type: Appearance
+ visuals:
+ - type: PowerCellVisualizer2D
+ prefix: s_hi
+
+
+- type: entity
+ name: Small Super-Capacity Power Cell
+ id: PowerCellSmallSuper
+ parent: PowerCellSmallBase
+ components:
+ - type: Sprite
+ sprite: Objects/PowerCells/power_cell_small_sup.rsi
+ layers:
+ - state: s_sup
+ - type: Icon
+ sprite: Objects/PowerCells/power_cell_small_sup.rsi
+ state: s_sup
+ - type: PowerCell
+ capacity: 6000
+ charge: 6000
+ - type: Appearance
+ visuals:
+ - type: PowerCellVisualizer2D
+ prefix: s_sup
+
+
+- type: entity
+ name: Small Hyper-Capacity Power Cell
+ id: PowerCellSmallHyper
+ parent: PowerCellSmallBase
+ components:
+ - type: Sprite
+ sprite: Objects/PowerCells/power_cell_small_hy.rsi
+ layers:
+ - state: s_hy
+ - type: Icon
+ sprite: Objects/PowerCells/power_cell_small_hy.rsi
+ state: s_hy
+ - type: PowerCell
+ capacity: 10000
+ charge: 10000
+ - type: Appearance
+ visuals:
+ - type: PowerCellVisualizer2D
+ prefix: s_hy