diff --git a/Content.Client/GameObjects/Components/EmergencyLightComponent.cs b/Content.Client/GameObjects/Components/EmergencyLightComponent.cs
index 3bf8879d02..3d893332f1 100644
--- a/Content.Client/GameObjects/Components/EmergencyLightComponent.cs
+++ b/Content.Client/GameObjects/Components/EmergencyLightComponent.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Client.GameObjects.Components.Animations;
@@ -13,6 +13,7 @@ namespace Content.Client.GameObjects.Components
{
public override string Name => "EmergencyLight";
+ ///
protected override void Startup()
{
base.Startup();
diff --git a/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/EmergencyLightComponent.cs b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/EmergencyLightComponent.cs
new file mode 100644
index 0000000000..3fa04af25a
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Power/ApcNetComponents/PowerReceiverUsers/EmergencyLightComponent.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections.Generic;
+using Content.Shared.GameObjects.EntitySystems;
+using Robust.Server.GameObjects;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
+using Robust.Shared.Serialization;
+using Robust.Shared.Utility;
+using Robust.Shared.ViewVariables;
+
+namespace Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerReceiverUsers
+{
+ ///
+ /// Component that represents an emergency light, it has an internal battery that charges when the power is on.
+ ///
+ [RegisterComponent]
+ public class EmergencyLightComponent : Component, IExamine
+ {
+ public override string Name => "EmergencyLight";
+
+ [ViewVariables]
+ private EmergencyLightState _lightState = EmergencyLightState.Charging;
+
+ [ViewVariables]
+ private BatteryComponent Battery => Owner.GetComponent();
+ [ViewVariables]
+ private PointLightComponent Light => Owner.GetComponent();
+ [ViewVariables]
+ private PowerReceiverComponent PowerReceiver => Owner.GetComponent();
+ private SpriteComponent Sprite => Owner.GetComponent();
+
+ [ViewVariables(VVAccess.ReadWrite)]
+ private float _wattage;
+ [ViewVariables(VVAccess.ReadWrite)]
+ private float _chargingWattage;
+ [ViewVariables(VVAccess.ReadWrite)]
+ private float _chargingEfficiency;
+
+ public override void ExposeData(ObjectSerializer serializer)
+ {
+ base.ExposeData(serializer);
+ serializer.DataField(ref _wattage, "wattage", 5);
+ serializer.DataField(ref _chargingWattage, "chargingWattage", 60);
+ serializer.DataField(ref _chargingEfficiency, "chargingEfficiency", 0.85f);
+ }
+
+ ///
+ /// For attaching UpdateState() to events.
+ ///
+ public void UpdateState(object sender, EventArgs e)
+ {
+ UpdateState();
+ }
+
+ ///
+ /// Updates the light's power drain, battery drain, sprite and actual light state.
+ ///
+ public void UpdateState()
+ {
+ if (PowerReceiver.Powered)
+ {
+ PowerReceiver.Load = (int) Math.Abs(_wattage);
+ TurnOff();
+ _lightState = EmergencyLightState.Charging;
+ }
+ else
+ {
+ TurnOn();
+ _lightState = EmergencyLightState.On;
+ }
+ }
+
+ public void OnUpdate(float frameTime)
+ {
+ if (_lightState == EmergencyLightState.Empty
+ || _lightState == EmergencyLightState.Full) return;
+
+ if(_lightState == EmergencyLightState.On)
+ {
+ if (!Battery.TryUseCharge(_wattage * frameTime))
+ {
+ _lightState = EmergencyLightState.Empty;
+ TurnOff();
+ }
+ }
+ else
+ {
+ Battery.CurrentCharge += _chargingWattage * frameTime * _chargingEfficiency;
+ if (Battery.BatteryState == BatteryState.Full)
+ {
+ PowerReceiver.Load = 1;
+ _lightState = EmergencyLightState.Full;
+ }
+ }
+ }
+
+ private void TurnOff()
+ {
+ Sprite.LayerSetState(0, "emergency_light_off");
+ Light.Enabled = false;
+ }
+
+ private void TurnOn()
+ {
+ Sprite.LayerSetState(0, "emergency_light_on");
+ Light.Enabled = true;
+ }
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ Owner.GetComponent().OnPowerStateChanged += UpdateState;
+ }
+
+ public override void OnRemove()
+ {
+ Owner.GetComponent().OnPowerStateChanged -= UpdateState;
+ base.OnRemove();
+ }
+
+ void IExamine.Examine(FormattedMessage message, bool inDetailsRange)
+ {
+ message.AddMarkup(Loc.GetString($"The battery indicator displays: {BatteryStateText[_lightState]}."));
+ }
+
+ public enum EmergencyLightState
+ {
+ Charging,
+ Full,
+ Empty,
+ On
+ }
+
+ public Dictionary BatteryStateText = new Dictionary
+ {
+ { EmergencyLightState.Full, "[color=darkgreen]Full[/color]"},
+ { EmergencyLightState.Empty, "[color=darkred]Empty[/color]"},
+ { EmergencyLightState.Charging, "[color=darkorange]Charging[/color]"},
+ { EmergencyLightState.On, "[color=darkorange]Discharging[/color]"}
+ };
+ }
+}
diff --git a/Content.Server/GameObjects/EntitySystems/EmergencyLightSystem.cs b/Content.Server/GameObjects/EntitySystems/EmergencyLightSystem.cs
new file mode 100644
index 0000000000..59c83e724b
--- /dev/null
+++ b/Content.Server/GameObjects/EntitySystems/EmergencyLightSystem.cs
@@ -0,0 +1,18 @@
+using Content.Server.GameObjects.Components.Power.ApcNetComponents.PowerReceiverUsers;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects.Systems;
+
+namespace Content.Server.GameObjects.EntitySystems
+{
+ [UsedImplicitly]
+ internal sealed class EmergencyLightSystem : EntitySystem
+ {
+ public override void Update(float frameTime)
+ {
+ foreach (var comp in ComponentManager.EntityQuery())
+ {
+ comp.OnUpdate(frameTime);
+ }
+ }
+ }
+}
diff --git a/Content.Server/IgnoredComponents.cs b/Content.Server/IgnoredComponents.cs
index cd9713f35d..518d680cf7 100644
--- a/Content.Server/IgnoredComponents.cs
+++ b/Content.Server/IgnoredComponents.cs
@@ -17,7 +17,6 @@
"AnimationsTest",
"ItemStatus",
"Marker",
- "EmergencyLight",
"Clickable",
"RadiatingLight",
};
diff --git a/Resources/Prototypes/Entities/Constructible/Walls/emergency_light.yml b/Resources/Prototypes/Entities/Constructible/Walls/emergency_light.yml
index c3253d28d8..64a95e6bd5 100644
--- a/Resources/Prototypes/Entities/Constructible/Walls/emergency_light.yml
+++ b/Resources/Prototypes/Entities/Constructible/Walls/emergency_light.yml
@@ -1,17 +1,27 @@
-- type: entity
+- type: entity
id: EmergencyLight
name: "emergency light"
+ description: A small red light with an internal battery that turns on as soon as it stops receiving any power.
parent: WallLight
components:
- type: PointLight
+ enabled: false
radius: 10
energy: 2.5
offset: "0.5, 0"
color: "#FF4020"
mask: /Textures/emergency_mask.png
-
- type: EmergencyLight
-
+ - type: PowerReceiver
+ - type: Battery
+ maxCharge: 30000
+ startingCharge: 0
+ - type: Sprite
+ sprite: Constructible/Lighting/emergency_light.rsi
+ state: emergency_light_off
+ - type: Icon
+ sprite: Constructible/Lighting/emergency_light.rsi
+ state: emergency_light_off
placement:
snap:
- Wallmount
diff --git a/Resources/Textures/Constructible/Lighting/emergency_light.rsi/emergency_light_off.png b/Resources/Textures/Constructible/Lighting/emergency_light.rsi/emergency_light_off.png
new file mode 100644
index 0000000000..6427384c2f
Binary files /dev/null and b/Resources/Textures/Constructible/Lighting/emergency_light.rsi/emergency_light_off.png differ
diff --git a/Resources/Textures/Constructible/Lighting/emergency_light.rsi/emergency_light_on.png b/Resources/Textures/Constructible/Lighting/emergency_light.rsi/emergency_light_on.png
new file mode 100644
index 0000000000..364d44b505
Binary files /dev/null and b/Resources/Textures/Constructible/Lighting/emergency_light.rsi/emergency_light_on.png differ
diff --git a/Resources/Textures/Constructible/Lighting/emergency_light.rsi/meta.json b/Resources/Textures/Constructible/Lighting/emergency_light.rsi/meta.json
new file mode 100644
index 0000000000..5e722f0710
--- /dev/null
+++ b/Resources/Textures/Constructible/Lighting/emergency_light.rsi/meta.json
@@ -0,0 +1,66 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "license": "CC-BY-SA-3.0",
+ "states": [
+ {
+ "name": "emergency_light_off",
+ "directions": 4,
+ "delays": [
+ [
+ 1.0
+ ],
+ [
+ 1.0
+ ],
+ [
+ 1.0
+ ],
+ [
+ 1.0
+ ]
+ ]
+ },
+ {
+ "name": "emergency_light_on",
+ "directions": 4,
+ "delays": [
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ],
+ [
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3,
+ 0.3
+ ]
+ ]
+ }
+ ]
+}