diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs index bac13274ea..01ea48c4cc 100644 --- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs +++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs @@ -4,6 +4,7 @@ using Content.Server.DeviceNetwork.Systems; using Content.Server.Ghost; using Content.Server.Light.Components; using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; using Content.Server.Temperature.Components; using Content.Shared.Audio; using Content.Shared.Damage; @@ -42,6 +43,7 @@ namespace Content.Server.Light.EntitySystems [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly PowerReceiverSystem _power = default!; private static readonly TimeSpan ThunkDelay = TimeSpan.FromSeconds(2); public const string LightBulbContainer = "light_bulb"; @@ -241,6 +243,14 @@ namespace Content.Server.Light.EntitySystems } #endregion + /// + /// Supply factor (0-1) as input x, returns linear light scale (0-1). + /// + private float LightCurve(float x) + { + return (float)(1/0.8*(x-0.2)); + } + private void UpdateLight(EntityUid uid, PoweredLightComponent? light = null, ApcPowerReceiverComponent? powerReceiver = null, @@ -265,9 +275,10 @@ namespace Content.Server.Light.EntitySystems switch (lightBulb.State) { case LightBulbState.Normal: - if (powerReceiver.Powered && light.On) + float factor = LightCurve(_power.SupplyFactor(uid, powerReceiver)); + if (factor > 0 && light.On) { - SetLight(uid, true, lightBulb.Color, light, lightBulb.LightRadius, lightBulb.LightEnergy, lightBulb.LightSoftness); + SetLight(uid, true, lightBulb.Color, light, lightBulb.LightRadius*factor, lightBulb.LightEnergy*factor, lightBulb.LightSoftness); _appearance.SetData(uid, PoweredLightVisuals.BulbState, PoweredLightState.On, appearance); var time = _gameTiming.CurTime; if (time > light.LastThunk + ThunkDelay) diff --git a/Content.Server/Power/Components/ApcPowerReceiverComponent.cs b/Content.Server/Power/Components/ApcPowerReceiverComponent.cs index ae4d739430..e224e86153 100644 --- a/Content.Server/Power/Components/ApcPowerReceiverComponent.cs +++ b/Content.Server/Power/Components/ApcPowerReceiverComponent.cs @@ -51,6 +51,7 @@ namespace Content.Server.Power.Components } public bool? PoweredLastUpdate; + public float LastPowerReceived; [ViewVariables] public PowerState.Load NetworkLoad { get; } = new PowerState.Load diff --git a/Content.Server/Power/EntitySystems/PowerNetSystem.cs b/Content.Server/Power/EntitySystems/PowerNetSystem.cs index b457a321a1..6b196cf45d 100644 --- a/Content.Server/Power/EntitySystems/PowerNetSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerNetSystem.cs @@ -297,13 +297,14 @@ namespace Content.Server.Power.EntitySystems while (enumerator.MoveNext(out var uid, out var apcReceiver)) { var powered = apcReceiver.Powered; - if (powered == apcReceiver.PoweredLastUpdate) + if (apcReceiver.LastPowerReceived == apcReceiver.NetworkLoad.ReceivingPower) continue; if (metaQuery.GetComponent(uid).EntityPaused) continue; apcReceiver.PoweredLastUpdate = powered; + apcReceiver.LastPowerReceived = apcReceiver.NetworkLoad.ReceivingPower; var ev = new PowerChangedEvent(apcReceiver.Powered, apcReceiver.NetworkLoad.ReceivingPower); RaiseLocalEvent(apcReceiver.Owner, ref ev); diff --git a/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs b/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs index 35412d1742..1e70b7ac7b 100644 --- a/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs @@ -156,6 +156,25 @@ namespace Content.Server.Power.EntitySystems return receiver.Powered; } + /// + /// Return the fraction of the load power that is actually supplied to this receiver, e.g. 1 + /// if full power and 0 if no power. Better at handling brownouts compared to IsPowered(). + /// Handles always-powered devices correctly. + /// + public float SupplyFactor(EntityUid uid, ApcPowerReceiverComponent? receiver = null) + { + if (!Resolve(uid, ref receiver, false)) + return 1f; + + if (receiver.PowerDisabled) + return 0f; + + if (!receiver.NeedsPower) + return 1f; + + return receiver.NetworkLoad.ReceivingPower / receiver.Load; + } + /// /// Turn this machine on or off. /// Returns true if we turned it on, false if we turned it off.