diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj
index 2a68133adb..812596a735 100644
--- a/Content.Client/Content.Client.csproj
+++ b/Content.Client/Content.Client.csproj
@@ -108,5 +108,7 @@
+
+
-
+
\ No newline at end of file
diff --git a/Content.Client/GameObjects/Components/Power/ApcVisualizer2D.cs b/Content.Client/GameObjects/Components/Power/ApcVisualizer2D.cs
new file mode 100644
index 0000000000..ee46cc84cb
--- /dev/null
+++ b/Content.Client/GameObjects/Components/Power/ApcVisualizer2D.cs
@@ -0,0 +1,67 @@
+using Content.Shared.GameObjects.Components.Power;
+using SS14.Client.GameObjects;
+using SS14.Client.Interfaces.GameObjects.Components;
+using SS14.Shared.Interfaces.GameObjects;
+
+namespace Content.Client.GameObjects.Components.Power
+{
+ public class ApcVisualizer2D : AppearanceVisualizer
+ {
+ public override void InitializeEntity(IEntity entity)
+ {
+ base.InitializeEntity(entity);
+
+ var sprite = entity.GetComponent();
+
+ sprite.LayerMapSet(Layers.ChargeState, sprite.AddLayerState("apco3-0"));
+ sprite.LayerSetShader(Layers.ChargeState, "unshaded");
+
+ sprite.LayerMapSet(Layers.Lock, sprite.AddLayerState("apcox-0"));
+ sprite.LayerSetShader(Layers.Lock, "unshaded");
+
+ sprite.LayerMapSet(Layers.Equipment, sprite.AddLayerState("apco0-3"));
+ sprite.LayerSetShader(Layers.Equipment, "unshaded");
+
+ sprite.LayerMapSet(Layers.Lighting, sprite.AddLayerState("apco1-3"));
+ sprite.LayerSetShader(Layers.Lighting, "unshaded");
+
+ sprite.LayerMapSet(Layers.Environment, sprite.AddLayerState("apco2-3"));
+ sprite.LayerSetShader(Layers.Environment, "unshaded");
+ }
+
+ public override void OnChangeData(AppearanceComponent component)
+ {
+ base.OnChangeData(component);
+
+ var sprite = component.Owner.GetComponent();
+ if (component.TryGetData(ApcVisuals.ChargeState, out var state))
+ {
+ switch (state)
+ {
+ case ApcChargeState.Lack:
+ sprite.LayerSetState(Layers.ChargeState, "apco3-0");
+ break;
+ case ApcChargeState.Charging:
+ sprite.LayerSetState(Layers.ChargeState, "apco3-1");
+ break;
+ case ApcChargeState.Full:
+ sprite.LayerSetState(Layers.ChargeState, "apco3-2");
+ break;
+ }
+ }
+ else
+ {
+ sprite.LayerSetState(Layers.ChargeState, "apco3-0");
+ }
+ }
+
+ enum Layers
+ {
+ ChargeState,
+ Lock,
+ Equipment,
+ Lighting,
+ Environment,
+ }
+ }
+}
diff --git a/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs b/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs
index 3f57dee966..6ecbb050e5 100644
--- a/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs
+++ b/Content.Client/GameObjects/Components/Power/PowerDebugTool.cs
@@ -10,6 +10,7 @@ namespace Content.Client.GameObjects.Components.Power
{
public class PowerDebugTool : SharedPowerDebugTool
{
+ SS14Window LastWindow;
public override void HandleMessage(ComponentMessage message, INetChannel netChannel = null, IComponent component = null)
{
base.HandleMessage(message, netChannel, component);
@@ -17,13 +18,17 @@ namespace Content.Client.GameObjects.Components.Power
switch (message)
{
case OpenDataWindowMsg msg:
- var window = new SS14Window
+ if (LastWindow != null && !LastWindow.Disposed)
{
- Title = "Power Debug Tool"
+ LastWindow.Dispose();
+ }
+ LastWindow = new SS14Window
+ {
+ Title = "Power Debug Tool",
};
- window.Contents.AddChild(new Label() { Text = msg.Data });
- window.AddToScreen();
- window.Open();
+ LastWindow.Contents.AddChild(new Label() { Text = msg.Data });
+ LastWindow.AddToScreen();
+ LastWindow.Open();
break;
}
}
diff --git a/Content.Client/GameObjects/Components/Power/SMESVisualizer2D.cs b/Content.Client/GameObjects/Components/Power/SMESVisualizer2D.cs
new file mode 100644
index 0000000000..5631f3f0ec
--- /dev/null
+++ b/Content.Client/GameObjects/Components/Power/SMESVisualizer2D.cs
@@ -0,0 +1,77 @@
+using Content.Shared.GameObjects.Components.Power;
+using SS14.Client.GameObjects;
+using SS14.Client.Interfaces.GameObjects.Components;
+using SS14.Shared.Interfaces.GameObjects;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Content.Client.GameObjects.Components.Power
+{
+ public class SmesVisualizer2D : AppearanceVisualizer
+ {
+ public override void InitializeEntity(IEntity entity)
+ {
+ base.InitializeEntity(entity);
+
+ var sprite = entity.GetComponent();
+
+ 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");
+ }
+
+ public override void OnChangeData(AppearanceComponent component)
+ {
+ base.OnChangeData(component);
+
+ var sprite = component.Owner.GetComponent();
+ 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
+ {
+ Input,
+ Charge,
+ Output,
+ }
+ }
+}
diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj
index b229998a91..36c090ce24 100644
--- a/Content.Server/Content.Server.csproj
+++ b/Content.Server/Content.Server.csproj
@@ -140,5 +140,7 @@
+
+
-
+
\ No newline at end of file
diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs
index 5d519681ac..84ac78490a 100644
--- a/Content.Server/EntryPoint.cs
+++ b/Content.Server/EntryPoint.cs
@@ -91,6 +91,8 @@ namespace Content.Server
factory.Register();
factory.Register();
+ factory.Register();
+ factory.Register();
}
///
diff --git a/Content.Server/GameObjects/Components/Power/ApcComponent.cs b/Content.Server/GameObjects/Components/Power/ApcComponent.cs
new file mode 100644
index 0000000000..605e7abd78
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Power/ApcComponent.cs
@@ -0,0 +1,50 @@
+using Content.Shared.GameObjects.Components.Power;
+using SS14.Server.GameObjects;
+using SS14.Shared.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Power
+{
+ public class ApcComponent : Component
+ {
+ public override string Name => "Apc";
+
+ PowerStorageComponent Storage;
+ AppearanceComponent Appearance;
+
+ ApcChargeState LastChargeState;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ Storage = Owner.GetComponent();
+ Appearance = Owner.GetComponent();
+ }
+
+ public override void Update(float frameTime)
+ {
+ var newState = CalcChargeState();
+ if (newState != LastChargeState)
+ {
+ LastChargeState = newState;
+ Appearance.SetData(ApcVisuals.ChargeState, newState);
+ }
+ }
+
+ ApcChargeState CalcChargeState()
+ {
+ var storageCharge = Storage.GetChargeState();
+ if (storageCharge == ChargeState.Discharging)
+ {
+ return ApcChargeState.Lack;
+ }
+
+ if (storageCharge == ChargeState.Charging)
+ {
+ return ApcChargeState.Charging;
+ }
+
+ // Still.
+ return Storage.Full ? ApcChargeState.Full : ApcChargeState.Lack;
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs b/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
index 56ad6ae66c..ce951a6cbe 100644
--- a/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerDebugTool.cs
@@ -1,3 +1,4 @@
+using System;
using System.Text;
using Content.Server.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Power;
@@ -61,9 +62,11 @@ namespace Content.Server.GameObjects.Components.Power
if (attacked.TryGetComponent(out var storage))
{
+ var stateSeconds = (DateTime.Now - storage.LastChargeStateChange).TotalSeconds;
builder.AppendFormat(@"Power Storage:
Capacity: {0}, Charge: {1}, ChargeRate: {2}, DistributionRate: {3}, ChargePowernet: {4}
-", storage.Capacity, storage.Charge, storage.ChargeRate, storage.DistributionRate, storage.ChargePowernet);
+ LastChargeState: {5} ({6}), LastChargeStateChange: {7:0.00} seconds ago.
+", storage.Capacity, storage.Charge, storage.ChargeRate, storage.DistributionRate, storage.ChargePowernet, storage.LastChargeState, storage.GetChargeState(), stateSeconds);
}
if (attacked.TryGetComponent(out var transfer))
diff --git a/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs b/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
index 413f7066ba..993924d492 100644
--- a/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
+++ b/Content.Server/GameObjects/Components/Power/PowerStorageComponent.cs
@@ -1,4 +1,5 @@
-using SS14.Shared.GameObjects;
+using Content.Shared.GameObjects.Components.Power;
+using SS14.Shared.GameObjects;
using SS14.Shared.Interfaces.GameObjects;
using SS14.Shared.IoC;
using SS14.Shared.Utility;
@@ -14,6 +15,9 @@ namespace Content.Server.GameObjects.Components.Power
{
public override string Name => "PowerStorage";
+ public ChargeState LastChargeState { get; private set; } = ChargeState.Still;
+ public DateTime LastChargeStateChange { get; private set; }
+
///
/// Maximum amount of energy the internal battery can store.
/// In Joules.
@@ -38,6 +42,8 @@ namespace Content.Server.GameObjects.Components.Power
///
public float DistributionRate { get; private set; } = 1000;
+ public bool Full => Charge >= Capacity;
+
private bool _chargepowernet = false;
///
@@ -129,15 +135,19 @@ namespace Content.Server.GameObjects.Components.Power
public void DeductCharge(float todeduct)
{
Charge = Math.Max(0, Charge - todeduct);
+ LastChargeState = ChargeState.Discharging;
+ LastChargeStateChange = DateTime.Now;
}
public void AddCharge(float charge)
{
Charge = Math.Min(Capacity, Charge + charge);
+ LastChargeState = ChargeState.Charging;
+ LastChargeStateChange = DateTime.Now;
}
///
- /// Returns the charge available from the energy storage
+ /// Returns the amount of energy that can be taken in by this storage in the specified amount of time.
///
public float RequestCharge(float frameTime)
{
@@ -145,15 +155,33 @@ namespace Content.Server.GameObjects.Components.Power
}
///
- /// Returns the charge available from the energy storage
+ /// Returns the amount of energy available for discharge in the specified amount of time.
///
public float AvailableCharge(float frameTime)
{
return Math.Min(DistributionRate * frameTime, Charge);
}
+ public ChargeState GetChargeState()
+ {
+ return GetChargeState(TimeSpan.FromSeconds(1));
+ }
+
+ public ChargeState GetChargeState(TimeSpan timeout)
+ {
+ if (LastChargeStateChange + timeout > DateTime.Now)
+ {
+ return LastChargeState;
+ }
+ return ChargeState.Still;
+ }
+
public void ChargePowerTick(float frameTime)
{
+ if (Full)
+ {
+ return;
+ }
AddCharge(RequestCharge(frameTime));
}
diff --git a/Content.Server/GameObjects/Components/Power/Powernet.cs b/Content.Server/GameObjects/Components/Power/Powernet.cs
index 7f3bf5d312..2750d4d751 100644
--- a/Content.Server/GameObjects/Components/Power/Powernet.cs
+++ b/Content.Server/GameObjects/Components/Power/Powernet.cs
@@ -145,6 +145,10 @@ namespace Content.Server.GameObjects.Components.Power
break;
}
var demand = consumer.RequestCharge(frameTime);
+ if (demand == 0)
+ {
+ continue;
+ }
var taken = Math.Min(demand, totalRemaining);
totalRemaining -= taken;
consumer.AddCharge(taken);
@@ -155,6 +159,10 @@ namespace Content.Server.GameObjects.Components.Power
foreach (var supplier in PowerStorageSupplierList)
{
var load = supplier.AvailableCharge(frameTime);
+ if (load == 0)
+ {
+ continue;
+ }
var added = Math.Min(load, supplierUsed);
supplierUsed -= added;
supplier.DeductCharge(added);
diff --git a/Content.Server/GameObjects/Components/Power/SMESComponent.cs b/Content.Server/GameObjects/Components/Power/SMESComponent.cs
new file mode 100644
index 0000000000..fdfb23701d
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Power/SMESComponent.cs
@@ -0,0 +1,53 @@
+using System;
+using Content.Shared.GameObjects.Components.Power;
+using Content.Shared.Utility;
+using SS14.Server.GameObjects;
+using SS14.Shared.GameObjects;
+
+namespace Content.Server.GameObjects.Components.Power
+{
+ ///
+ /// Handles the "user-facing" side of the actual SMES object.
+ /// This is operations that are specific to the SMES, like UI and visuals.
+ /// Code interfacing with the powernet is handled in .
+ ///
+ public class SmesComponent : Component
+ {
+ public override string Name => "Smes";
+
+ PowerStorageComponent Storage;
+ AppearanceComponent Appearance;
+
+ int LastChargeLevel = 0;
+ ChargeState LastChargeState;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ Storage = Owner.GetComponent();
+ Appearance = Owner.GetComponent();
+ }
+
+ public override void Update(float frameTime)
+ {
+ var newLevel = CalcChargeLevel();
+ if (newLevel != LastChargeLevel)
+ {
+ LastChargeLevel = newLevel;
+ Appearance.SetData(SmesVisuals.LastChargeLevel, newLevel);
+ }
+
+ var newState = Storage.GetChargeState();
+ if (newState != LastChargeState)
+ {
+ LastChargeState = newState;
+ Appearance.SetData(SmesVisuals.LastChargeState, newState);
+ }
+ }
+
+ int CalcChargeLevel()
+ {
+ return ContentHelpers.RoundToLevels(Storage.Charge, Storage.Capacity, 6);
+ }
+ }
+}
diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj
index 70e509dc1e..db0b641216 100644
--- a/Content.Shared/Content.Shared.csproj
+++ b/Content.Shared/Content.Shared.csproj
@@ -67,6 +67,7 @@
+
@@ -100,6 +101,9 @@
+
+
+
-
+
\ No newline at end of file
diff --git a/Content.Shared/GameObjects/Components/Power/PowerShared.cs b/Content.Shared/GameObjects/Components/Power/PowerShared.cs
new file mode 100644
index 0000000000..abe8f3e8f1
--- /dev/null
+++ b/Content.Shared/GameObjects/Components/Power/PowerShared.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using SS14.Shared.Serialization;
+
+namespace Content.Shared.GameObjects.Components.Power
+{
+ [Serializable, NetSerializable]
+ public enum ChargeState
+ {
+ Still,
+ Charging,
+ Discharging,
+ }
+}
diff --git a/Content.Shared/GameObjects/Components/Power/SharedApcComponent.cs b/Content.Shared/GameObjects/Components/Power/SharedApcComponent.cs
new file mode 100644
index 0000000000..5ff2c23114
--- /dev/null
+++ b/Content.Shared/GameObjects/Components/Power/SharedApcComponent.cs
@@ -0,0 +1,30 @@
+using System;
+using SS14.Shared.Serialization;
+
+namespace Content.Shared.GameObjects.Components.Power
+{
+ [Serializable, NetSerializable]
+ public enum ApcVisuals
+ {
+ ChargeState
+ }
+
+ [Serializable, NetSerializable]
+ public enum ApcChargeState
+ {
+ ///
+ /// APC does not have enough power to charge cell (if necessary) and keep powering the area.
+ ///
+ Lack,
+
+ ///
+ /// APC is not full but has enough power.
+ ///
+ Charging,
+
+ ///
+ /// APC battery is full and has enough power.
+ ///
+ Full,
+ }
+}
diff --git a/Content.Shared/GameObjects/Components/Power/SharedSMESComponent.cs b/Content.Shared/GameObjects/Components/Power/SharedSMESComponent.cs
new file mode 100644
index 0000000000..90ae68d11f
--- /dev/null
+++ b/Content.Shared/GameObjects/Components/Power/SharedSMESComponent.cs
@@ -0,0 +1,16 @@
+using SS14.Shared.Serialization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Content.Shared.GameObjects.Components.Power
+{
+ [Serializable, NetSerializable]
+ public enum SmesVisuals
+ {
+ LastChargeState,
+ LastChargeLevel,
+ }
+}
diff --git a/Content.Shared/Utility/ContentHelpers.cs b/Content.Shared/Utility/ContentHelpers.cs
new file mode 100644
index 0000000000..7b1682e0ee
--- /dev/null
+++ b/Content.Shared/Utility/ContentHelpers.cs
@@ -0,0 +1,60 @@
+using System;
+
+namespace Content.Shared.Utility
+{
+ public static class ContentHelpers
+ {
+ ///
+ /// Assigns the value going from 0 to
+ /// such that it is divided into a set of (amount ) "levels".
+ /// Rounding is performed to the "middle" so that the highest and lowest levels are only assigned
+ /// if is exactly or 0.
+ ///
+ ///
+ /// Say you have a progress bar going from 0 -> 100 inclusive and you want to map this to 6 sprite states (0, 4 intermediates and full).
+ /// This method allows you to easily map this progress bar to the sprite states.
+ ///
+ /// The amount of levels to subdivide into.
+ /// An integer from 0 to -1.
+ ///
+ /// Thrown if levels is less than 1.
+ ///
+ public static int RoundToLevels(double actual, double max, int levels)
+ {
+ if (levels <= 0)
+ {
+ throw new ArgumentException("Levels must be greater than 0.", nameof(levels));
+ }
+ if (actual >= max)
+ {
+ return levels - 1;
+ }
+ if (actual <= 0)
+ {
+ return 0;
+ }
+ var toOne = actual / max;
+ double threshold;
+ if (levels % 2 == 0)
+ {
+ // Basically, if we have an even count of levels, there's no exact "mid point".
+ // Thus, I nominate the first one below the 50% mark.
+ threshold = ((levels / 2f) - 1) / (levels - 1);
+ }
+ else
+ {
+ threshold = 0.5f;
+ }
+
+ var preround = toOne * (levels - 1);
+ if (toOne <= threshold)
+ {
+ return (int)Math.Ceiling(preround);
+ }
+ else
+ {
+ return (int)Math.Floor(preround);
+ }
+ }
+ }
+}
diff --git a/Content.Tests/Content.Tests.csproj b/Content.Tests/Content.Tests.csproj
new file mode 100644
index 0000000000..de55f6ca39
--- /dev/null
+++ b/Content.Tests/Content.Tests.csproj
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+ Debug
+ AnyCPU
+ {8EDF4429-251A-416D-BB68-93F227191BCF}
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ Library
+ Properties
+ Content.Tests
+ Content.Tests
+ v4.5.1
+ 512
+ UnitTest
+ ..\bin\Content.Tests\
+
+
+ true
+ full
+ false
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ TRACE
+ prompt
+ 4
+
+
+ true
+ DEBUG;TRACE
+ full
+ x64
+ prompt
+
+
+ TRACE
+ true
+ pdbonly
+ x64
+ prompt
+
+
+ true
+ DEBUG;TRACE
+ full
+ x86
+ prompt
+
+
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+
+
+
+ $(SolutionDir)packages\NUnit.3.10.1\lib\net45\nunit.framework.dll
+
+
+ $(SolutionDir)packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {a2e5f175-78af-4ddd-8f97-e2d2552372ed}
+ Content.Client
+
+
+ {b38dbbd0-04c2-4d1a-84e2-b3446f6adf2a}
+ Content.Server
+
+
+ {26aeebb3-dde7-443a-9f43-7bc7f4acf6b5}
+ Content.Shared
+
+
+ {59250baf-0000-0000-0000-000000000000}
+ Lidgren.Network
+
+
+ {8af31169-49b1-4a12-b8f4-2a0674a9e7cb}
+ SS14.Client.Godot
+
+
+ {83429bd6-6358-4b18-be51-401df8ea2673}
+ SS14.Client
+
+
+ {b04aae71-0000-0000-0000-000000000000}
+ SS14.Server
+
+
+ {0529f740-0000-0000-0000-000000000000}
+ SS14.Shared
+
+
+ {f0ada779-40b8-4f7e-ba6c-cdb19f3065d9}
+ SS14.UnitTesting
+
+
+
+
+
diff --git a/Content.Tests/Properties/AssemblyInfo.cs b/Content.Tests/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..9b98942957
--- /dev/null
+++ b/Content.Tests/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Content.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("nunit.tests")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Content.Tests/Shared/Utility/ContentHelpers_Test.cs b/Content.Tests/Shared/Utility/ContentHelpers_Test.cs
new file mode 100644
index 0000000000..961accd5b6
--- /dev/null
+++ b/Content.Tests/Shared/Utility/ContentHelpers_Test.cs
@@ -0,0 +1,60 @@
+using Content.Shared.Utility;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Content.Tests.Shared.Utility
+{
+ [Parallelizable]
+ [TestFixture]
+ [TestOf(typeof(ContentHelpers))]
+ public class ContentHelpers_Test
+ {
+
+ public static readonly IEnumerable<(double val, double max, int levels, int expected)> TestData = new(double, double, int, int)[]
+ {
+ // Testing odd level counts. These are easy.
+ (-1, 10, 5, 0),
+ ( 0, 10, 5, 0),
+ ( 0.01f, 10, 5, 1),
+ ( 1, 10, 5, 1),
+ ( 2, 10, 5, 1),
+ ( 2.5f, 10, 5, 1),
+ ( 2.51f, 10, 5, 2),
+ ( 3, 10, 5, 2),
+ ( 4, 10, 5, 2),
+ ( 5, 10, 5, 2),
+ ( 6, 10, 5, 2),
+ ( 7, 10, 5, 2),
+ ( 7.49f, 10, 5, 2),
+ ( 7.5f, 10, 5, 3),
+ ( 8, 10, 5, 3),
+ ( 9, 10, 5, 3),
+ (10, 10, 5, 4),
+ (11, 10, 5, 4),
+
+ // Even level counts though..
+ ( 1, 10, 6, 1),
+ ( 2, 10, 6, 1),
+ ( 3, 10, 6, 2),
+ ( 4, 10, 6, 2),
+ ( 5, 10, 6, 2),
+ ( 6, 10, 6, 3),
+ ( 7, 10, 6, 3),
+ ( 8, 10, 6, 4),
+ ( 9, 10, 6, 4),
+ (10, 10, 6, 5),
+ };
+
+ [Parallelizable]
+ [Test]
+ public void Test([ValueSource(nameof(TestData))] (double val, double max, int levels, int expected) data)
+ {
+ (double val, double max, int levels, int expected) = data;
+ Assert.That(ContentHelpers.RoundToLevels(val, max, levels), Is.EqualTo(expected));
+ }
+ }
+}
diff --git a/Content.Tests/packages.config b/Content.Tests/packages.config
new file mode 100644
index 0000000000..268222d562
--- /dev/null
+++ b/Content.Tests/packages.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Resources/Maps/stationstation.yml b/Resources/Maps/stationstation.yml
index f4278807dd..5703ba3869 100644
--- a/Resources/Maps/stationstation.yml
+++ b/Resources/Maps/stationstation.yml
@@ -1745,6 +1745,8 @@
- &1206253354
type: &1921049841 PowerStorage
- type: PowerNode
+ - type: Smes
+ - type: Appearance
- type: entity
id: SMES
name: SMES
@@ -1760,6 +1762,8 @@
- type: Sprite
- type: PowerStorage
- type: PowerNode
+ - type: Smes
+ - type: Appearance
- type: entity
id: &400177229 BlueWire
name: BlueWire
@@ -2236,8 +2240,8 @@
- type: PowerDevice
- type: PoweredLight
- type: entity
- id: &692485458 WPP
- name: WPP
+ id: &692485458 APC
+ name: APC
components:
- type: PowerStorage
- type: PowerNode
@@ -2251,9 +2255,11 @@
- type: Sprite
- &1938028994
type: &323998104 PowerProvider
+ - type: Apc
+ - type: Appearance
- type: entity
- id: WPP
- name: WPP
+ id: APC
+ name: APC
components:
- type: PowerStorage
- type: PowerNode
@@ -2266,6 +2272,8 @@
- type: BoundingBox
- type: Sprite
- type: PowerProvider
+ - type: Apc
+ - type: Appearance
- type: entity
id: Wire
name: Wire
@@ -2369,8 +2377,8 @@
- type: PowerDevice
- type: PoweredLight
- type: entity
- id: WPP
- name: WPP
+ id: APC
+ name: APC
components:
- type: PowerStorage
- type: PowerNode
@@ -2382,6 +2390,8 @@
- type: BoundingBox
- type: Sprite
- type: PowerProvider
+ - type: Apc
+ - type: Appearance
- type: entity
id: Wire
name: Wire
@@ -2396,8 +2406,8 @@
color: '#FF0000FF'
- type: PowerTransfer
- type: entity
- id: WPP
- name: WPP
+ id: APC
+ name: APC
components:
- type: PowerStorage
- type: PowerNode
@@ -2409,6 +2419,8 @@
- type: BoundingBox
- type: Sprite
- type: PowerProvider
+ - type: Apc
+ - type: Appearance
- type: entity
id: Wire
name: Wire
@@ -2649,8 +2661,8 @@
color: '#FF0000FF'
- type: PowerTransfer
- type: entity
- id: WPP
- name: WPP
+ id: APC
+ name: APC
components:
- type: PowerStorage
- type: PowerNode
@@ -2663,9 +2675,11 @@
- type: BoundingBox
- type: Sprite
- type: PowerProvider
+ - type: Apc
+ - type: Appearance
- type: entity
- id: WPP
- name: WPP
+ id: APC
+ name: APC
components:
- type: PowerStorage
- type: PowerNode
@@ -2678,6 +2692,8 @@
- type: BoundingBox
- type: Sprite
- type: PowerProvider
+ - type: Apc
+ - type: Appearance
- type: entity
id: Wire
name: Wire
diff --git a/Resources/Prototypes/Entities/Power.yml b/Resources/Prototypes/Entities/Power.yml
index f300647612..8cd150abe5 100644
--- a/Resources/Prototypes/Entities/Power.yml
+++ b/Resources/Prototypes/Entities/Power.yml
@@ -70,25 +70,49 @@
chargerate: 200
chargepowernet: false
+- type: entity
+ parent: WPP
+ id: APC
+ name: APC
+ components:
+ - type: Apc
+ - type: Sprite
+ netsync: false
+ texture: ""
+ sprite: "Buildings/apc.rsi"
+ state: apc0
+ - type: Appearance
+ visuals:
+ - type: ApcVisualizer2D
- type: entity
id: SMES
- name: SMES
- description: Stores power in its supermagnetic cells
+ name: Smes
+ description: Stores power in its super-magnetic cells
components:
- type: Transform
- type: Clickable
- type: BoundingBox
- type: Sprite
- texture: Objects/storage.png
+ netsync: false
+ sprite: Buildings/smes.rsi
+ state: smes
+ layers:
+ - state: smes-display
+ shader: unshaded
- type: Icon
- texture: Objects/storage.png
+ sprite: Buildings/smes.rsi
+ state: smes
- type: PowerStorage
capacity: 3000
charge: 1000
chargerate: 200
distributionrate: 400
chargepowernet: true
+ - type: Smes
+ - type: Appearance
+ visuals:
+ - type: SmesVisualizer2D
- type: entity
id: WiredMachine
diff --git a/Resources/Textures/Buildings/apc.rsi/apc-b.png b/Resources/Textures/Buildings/apc.rsi/apc-b.png
new file mode 100644
index 0000000000..925f8c5ffc
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc-b.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apc-spark.png b/Resources/Textures/Buildings/apc.rsi/apc-spark.png
new file mode 100644
index 0000000000..67437b67d0
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc-spark.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apc0.png b/Resources/Textures/Buildings/apc.rsi/apc0.png
new file mode 100644
index 0000000000..7079bad29a
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc0.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apc1-b-nocover.png b/Resources/Textures/Buildings/apc.rsi/apc1-b-nocover.png
new file mode 100644
index 0000000000..996a618f3a
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc1-b-nocover.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apc1-nocover.png b/Resources/Textures/Buildings/apc.rsi/apc1-nocover.png
new file mode 100644
index 0000000000..6e42c824b1
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc1-nocover.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apc1.png b/Resources/Textures/Buildings/apc.rsi/apc1.png
new file mode 100644
index 0000000000..233f75c36c
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc1.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apc2-b-nocover.png b/Resources/Textures/Buildings/apc.rsi/apc2-b-nocover.png
new file mode 100644
index 0000000000..c218a439e9
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc2-b-nocover.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apc2-nocover.png b/Resources/Textures/Buildings/apc.rsi/apc2-nocover.png
new file mode 100644
index 0000000000..0dc5cda211
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc2-nocover.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apc2.png b/Resources/Textures/Buildings/apc.rsi/apc2.png
new file mode 100644
index 0000000000..d273c1926f
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apc2.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apcemag.png b/Resources/Textures/Buildings/apc.rsi/apcemag.png
new file mode 100644
index 0000000000..86b58be5fb
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apcemag.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apcewires.png b/Resources/Textures/Buildings/apc.rsi/apcewires.png
new file mode 100644
index 0000000000..9370aaf7d4
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apcewires.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apcmaint.png b/Resources/Textures/Buildings/apc.rsi/apcmaint.png
new file mode 100644
index 0000000000..41ef7add2a
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apcmaint.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco0-0.png b/Resources/Textures/Buildings/apc.rsi/apco0-0.png
new file mode 100644
index 0000000000..ac4581febb
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco0-0.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco0-1.png b/Resources/Textures/Buildings/apc.rsi/apco0-1.png
new file mode 100644
index 0000000000..4519f53653
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco0-1.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco0-2.png b/Resources/Textures/Buildings/apc.rsi/apco0-2.png
new file mode 100644
index 0000000000..355a76f926
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco0-2.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco0-3.png b/Resources/Textures/Buildings/apc.rsi/apco0-3.png
new file mode 100644
index 0000000000..27c2a87efd
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco0-3.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco1-0.png b/Resources/Textures/Buildings/apc.rsi/apco1-0.png
new file mode 100644
index 0000000000..c66bfa90d9
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco1-0.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco1-1.png b/Resources/Textures/Buildings/apc.rsi/apco1-1.png
new file mode 100644
index 0000000000..365fef1fe6
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco1-1.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco1-2.png b/Resources/Textures/Buildings/apc.rsi/apco1-2.png
new file mode 100644
index 0000000000..dd28cce545
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco1-2.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco1-3.png b/Resources/Textures/Buildings/apc.rsi/apco1-3.png
new file mode 100644
index 0000000000..a696818ec1
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco1-3.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco2-0.png b/Resources/Textures/Buildings/apc.rsi/apco2-0.png
new file mode 100644
index 0000000000..7359d44fb0
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco2-0.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco2-1.png b/Resources/Textures/Buildings/apc.rsi/apco2-1.png
new file mode 100644
index 0000000000..ccf7139dfb
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco2-1.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco2-2.png b/Resources/Textures/Buildings/apc.rsi/apco2-2.png
new file mode 100644
index 0000000000..1623be3521
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco2-2.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco2-3.png b/Resources/Textures/Buildings/apc.rsi/apco2-3.png
new file mode 100644
index 0000000000..0b5501318c
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco2-3.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco3-0.png b/Resources/Textures/Buildings/apc.rsi/apco3-0.png
new file mode 100644
index 0000000000..9df197cce3
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco3-0.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco3-1.png b/Resources/Textures/Buildings/apc.rsi/apco3-1.png
new file mode 100644
index 0000000000..5a09344a3e
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco3-1.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apco3-2.png b/Resources/Textures/Buildings/apc.rsi/apco3-2.png
new file mode 100644
index 0000000000..89c3087474
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apco3-2.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apcox-0.png b/Resources/Textures/Buildings/apc.rsi/apcox-0.png
new file mode 100644
index 0000000000..e1e3843852
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apcox-0.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/apcox-1.png b/Resources/Textures/Buildings/apc.rsi/apcox-1.png
new file mode 100644
index 0000000000..25e86bb9b3
Binary files /dev/null and b/Resources/Textures/Buildings/apc.rsi/apcox-1.png differ
diff --git a/Resources/Textures/Buildings/apc.rsi/meta.json b/Resources/Textures/Buildings/apc.rsi/meta.json
new file mode 100644
index 0000000000..9ecb0668ac
--- /dev/null
+++ b/Resources/Textures/Buildings/apc.rsi/meta.json
@@ -0,0 +1,344 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/d1e0161af146835f4fb79d21a6200caa9cc842d0/icons/obj/power.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "apc-b",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apc-spark",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1
+ ]
+ ]
+ },
+ {
+ "name": "apc0",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apc1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apc1-b-nocover",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apc1-nocover",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apc2",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apc2-b-nocover",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apc2-nocover",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apcemag",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 0.5,
+ 0.5
+ ]
+ ]
+ },
+ {
+ "name": "apcewires",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apcmaint",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco0-0",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco0-1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco0-2",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco0-3",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco1-0",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco1-1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco1-2",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco1-3",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco2-0",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco2-1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco2-2",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco2-3",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apco3-0",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0,
+ 2.0
+ ]
+ ]
+ },
+ {
+ "name": "apco3-1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "apco3-2",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0,
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apcox-0",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "apcox-1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ }
+ ]
+}
diff --git a/Resources/Textures/Buildings/smes.rsi/meta.json b/Resources/Textures/Buildings/smes.rsi/meta.json
new file mode 100644
index 0000000000..d196ff85b0
--- /dev/null
+++ b/Resources/Textures/Buildings/smes.rsi/meta.json
@@ -0,0 +1,170 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/d1e0161af146835f4fb79d21a6200caa9cc842d0/icons/obj/power.dmi and modified.",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "smes",
+ "select": [],
+ "flags": {},
+ "directions": 1
+ },
+ {
+ "name": "smes-display",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "smes-crit",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 0.2,
+ 0.2,
+ 0.2,
+ 0.2
+ ]
+ ]
+ },
+ {
+ "name": "smes-oc0",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "smes-oc1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 0.5,
+ 0.5
+ ]
+ ]
+ },
+ {
+ "name": "smes-oc2",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 0.5,
+ 0.5
+ ]
+ ]
+ },
+ {
+ "name": "smes-og1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "smes-og2",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "smes-og3",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "smes-og4",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "smes-og5",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "smes-op0",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "smes-op1",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0,
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "smes-op2",
+ "select": [],
+ "flags": {},
+ "directions": 1,
+ "delays": [
+ [
+ 1.0
+ ]
+ ]
+ }
+ ]
+}
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-crit.png b/Resources/Textures/Buildings/smes.rsi/smes-crit.png
new file mode 100644
index 0000000000..644ab351f1
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-crit.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-display.png b/Resources/Textures/Buildings/smes.rsi/smes-display.png
new file mode 100644
index 0000000000..8681ed776d
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-display.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-oc0.png b/Resources/Textures/Buildings/smes.rsi/smes-oc0.png
new file mode 100644
index 0000000000..2a8a9cb961
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-oc0.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-oc1.png b/Resources/Textures/Buildings/smes.rsi/smes-oc1.png
new file mode 100644
index 0000000000..66095d016b
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-oc1.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-oc2.png b/Resources/Textures/Buildings/smes.rsi/smes-oc2.png
new file mode 100644
index 0000000000..2b39f4a827
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-oc2.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-og1.png b/Resources/Textures/Buildings/smes.rsi/smes-og1.png
new file mode 100644
index 0000000000..741ed22138
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-og1.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-og2.png b/Resources/Textures/Buildings/smes.rsi/smes-og2.png
new file mode 100644
index 0000000000..0db9f1a6ef
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-og2.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-og3.png b/Resources/Textures/Buildings/smes.rsi/smes-og3.png
new file mode 100644
index 0000000000..30ea3f0722
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-og3.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-og4.png b/Resources/Textures/Buildings/smes.rsi/smes-og4.png
new file mode 100644
index 0000000000..6ea122e0f4
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-og4.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-og5.png b/Resources/Textures/Buildings/smes.rsi/smes-og5.png
new file mode 100644
index 0000000000..63579e63ab
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-og5.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-op0.png b/Resources/Textures/Buildings/smes.rsi/smes-op0.png
new file mode 100644
index 0000000000..7a6e915b53
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-op0.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-op1.png b/Resources/Textures/Buildings/smes.rsi/smes-op1.png
new file mode 100644
index 0000000000..b98f33d5c6
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-op1.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes-op2.png b/Resources/Textures/Buildings/smes.rsi/smes-op2.png
new file mode 100644
index 0000000000..55ce2f53f5
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes-op2.png differ
diff --git a/Resources/Textures/Buildings/smes.rsi/smes.png b/Resources/Textures/Buildings/smes.rsi/smes.png
new file mode 100644
index 0000000000..0689af2401
Binary files /dev/null and b/Resources/Textures/Buildings/smes.rsi/smes.png differ
diff --git a/SpaceStation14Content.sln b/SpaceStation14Content.sln
index 11505fd242..ce4927a3f6 100644
--- a/SpaceStation14Content.sln
+++ b/SpaceStation14Content.sln
@@ -40,6 +40,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SS14.Client", "engine\SS14.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SS14.Client.Godot", "engine\SS14.Client.Godot\SS14.Client.Godot.csproj", "{8AF31169-49B1-4A12-B8F4-2A0674A9E7CB}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.Tests", "Content.Tests\Content.Tests.csproj", "{8EDF4429-251A-416D-BB68-93F227191BCF}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -233,6 +235,24 @@ Global
{8AF31169-49B1-4A12-B8F4-2A0674A9E7CB}.Tools|x64.Build.0 = Tools|Any CPU
{8AF31169-49B1-4A12-B8F4-2A0674A9E7CB}.Tools|x86.ActiveCfg = Tools|Any CPU
{8AF31169-49B1-4A12-B8F4-2A0674A9E7CB}.Tools|x86.Build.0 = Tools|Any CPU
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Debug|x64.ActiveCfg = Debug|x64
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Debug|x64.Build.0 = Debug|x64
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Debug|x86.ActiveCfg = Debug|x86
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Debug|x86.Build.0 = Debug|x86
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Release|x64.ActiveCfg = Release|x64
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Release|x64.Build.0 = Release|x64
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Release|x86.ActiveCfg = Release|x86
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Release|x86.Build.0 = Release|x86
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Tools|Any CPU.ActiveCfg = Debug|Any CPU
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Tools|Any CPU.Build.0 = Debug|Any CPU
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Tools|x64.ActiveCfg = Debug|x64
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Tools|x64.Build.0 = Debug|x64
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Tools|x86.ActiveCfg = Debug|x86
+ {8EDF4429-251A-416D-BB68-93F227191BCF}.Tools|x86.Build.0 = Debug|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/engine b/engine
index f6d01c5d61..92f12334b4 160000
--- a/engine
+++ b/engine
@@ -1 +1 @@
-Subproject commit f6d01c5d61993c5befae181383102160f3fef9ab
+Subproject commit 92f12334b4ed55f63b65e347b7ffb7625fdbe032