diff --git a/Content.Client/Guidebook/GuidebookSystem.cs b/Content.Client/Guidebook/GuidebookSystem.cs index 6ed38ddef0..8ef6f13e31 100644 --- a/Content.Client/Guidebook/GuidebookSystem.cs +++ b/Content.Client/Guidebook/GuidebookSystem.cs @@ -3,7 +3,7 @@ using Content.Client.Guidebook.Components; using Content.Client.Light; using Content.Client.Verbs; using Content.Shared.Interaction; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.Speech; using Content.Shared.Tag; using Content.Shared.Verbs; diff --git a/Content.Client/Light/Components/EmergencyLightComponent.cs b/Content.Client/Light/Components/EmergencyLightComponent.cs index 17f14a62b5..6a5b48ffe9 100644 --- a/Content.Client/Light/Components/EmergencyLightComponent.cs +++ b/Content.Client/Light/Components/EmergencyLightComponent.cs @@ -1,18 +1,8 @@ -using Content.Shared.Light.Component; -using Robust.Shared.GameObjects; -using Robust.Shared.GameStates; +using Content.Shared.Light.Components; namespace Content.Client.Light.Components; [RegisterComponent] -[NetworkedComponent] public sealed partial class EmergencyLightComponent : SharedEmergencyLightComponent { } - -public enum EmergencyLightVisualLayers -{ - Base, - LightOff, - LightOn, -} diff --git a/Content.Client/Light/Components/ExpendableLightComponent.cs b/Content.Client/Light/Components/ExpendableLightComponent.cs index a3771c101e..2ce0249fc1 100644 --- a/Content.Client/Light/Components/ExpendableLightComponent.cs +++ b/Content.Client/Light/Components/ExpendableLightComponent.cs @@ -1,5 +1,5 @@ using Content.Client.Light.EntitySystems; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Robust.Shared.Audio; namespace Content.Client.Light.Components; diff --git a/Content.Client/Light/Components/HandheldLightComponent.cs b/Content.Client/Light/Components/HandheldLightComponent.cs index f140f83124..033c45a206 100644 --- a/Content.Client/Light/Components/HandheldLightComponent.cs +++ b/Content.Client/Light/Components/HandheldLightComponent.cs @@ -1,6 +1,6 @@ using System.Numerics; using Content.Shared.Light; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; diff --git a/Content.Client/Light/Components/LightBehaviourComponent.cs b/Content.Client/Light/Components/LightBehaviourComponent.cs index 443c893dfb..a7961347e3 100644 --- a/Content.Client/Light/Components/LightBehaviourComponent.cs +++ b/Content.Client/Light/Components/LightBehaviourComponent.cs @@ -1,5 +1,5 @@ using System.Linq; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using JetBrains.Annotations; using Robust.Client.Animations; using Robust.Client.GameObjects; diff --git a/Content.Client/Light/EmergencyLightSystem.cs b/Content.Client/Light/EmergencyLightSystem.cs deleted file mode 100644 index 34f2b9bf05..0000000000 --- a/Content.Client/Light/EmergencyLightSystem.cs +++ /dev/null @@ -1,89 +0,0 @@ -using System; -using Content.Client.Light.Components; -using Content.Shared.Light; -using Content.Shared.Light.Component; -using Robust.Client.Animations; -using Robust.Client.GameObjects; -using Robust.Shared.Animations; -using Robust.Shared.GameObjects; -using Robust.Shared.GameStates; -using Robust.Shared.Maths; - -namespace Content.Client.Light -{ - public sealed class EmergencyLightSystem : SharedEmergencyLightSystem - { - private const float DegreesPerSecond = 90; - private static Animation Animation => - new() - { - Length = TimeSpan.FromSeconds(360f/ DegreesPerSecond), - AnimationTracks = - { - new AnimationTrackComponentProperty - { - ComponentType = typeof(PointLightComponent), - InterpolationMode = AnimationInterpolationMode.Linear, - Property = nameof(PointLightComponent.Rotation), - KeyFrames = - { - new AnimationTrackProperty.KeyFrame(Angle.Zero, 0), - new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(120), 120f/DegreesPerSecond), - new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(240), 120f/DegreesPerSecond), - new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(360), 120f/DegreesPerSecond) - } - } - } - }; - - private const string AnimKey = "emergency"; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(HandleStartup); - SubscribeLocalEvent(HandleAnimationComplete); - SubscribeLocalEvent(HandleCompState); - } - - private void HandleCompState(EntityUid uid, EmergencyLightComponent component, ref ComponentHandleState args) - { - if (args.Current is not EmergencyLightComponentState state) return; - - if (component.Enabled == state.Enabled) return; - - var playerComponent = component.Owner.EnsureComponent(); - - component.Enabled = state.Enabled; - - if (component.Enabled && !playerComponent.HasRunningAnimation(AnimKey)) - playerComponent.Play(Animation, AnimKey); - - if (!component.Enabled) - playerComponent.Stop(AnimKey); - } - - private void HandleAnimationComplete(EntityUid uid, EmergencyLightComponent component, AnimationCompletedEvent args) - { - if (!component.Enabled || - !EntityManager.TryGetComponent(uid, out var playerComponent)) return; - - playerComponent.Play(Animation, AnimKey); - } - - private void HandleStartup(EntityUid uid, EmergencyLightComponent component, ComponentStartup args) - { - PlayAnimation(component); - } - - private void PlayAnimation(EmergencyLightComponent component) - { - if (!component.Enabled) return; - - var playerComponent = component.Owner.EnsureComponent(); - - if (!playerComponent.HasRunningAnimation(AnimKey)) - playerComponent.Play(Animation, AnimKey); - } - } -} diff --git a/Content.Client/Light/EntitySystems/EmergencyLightSystem.cs b/Content.Client/Light/EntitySystems/EmergencyLightSystem.cs index 71d6673b0d..452e70b5a3 100644 --- a/Content.Client/Light/EntitySystems/EmergencyLightSystem.cs +++ b/Content.Client/Light/EntitySystems/EmergencyLightSystem.cs @@ -1,5 +1,5 @@ using Content.Client.Light.Components; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Robust.Client.GameObjects; namespace Content.Client.Light.EntitySystems; diff --git a/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs b/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs index d180f430db..6e9e546dfa 100644 --- a/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs +++ b/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs @@ -1,5 +1,5 @@ using Content.Client.Light.Components; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Robust.Client.GameObjects; using Robust.Client.Graphics; diff --git a/Content.Client/Light/EntitySystems/LightBulbSystem.cs b/Content.Client/Light/EntitySystems/LightBulbSystem.cs index 5130308c93..09cf3780e2 100644 --- a/Content.Client/Light/EntitySystems/LightBulbSystem.cs +++ b/Content.Client/Light/EntitySystems/LightBulbSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Robust.Client.GameObjects; namespace Content.Client.Light.Visualizers; diff --git a/Content.Client/Light/EntitySystems/RotatingLightSystem.cs b/Content.Client/Light/EntitySystems/RotatingLightSystem.cs new file mode 100644 index 0000000000..dc70fb6312 --- /dev/null +++ b/Content.Client/Light/EntitySystems/RotatingLightSystem.cs @@ -0,0 +1,89 @@ +using Content.Shared.Light; +using Content.Shared.Light.Components; +using Robust.Client.Animations; +using Robust.Client.GameObjects; +using Robust.Shared.Animations; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.Maths; + +namespace Content.Client.Light.Systems; + +public sealed class RotatingLightSystem : SharedRotatingLightSystem +{ + private Animation GetAnimation(float speed) + { + var third = 120f / speed; + return new Animation() + { + Length = TimeSpan.FromSeconds(360f / speed), + AnimationTracks = + { + new AnimationTrackComponentProperty + { + ComponentType = typeof(PointLightComponent), + InterpolationMode = AnimationInterpolationMode.Linear, + Property = nameof(PointLightComponent.Rotation), + KeyFrames = + { + new AnimationTrackProperty.KeyFrame(Angle.Zero, 0), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(120), third), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(240), third), + new AnimationTrackProperty.KeyFrame(Angle.FromDegrees(360), third) + } + } + } + }; + } + + private const string AnimKey = "rotating_light"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnAfterAutoHandleState); + SubscribeLocalEvent(OnAnimationComplete); + } + + private void OnStartup(EntityUid uid, RotatingLightComponent comp, ComponentStartup args) + { + var player = EnsureComp(uid); + PlayAnimation(uid, comp, player); + } + + private void OnAfterAutoHandleState(EntityUid uid, RotatingLightComponent comp, ref AfterAutoHandleStateEvent args) + { + if (!TryComp(uid, out var player)) + return; + + if (comp.Enabled) + { + PlayAnimation(uid, comp, player); + } + else + { + player.Stop(AnimKey); + } + } + + private void OnAnimationComplete(EntityUid uid, RotatingLightComponent comp, AnimationCompletedEvent args) + { + PlayAnimation(uid, comp); + } + + /// + /// Play the light rotation animation. + /// + public void PlayAnimation(EntityUid uid, RotatingLightComponent? comp = null, AnimationPlayerComponent? player = null) + { + if (!Resolve(uid, ref comp, ref player) || !comp.Enabled) + return; + + if (!player.HasRunningAnimation(AnimKey)) + { + player.Play(GetAnimation(comp.Speed), AnimKey); + } + } +} diff --git a/Content.Client/Light/HandheldLightSystem.cs b/Content.Client/Light/HandheldLightSystem.cs index fb68c7794b..1912fe91f0 100644 --- a/Content.Client/Light/HandheldLightSystem.cs +++ b/Content.Client/Light/HandheldLightSystem.cs @@ -1,6 +1,7 @@ using Content.Client.Items; using Content.Client.Light.Components; using Content.Shared.Light; +using Content.Shared.Light.Components; using Content.Shared.Toggleable; using Robust.Client.Animations; using Robust.Client.GameObjects; diff --git a/Content.Client/Light/RgbLightControllerSystem.cs b/Content.Client/Light/RgbLightControllerSystem.cs index ac51e820f0..405cf3d018 100644 --- a/Content.Client/Light/RgbLightControllerSystem.cs +++ b/Content.Client/Light/RgbLightControllerSystem.cs @@ -4,7 +4,7 @@ using Content.Shared.Clothing; using Content.Shared.Hands; using Content.Shared.Inventory.Events; using Content.Shared.Light; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Robust.Client.GameObjects; using Robust.Shared.GameStates; using Robust.Shared.Map.Components; diff --git a/Content.Server/Light/Components/EmergencyLightComponent.cs b/Content.Server/Light/Components/EmergencyLightComponent.cs index c86167983b..20de7f1c03 100644 --- a/Content.Server/Light/Components/EmergencyLightComponent.cs +++ b/Content.Server/Light/Components/EmergencyLightComponent.cs @@ -1,62 +1,58 @@ using Content.Server.Light.EntitySystems; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; -namespace Content.Server.Light.Components +namespace Content.Server.Light.Components; + +/// +/// Component that represents an emergency light, it has an internal battery that charges when the power is on. +/// +[RegisterComponent, Access(typeof(EmergencyLightSystem))] +public sealed partial class EmergencyLightComponent : SharedEmergencyLightComponent { + [ViewVariables] + public EmergencyLightState State; + /// - /// Component that represents an emergency light, it has an internal battery that charges when the power is on. + /// Is this emergency light forced on for some reason and cannot be disabled through normal means + /// (i.e. delta alert level?) /// - [RegisterComponent, Access(typeof(EmergencyLightSystem))] - public sealed partial class EmergencyLightComponent : SharedEmergencyLightComponent + public bool ForciblyEnabled = false; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("wattage")] + public float Wattage = 5; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("chargingWattage")] + public float ChargingWattage = 60; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("chargingEfficiency")] + public float ChargingEfficiency = 0.85f; + + public Dictionary BatteryStateText = new() { - [ViewVariables] - public EmergencyLightState State; + { EmergencyLightState.Full, "emergency-light-component-light-state-full" }, + { EmergencyLightState.Empty, "emergency-light-component-light-state-empty" }, + { EmergencyLightState.Charging, "emergency-light-component-light-state-charging" }, + { EmergencyLightState.On, "emergency-light-component-light-state-on" } + }; +} - /// - /// Is this emergency light forced on for some reason and cannot be disabled through normal means - /// (i.e. delta alert level?) - /// - public bool ForciblyEnabled = false; +public enum EmergencyLightState : byte +{ + Charging, + Full, + Empty, + On +} - [ViewVariables(VVAccess.ReadWrite)] - [DataField("wattage")] - public float Wattage = 5; +public sealed class EmergencyLightEvent : EntityEventArgs +{ + public EmergencyLightState State { get; } - [ViewVariables(VVAccess.ReadWrite)] - [DataField("chargingWattage")] - public float ChargingWattage = 60; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("chargingEfficiency")] - public float ChargingEfficiency = 0.85f; - - public Dictionary BatteryStateText = new() - { - { EmergencyLightState.Full, "emergency-light-component-light-state-full" }, - { EmergencyLightState.Empty, "emergency-light-component-light-state-empty" }, - { EmergencyLightState.Charging, "emergency-light-component-light-state-charging" }, - { EmergencyLightState.On, "emergency-light-component-light-state-on" } - }; - } - - public enum EmergencyLightState : byte + public EmergencyLightEvent(EmergencyLightState state) { - Charging, - Full, - Empty, - On - } - - public sealed class EmergencyLightEvent : EntityEventArgs - { - public EmergencyLightComponent Component { get; } - - public EmergencyLightState State { get; } - - public EmergencyLightEvent(EmergencyLightComponent component, EmergencyLightState state) - { - Component = component; - State = state; - } + State = state; } } diff --git a/Content.Server/Light/Components/ExpendableLightComponent.cs b/Content.Server/Light/Components/ExpendableLightComponent.cs index 49c42a718e..4129412706 100644 --- a/Content.Server/Light/Components/ExpendableLightComponent.cs +++ b/Content.Server/Light/Components/ExpendableLightComponent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; namespace Content.Server.Light.Components { diff --git a/Content.Server/Light/Components/LightBehaviourComponent.cs b/Content.Server/Light/Components/LightBehaviourComponent.cs index 5698975ea7..430c692c3a 100644 --- a/Content.Server/Light/Components/LightBehaviourComponent.cs +++ b/Content.Server/Light/Components/LightBehaviourComponent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; namespace Content.Server.Light.Components { diff --git a/Content.Server/Light/Components/PoweredLightComponent.cs b/Content.Server/Light/Components/PoweredLightComponent.cs index 1985042c2a..489a49eec2 100644 --- a/Content.Server/Light/Components/PoweredLightComponent.cs +++ b/Content.Server/Light/Components/PoweredLightComponent.cs @@ -1,7 +1,7 @@ using Content.Server.Light.EntitySystems; using Content.Shared.Damage; using Content.Shared.DeviceLinking; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.Prototypes; diff --git a/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs b/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs index c18406564e..22a27dc8c4 100644 --- a/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs +++ b/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs @@ -2,228 +2,198 @@ using Content.Server.AlertLevel; using Content.Server.Audio; using Content.Server.Light.Components; using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; using Content.Server.Station.Components; using Content.Server.Station.Systems; using Content.Shared.Examine; using Content.Shared.Light; -using Content.Shared.Light.Component; -using JetBrains.Annotations; +using Content.Shared.Light.Components; using Robust.Server.GameObjects; using Robust.Shared.GameStates; using Color = Robust.Shared.Maths.Color; -namespace Content.Server.Light.EntitySystems +namespace Content.Server.Light.EntitySystems; + +public sealed class EmergencyLightSystem : SharedEmergencyLightSystem { - [UsedImplicitly] - public sealed class EmergencyLightSystem : SharedEmergencyLightSystem + [Dependency] private readonly AmbientSoundSystem _ambient = default!; + [Dependency] private readonly BatterySystem _battery = default!; + [Dependency] private readonly PointLightSystem _pointLight = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly StationSystem _station = default!; + + public override void Initialize() { - [Dependency] private readonly AmbientSoundSystem _ambient = default!; - [Dependency] private readonly StationSystem _station = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + base.Initialize(); - public override void Initialize() + SubscribeLocalEvent(OnEmergencyLightEvent); + SubscribeLocalEvent(OnAlertLevelChanged); + SubscribeLocalEvent(OnEmergencyExamine); + SubscribeLocalEvent(OnEmergencyPower); + } + + private void OnEmergencyPower(EntityUid uid, EmergencyLightComponent component, ref PowerChangedEvent args) + { + var meta = MetaData(uid); + + // TODO: PowerChangedEvent shouldn't be issued for paused ents but this is the world we live in. + if (meta.EntityLifeStage >= EntityLifeStage.Terminating || + meta.EntityPaused) { - base.Initialize(); - SubscribeLocalEvent(OnEmergencyLightEvent); - SubscribeLocalEvent(OnAlertLevelChanged); - SubscribeLocalEvent(GetCompState); - SubscribeLocalEvent(HandleLightToggle); - SubscribeLocalEvent(OnEmergencyExamine); - SubscribeLocalEvent(OnEmergencyPower); + return; } - private void OnEmergencyPower(EntityUid uid, EmergencyLightComponent component, ref PowerChangedEvent args) + UpdateState(uid, component); + } + + private void OnEmergencyExamine(EntityUid uid, EmergencyLightComponent component, ExaminedEvent args) + { + args.PushMarkup( + Loc.GetString("emergency-light-component-on-examine", + ("batteryStateText", + Loc.GetString(component.BatteryStateText[component.State])))); + + // Show alert level on the light itself. + if (!TryComp(_station.GetOwningStation(uid), out var alerts)) + return; + + if (alerts.AlertLevels == null) + return; + + var name = alerts.CurrentLevel; + + var color = Color.White; + if (alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details)) + color = details.Color; + + args.PushMarkup( + Loc.GetString("emergency-light-component-on-examine-alert", + ("color", color.ToHex()), + ("level", name))); + } + + private void OnEmergencyLightEvent(EntityUid uid, EmergencyLightComponent component, EmergencyLightEvent args) + { + switch (args.State) { - var meta = MetaData(uid); - - // TODO: PowerChangedEvent shouldn't be issued for paused ents but this is the world we live in. - if (meta.EntityLifeStage >= EntityLifeStage.Terminating || - meta.EntityPaused) - { - return; - } - - UpdateState(component); - } - - private void OnEmergencyExamine(EntityUid uid, EmergencyLightComponent component, ExaminedEvent args) - { - args.PushMarkup( - Loc.GetString("emergency-light-component-on-examine", - ("batteryStateText", - Loc.GetString(component.BatteryStateText[component.State])))); - - // Show alert level on the light itself. - if (!TryComp(_station.GetOwningStation(uid), out var alerts)) - return; - - if (alerts.AlertLevels == null) - return; - - var name = alerts.CurrentLevel; - - var color = Color.White; - if (alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details)) - color = details.Color; - - args.PushMarkup( - Loc.GetString("emergency-light-component-on-examine-alert", - ("color", color.ToHex()), - ("level", name))); - } - - private void HandleLightToggle(EntityUid uid, EmergencyLightComponent component, PointLightToggleEvent args) - { - if (component.Enabled == args.Enabled) - return; - - component.Enabled = args.Enabled; - Dirty(component); - } - - private void GetCompState(EntityUid uid, EmergencyLightComponent component, ref ComponentGetState args) - { - args.State = new EmergencyLightComponentState(component.Enabled); - } - - private void OnEmergencyLightEvent(EntityUid uid, EmergencyLightComponent component, EmergencyLightEvent args) - { - switch (args.State) - { - case EmergencyLightState.On: - case EmergencyLightState.Charging: - EnsureComp(uid); - break; - case EmergencyLightState.Full: - case EmergencyLightState.Empty: - RemComp(uid); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - private void OnAlertLevelChanged(AlertLevelChangedEvent ev) - { - if (!TryComp(ev.Station, out var alert)) - return; - - if (alert.AlertLevels == null || !alert.AlertLevels.Levels.TryGetValue(ev.AlertLevel, out var details)) - return; - - foreach (var (light, pointLight, appearance, xform) in EntityQuery()) - { - if (CompOrNull(xform.GridUid)?.Station != ev.Station) - continue; - - pointLight.Color = details.EmergencyLightColor; - _appearance.SetData(appearance.Owner, EmergencyLightVisuals.Color, details.EmergencyLightColor, appearance); - - if (details.ForceEnableEmergencyLights && !light.ForciblyEnabled) - { - light.ForciblyEnabled = true; - TurnOn(light); - } - else if (!details.ForceEnableEmergencyLights && light.ForciblyEnabled) - { - // Previously forcibly enabled, and we went down an alert level. - light.ForciblyEnabled = false; - UpdateState(light); - } - } - } - - public void SetState(EmergencyLightComponent component, EmergencyLightState state) - { - if (component.State == state) return; - - component.State = state; - RaiseLocalEvent(component.Owner, new EmergencyLightEvent(component, state)); - } - - public override void Update(float frameTime) - { - foreach (var (_, activeLight, battery) in EntityQuery()) - { - Update(activeLight, battery, frameTime); - } - } - - private void Update(EmergencyLightComponent component, BatteryComponent battery, float frameTime) - { - if (component.State == EmergencyLightState.On) - { - if (!battery.TryUseCharge(component.Wattage * frameTime)) - { - SetState(component, EmergencyLightState.Empty); - TurnOff(component); - } - } - else - { - battery.CurrentCharge += component.ChargingWattage * frameTime * component.ChargingEfficiency; - if (battery.IsFullyCharged) - { - if (TryComp(component.Owner, out ApcPowerReceiverComponent? receiver)) - { - receiver.Load = 1; - } - - SetState(component, EmergencyLightState.Full); - } - } - } - - /// - /// Updates the light's power drain, battery drain, sprite and actual light state. - /// - public void UpdateState(EmergencyLightComponent component) - { - if (!TryComp(component.Owner, out ApcPowerReceiverComponent? receiver)) - { - return; - } - - if (receiver.Powered && !component.ForciblyEnabled) - { - receiver.Load = (int) Math.Abs(component.Wattage); - TurnOff(component); - SetState(component, EmergencyLightState.Charging); - } - else - { - TurnOn(component); - SetState(component, EmergencyLightState.On); - } - } - - private void TurnOff(EmergencyLightComponent component) - { - if (TryComp(component.Owner, out PointLightComponent? light)) - { - light.Enabled = false; - } - - if (TryComp(component.Owner, out AppearanceComponent? appearance)) - _appearance.SetData(appearance.Owner, EmergencyLightVisuals.On, false, appearance); - - _ambient.SetAmbience(component.Owner, false); - } - - private void TurnOn(EmergencyLightComponent component) - { - if (TryComp(component.Owner, out PointLightComponent? light)) - { - light.Enabled = true; - } - - if (TryComp(component.Owner, out AppearanceComponent? appearance)) - { - _appearance.SetData(appearance.Owner, EmergencyLightVisuals.On, true, appearance); - } - - _ambient.SetAmbience(component.Owner, true); + case EmergencyLightState.On: + case EmergencyLightState.Charging: + EnsureComp(uid); + break; + case EmergencyLightState.Full: + case EmergencyLightState.Empty: + RemComp(uid); + break; + default: + throw new ArgumentOutOfRangeException(); } } -} + private void OnAlertLevelChanged(AlertLevelChangedEvent ev) + { + if (!TryComp(ev.Station, out var alert)) + return; + + if (alert.AlertLevels == null || !alert.AlertLevels.Levels.TryGetValue(ev.AlertLevel, out var details)) + return; + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var light, out var pointLight, out var appearance, out var xform)) + { + if (CompOrNull(xform.GridUid)?.Station != ev.Station) + continue; + + pointLight.Color = details.EmergencyLightColor; + _appearance.SetData(uid, EmergencyLightVisuals.Color, details.EmergencyLightColor, appearance); + + if (details.ForceEnableEmergencyLights && !light.ForciblyEnabled) + { + light.ForciblyEnabled = true; + TurnOn(uid, light); + } + else if (!details.ForceEnableEmergencyLights && light.ForciblyEnabled) + { + // Previously forcibly enabled, and we went down an alert level. + light.ForciblyEnabled = false; + UpdateState(uid, light); + } + } + } + + public void SetState(EntityUid uid, EmergencyLightComponent component, EmergencyLightState state) + { + if (component.State == state) return; + + component.State = state; + RaiseLocalEvent(uid, new EmergencyLightEvent(state)); + } + + public override void Update(float frameTime) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _, out var emergencyLight, out var battery)) + { + Update(uid, emergencyLight, battery, frameTime); + } + } + + private void Update(EntityUid uid, EmergencyLightComponent component, BatteryComponent battery, float frameTime) + { + if (component.State == EmergencyLightState.On) + { + if (!_battery.TryUseCharge(uid, component.Wattage * frameTime, battery)) + { + SetState(uid, component, EmergencyLightState.Empty); + TurnOff(uid, component); + } + } + else + { + battery.CurrentCharge += component.ChargingWattage * frameTime * component.ChargingEfficiency; + if (battery.IsFullyCharged) + { + if (TryComp(uid, out var receiver)) + { + receiver.Load = 1; + } + + SetState(uid, component, EmergencyLightState.Full); + } + } + } + + /// + /// Updates the light's power drain, battery drain, sprite and actual light state. + /// + public void UpdateState(EntityUid uid, EmergencyLightComponent component) + { + if (!TryComp(uid, out var receiver)) + return; + + if (receiver.Powered && !component.ForciblyEnabled) + { + receiver.Load = (int) Math.Abs(component.Wattage); + TurnOff(uid, component); + SetState(uid, component, EmergencyLightState.Charging); + } + else + { + TurnOn(uid, component); + SetState(uid, component, EmergencyLightState.On); + } + } + + private void TurnOff(EntityUid uid, EmergencyLightComponent component) + { + _pointLight.SetEnabled(uid, false); + _appearance.SetData(uid, EmergencyLightVisuals.On, false); + _ambient.SetAmbience(uid, false); + } + + private void TurnOn(EntityUid uid, EmergencyLightComponent component) + { + _pointLight.SetEnabled(uid, true); + _appearance.SetData(uid, EmergencyLightVisuals.On, true); + _ambient.SetAmbience(uid, true); + } +} diff --git a/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs b/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs index 0e93827df7..ff6393fe5a 100644 --- a/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs +++ b/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs @@ -3,7 +3,7 @@ using Content.Shared.Clothing.Components; using Content.Shared.Clothing.EntitySystems; using Content.Shared.Interaction.Events; using Content.Shared.Item; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.Tag; using Content.Shared.Temperature; using Content.Shared.Verbs; diff --git a/Content.Server/Light/EntitySystems/HandheldLightSystem.cs b/Content.Server/Light/EntitySystems/HandheldLightSystem.cs index 2c23057e2d..6417bad4b5 100644 --- a/Content.Server/Light/EntitySystems/HandheldLightSystem.cs +++ b/Content.Server/Light/EntitySystems/HandheldLightSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Actions.ActionTypes; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Light; +using Content.Shared.Light.Components; using Content.Shared.Rounding; using Content.Shared.Toggleable; using Content.Shared.Verbs; diff --git a/Content.Server/Light/EntitySystems/LightBulbSystem.cs b/Content.Server/Light/EntitySystems/LightBulbSystem.cs index 75e34fca36..43b0b4662c 100644 --- a/Content.Server/Light/EntitySystems/LightBulbSystem.cs +++ b/Content.Server/Light/EntitySystems/LightBulbSystem.cs @@ -1,6 +1,6 @@ using Content.Server.Light.Components; using Content.Shared.Destructible; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.Throwing; using Robust.Server.GameObjects; using Robust.Shared.Audio; diff --git a/Content.Server/Light/EntitySystems/LightReplacerSystem.cs b/Content.Server/Light/EntitySystems/LightReplacerSystem.cs index e43ce5a5ae..e6297eebc5 100644 --- a/Content.Server/Light/EntitySystems/LightReplacerSystem.cs +++ b/Content.Server/Light/EntitySystems/LightReplacerSystem.cs @@ -3,7 +3,7 @@ using Content.Server.Light.Components; using Content.Server.Storage.Components; using Content.Shared.Examine; using Content.Shared.Interaction; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.Popups; using Content.Shared.Storage; using JetBrains.Annotations; diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs index bac13274ea..acb354082a 100644 --- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs +++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs @@ -11,7 +11,7 @@ using Content.Shared.Database; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Light; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.Popups; using Robust.Server.GameObjects; using Robust.Shared.Audio; diff --git a/Content.Server/Light/EntitySystems/RotatingLightSystem.cs b/Content.Server/Light/EntitySystems/RotatingLightSystem.cs new file mode 100644 index 0000000000..dd72b3a43e --- /dev/null +++ b/Content.Server/Light/EntitySystems/RotatingLightSystem.cs @@ -0,0 +1,24 @@ +using Content.Shared.Light; +using Content.Shared.Light.Components; +using Robust.Shared.GameObjects; + +namespace Content.Server.Light.EntitySystems; + +public sealed class RotatingLightSystem : SharedRotatingLightSystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnLightToggle); + } + + private void OnLightToggle(EntityUid uid, RotatingLightComponent comp, PointLightToggleEvent args) + { + if (comp.Enabled == args.Enabled) + return; + + comp.Enabled = args.Enabled; + Dirty(comp); + } +} diff --git a/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs b/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs index 1cc7f50268..b136645264 100644 --- a/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs +++ b/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs @@ -3,7 +3,7 @@ using Content.Shared.Actions; using Content.Shared.Decals; using Content.Shared.Emag.Systems; using Content.Shared.Light; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.Mind.Components; using Content.Shared.Toggleable; using Content.Shared.Verbs; diff --git a/Content.Server/PDA/PdaSystem.cs b/Content.Server/PDA/PdaSystem.cs index abc4d6bcdc..e1650f19b3 100644 --- a/Content.Server/PDA/PdaSystem.cs +++ b/Content.Server/PDA/PdaSystem.cs @@ -12,7 +12,7 @@ using Content.Server.Station.Systems; using Content.Server.Store.Components; using Content.Server.Store.Systems; using Content.Shared.Access.Components; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.PDA; using Robust.Server.GameObjects; using Robust.Server.Player; diff --git a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs index 2b414ea00d..67866e6e5a 100644 --- a/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs +++ b/Content.Server/Weapons/Melee/EnergySword/EnergySwordSystem.cs @@ -4,7 +4,7 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Item; using Content.Shared.Light; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.Temperature; using Content.Shared.Toggleable; using Content.Shared.Tools.Components; diff --git a/Content.Shared/Light/Component/HandheldLightComponent.cs b/Content.Shared/Light/Component/HandheldLightComponent.cs deleted file mode 100644 index a3f6d2c964..0000000000 --- a/Content.Shared/Light/Component/HandheldLightComponent.cs +++ /dev/null @@ -1,95 +0,0 @@ -using Content.Shared.Actions.ActionTypes; -using Robust.Shared.Audio; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Light -{ - [NetworkedComponent] - [RegisterComponent] - [Access(typeof(SharedHandheldLightSystem))] - public sealed partial class HandheldLightComponent : Robust.Shared.GameObjects.Component - { - public byte? Level; - public bool Activated; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("wattage")] - public float Wattage { get; set; } = .8f; - - [DataField("turnOnSound")] - public SoundSpecifier TurnOnSound = new SoundPathSpecifier("/Audio/Items/flashlight_on.ogg"); - - [DataField("turnOnFailSound")] - public SoundSpecifier TurnOnFailSound = new SoundPathSpecifier("/Audio/Machines/button.ogg"); - - [DataField("turnOffSound")] - public SoundSpecifier TurnOffSound = new SoundPathSpecifier("/Audio/Items/flashlight_off.ogg"); - - /// - /// Whether to automatically set item-prefixes when toggling the flashlight. - /// - /// - /// Flashlights should probably be using explicit unshaded sprite, in-hand and clothing layers, this is - /// mostly here for backwards compatibility. - /// - [DataField("addPrefix")] - public bool AddPrefix = false; - - [DataField("toggleActionId", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ToggleActionId = "ToggleLight"; - - /// - /// Whether or not the light can be toggled via standard interactions - /// (alt verbs, using in hand, etc) - /// - [DataField("toggleOnInteract")] - public bool ToggleOnInteract = true; - - [DataField("toggleAction")] - public InstantAction? ToggleAction; - - public const int StatusLevels = 6; - - /// - /// Specify the ID of the light behaviour to use when the state of the light is Dying - /// - [DataField("blinkingBehaviourId")] - public string BlinkingBehaviourId { get; set; } = string.Empty; - - /// - /// Specify the ID of the light behaviour to use when the state of the light is LowPower - /// - [DataField("radiatingBehaviourId")] - public string RadiatingBehaviourId { get; set; } = string.Empty; - - [Serializable, NetSerializable] - public sealed class HandheldLightComponentState : ComponentState - { - public byte? Charge { get; } - - public bool Activated { get; } - - public HandheldLightComponentState(bool activated, byte? charge) - { - Activated = activated; - Charge = charge; - } - } - } - - [Serializable, NetSerializable] - public enum HandheldLightVisuals - { - Power - } - - [Serializable, NetSerializable] - public enum HandheldLightPowerStates - { - FullPower, - LowPower, - Dying, - } -} diff --git a/Content.Shared/Light/Component/SharedEmergencyLightComponent.cs b/Content.Shared/Light/Component/SharedEmergencyLightComponent.cs deleted file mode 100644 index b7d71f639d..0000000000 --- a/Content.Shared/Light/Component/SharedEmergencyLightComponent.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - -namespace Content.Shared.Light.Component -{ - [NetworkedComponent] - public abstract partial class SharedEmergencyLightComponent : Robust.Shared.GameObjects.Component - { - public bool Enabled { get; set; } = false; - } - - [Serializable, NetSerializable] - public sealed class EmergencyLightComponentState : ComponentState - { - public bool Enabled; - - public EmergencyLightComponentState(bool enabled) - { - Enabled = enabled; - } - } - - [Serializable, NetSerializable] - public enum EmergencyLightVisuals - { - On, - Color - } -} diff --git a/Content.Shared/Light/Component/SharedExpendableLightComponent.cs b/Content.Shared/Light/Component/SharedExpendableLightComponent.cs deleted file mode 100644 index 7979c15224..0000000000 --- a/Content.Shared/Light/Component/SharedExpendableLightComponent.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - -namespace Content.Shared.Light.Component -{ - [Serializable, NetSerializable] - public enum ExpendableLightVisuals - { - State, - Behavior - } - - [Serializable, NetSerializable] - public enum ExpendableLightState - { - BrandNew, - Lit, - Fading, - Dead - } - - [NetworkedComponent] - public abstract partial class SharedExpendableLightComponent: Robust.Shared.GameObjects.Component - { - public static readonly AudioParams LoopedSoundParams = new(0, 1, "Master", 62.5f, 1, 1, true, 0.3f); - - [ViewVariables(VVAccess.ReadOnly)] - public ExpendableLightState CurrentState { get; set; } - - [DataField("turnOnBehaviourID")] - public string TurnOnBehaviourID { get; set; } = string.Empty; - - [DataField("fadeOutBehaviourID")] - public string FadeOutBehaviourID { get; set; } = string.Empty; - - [DataField("glowDuration")] - public float GlowDuration { get; set; } = 60 * 15f; - - [DataField("fadeOutDuration")] - public float FadeOutDuration { get; set; } = 60 * 5f; - - [DataField("spentDesc")] - public string SpentDesc { get; set; } = string.Empty; - - [DataField("spentName")] - public string SpentName { get; set; } = string.Empty; - - [DataField("litSound")] - public SoundSpecifier? LitSound { get; set; } - - [DataField("loopedSound")] - public SoundSpecifier? LoopedSound { get; set; } - - [DataField("dieSound")] - public SoundSpecifier? DieSound { get; set; } = null; - } -} diff --git a/Content.Shared/Light/Component/SharedLightBehaviourComponent.cs b/Content.Shared/Light/Component/SharedLightBehaviourComponent.cs deleted file mode 100644 index 56ad1d6a72..0000000000 --- a/Content.Shared/Light/Component/SharedLightBehaviourComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Content.Shared.Light.Component -{ - /// - /// A component which applies a specific behaviour to a PointLightComponent on its owner. - /// - public abstract partial class SharedLightBehaviourComponent : Robust.Shared.GameObjects.Component - { - } -} diff --git a/Content.Shared/Light/Components/HandheldLightComponent.cs b/Content.Shared/Light/Components/HandheldLightComponent.cs new file mode 100644 index 0000000000..8edf558566 --- /dev/null +++ b/Content.Shared/Light/Components/HandheldLightComponent.cs @@ -0,0 +1,92 @@ +using Content.Shared.Actions.ActionTypes; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Light.Components; + +[RegisterComponent, NetworkedComponent, Access(typeof(SharedHandheldLightSystem))] +public sealed partial class HandheldLightComponent : Component +{ + public byte? Level; + public bool Activated; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField("wattage")] + public float Wattage { get; set; } = .8f; + + [DataField("turnOnSound")] + public SoundSpecifier TurnOnSound = new SoundPathSpecifier("/Audio/Items/flashlight_on.ogg"); + + [DataField("turnOnFailSound")] + public SoundSpecifier TurnOnFailSound = new SoundPathSpecifier("/Audio/Machines/button.ogg"); + + [DataField("turnOffSound")] + public SoundSpecifier TurnOffSound = new SoundPathSpecifier("/Audio/Items/flashlight_off.ogg"); + + /// + /// Whether to automatically set item-prefixes when toggling the flashlight. + /// + /// + /// Flashlights should probably be using explicit unshaded sprite, in-hand and clothing layers, this is + /// mostly here for backwards compatibility. + /// + [DataField("addPrefix")] + public bool AddPrefix = false; + + [DataField("toggleActionId", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string ToggleActionId = "ToggleLight"; + + /// + /// Whether or not the light can be toggled via standard interactions + /// (alt verbs, using in hand, etc) + /// + [DataField("toggleOnInteract")] + public bool ToggleOnInteract = true; + + [DataField("toggleAction")] + public InstantAction? ToggleAction; + + public const int StatusLevels = 6; + + /// + /// Specify the ID of the light behaviour to use when the state of the light is Dying + /// + [DataField("blinkingBehaviourId")] + public string BlinkingBehaviourId { get; set; } = string.Empty; + + /// + /// Specify the ID of the light behaviour to use when the state of the light is LowPower + /// + [DataField("radiatingBehaviourId")] + public string RadiatingBehaviourId { get; set; } = string.Empty; + + [Serializable, NetSerializable] + public sealed class HandheldLightComponentState : ComponentState + { + public byte? Charge { get; } + + public bool Activated { get; } + + public HandheldLightComponentState(bool activated, byte? charge) + { + Activated = activated; + Charge = charge; + } + } +} + +[Serializable, NetSerializable] +public enum HandheldLightVisuals +{ + Power +} + +[Serializable, NetSerializable] +public enum HandheldLightPowerStates +{ + FullPower, + LowPower, + Dying, +} diff --git a/Content.Shared/Light/Component/LightBulbComponent.cs b/Content.Shared/Light/Components/LightBulbComponent.cs similarity index 95% rename from Content.Shared/Light/Component/LightBulbComponent.cs rename to Content.Shared/Light/Components/LightBulbComponent.cs index 9c6e8524e5..01b348d13a 100644 --- a/Content.Shared/Light/Component/LightBulbComponent.cs +++ b/Content.Shared/Light/Components/LightBulbComponent.cs @@ -2,15 +2,14 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Serialization; -namespace Content.Shared.Light.Component; +namespace Content.Shared.Light.Components; /// /// Component that represents a light bulb. Can be broken, or burned, which turns them mostly useless. /// TODO: Breaking and burning should probably be moved to another component eventually. /// -[RegisterComponent] -[NetworkedComponent] -public sealed partial class LightBulbComponent : Robust.Shared.GameObjects.Component +[RegisterComponent, NetworkedComponent] +public sealed partial class LightBulbComponent : Component { /// /// The color of the lightbulb and the light it produces. diff --git a/Content.Shared/Light/Component/RgbLightControllerComponent.cs b/Content.Shared/Light/Components/RgbLightControllerComponent.cs similarity index 88% rename from Content.Shared/Light/Component/RgbLightControllerComponent.cs rename to Content.Shared/Light/Components/RgbLightControllerComponent.cs index fdacbd79f2..24beed7942 100644 --- a/Content.Shared/Light/Component/RgbLightControllerComponent.cs +++ b/Content.Shared/Light/Components/RgbLightControllerComponent.cs @@ -1,7 +1,7 @@ using Robust.Shared.GameStates; using Robust.Shared.Serialization; -namespace Content.Shared.Light.Component; +namespace Content.Shared.Light.Components; /// /// Makes the color of lights on an entity fluctuate. Will update point-light color and modulate some or all of the @@ -10,10 +10,8 @@ namespace Content.Shared.Light.Component; /// /// Networked ~~solely for admemes~~ for completely legitimate reasons, like hacked energy swords. /// -[NetworkedComponent] -[RegisterComponent] -[Access(typeof(SharedRgbLightControllerSystem))] -public sealed partial class RgbLightControllerComponent : Robust.Shared.GameObjects.Component +[NetworkedComponent, RegisterComponent, Access(typeof(SharedRgbLightControllerSystem))] +public sealed partial class RgbLightControllerComponent : Component { [DataField("cycleRate")] public float CycleRate { get; set; } = 0.1f; diff --git a/Content.Shared/Light/Components/RotatingLightComponent.cs b/Content.Shared/Light/Components/RotatingLightComponent.cs new file mode 100644 index 0000000000..f9be15ce89 --- /dev/null +++ b/Content.Shared/Light/Components/RotatingLightComponent.cs @@ -0,0 +1,21 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Light.Components; + +/// +/// Animates a point light's rotation while enabled. +/// All animation is done in the client system. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +[Access(typeof(SharedRotatingLightSystem))] +public sealed partial class RotatingLightComponent : Component +{ + /// + /// Speed to rotate at, in degrees per second + /// + [DataField("speed")] + public float Speed = 90f; + + [ViewVariables, AutoNetworkedField] + public bool Enabled = true; +} diff --git a/Content.Shared/Light/Components/SharedEmergencyLightComponent.cs b/Content.Shared/Light/Components/SharedEmergencyLightComponent.cs new file mode 100644 index 0000000000..cf05af19c1 --- /dev/null +++ b/Content.Shared/Light/Components/SharedEmergencyLightComponent.cs @@ -0,0 +1,26 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Light.Components; + +/// +/// Handles station alert level and power changes for emergency lights. +/// All logic is serverside, animation is handled by . +/// +[Access(typeof(SharedEmergencyLightSystem))] +public abstract partial class SharedEmergencyLightComponent : Component +{ +} + +[Serializable, NetSerializable] +public enum EmergencyLightVisuals +{ + On, + Color +} + +public enum EmergencyLightVisualLayers +{ + Base, + LightOff, + LightOn, +} diff --git a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs new file mode 100644 index 0000000000..c802700b62 --- /dev/null +++ b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs @@ -0,0 +1,57 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Light.Components; + +[NetworkedComponent] +public abstract partial class SharedExpendableLightComponent : Component +{ + public static readonly AudioParams LoopedSoundParams = new(0, 1, "Master", 62.5f, 1, 1, true, 0.3f); + + [ViewVariables(VVAccess.ReadOnly)] + public ExpendableLightState CurrentState { get; set; } + + [DataField("turnOnBehaviourID")] + public string TurnOnBehaviourID { get; set; } = string.Empty; + + [DataField("fadeOutBehaviourID")] + public string FadeOutBehaviourID { get; set; } = string.Empty; + + [DataField("glowDuration")] + public float GlowDuration { get; set; } = 60 * 15f; + + [DataField("fadeOutDuration")] + public float FadeOutDuration { get; set; } = 60 * 5f; + + [DataField("spentDesc")] + public string SpentDesc { get; set; } = string.Empty; + + [DataField("spentName")] + public string SpentName { get; set; } = string.Empty; + + [DataField("litSound")] + public SoundSpecifier? LitSound { get; set; } + + [DataField("loopedSound")] + public SoundSpecifier? LoopedSound { get; set; } + + [DataField("dieSound")] + public SoundSpecifier? DieSound { get; set; } = null; +} + +[Serializable, NetSerializable] +public enum ExpendableLightVisuals +{ + State, + Behavior +} + +[Serializable, NetSerializable] +public enum ExpendableLightState +{ + BrandNew, + Lit, + Fading, + Dead +} diff --git a/Content.Shared/Light/Components/SharedLightBehaviourComponent.cs b/Content.Shared/Light/Components/SharedLightBehaviourComponent.cs new file mode 100644 index 0000000000..b93cfeef7e --- /dev/null +++ b/Content.Shared/Light/Components/SharedLightBehaviourComponent.cs @@ -0,0 +1,8 @@ +namespace Content.Shared.Light.Components; + +/// +/// A component which applies a specific behaviour to a PointLightComponent on its owner. +/// +public abstract partial class SharedLightBehaviourComponent : Component +{ +} diff --git a/Content.Shared/Light/Component/UnpoweredFlashlightComponent.cs b/Content.Shared/Light/Components/UnpoweredFlashlightComponent.cs similarity index 86% rename from Content.Shared/Light/Component/UnpoweredFlashlightComponent.cs rename to Content.Shared/Light/Components/UnpoweredFlashlightComponent.cs index 66879a59e7..4011f6937b 100644 --- a/Content.Shared/Light/Component/UnpoweredFlashlightComponent.cs +++ b/Content.Shared/Light/Components/UnpoweredFlashlightComponent.cs @@ -2,14 +2,14 @@ using Content.Shared.Actions.ActionTypes; using Content.Shared.Decals; using Robust.Shared.Audio; -namespace Content.Shared.Light.Component; +namespace Content.Shared.Light.Components; /// /// This is simplified version of . /// It doesn't consume any power and can be toggle only by verb. /// [RegisterComponent] -public sealed partial class UnpoweredFlashlightComponent : Robust.Shared.GameObjects.Component +public sealed partial class UnpoweredFlashlightComponent : Component { [DataField("toggleFlashlightSound")] public SoundSpecifier ToggleSound = new SoundPathSpecifier("/Audio/Items/flashlight_pda.ogg"); diff --git a/Content.Shared/Light/SharedEmergencyLightSystem.cs b/Content.Shared/Light/SharedEmergencyLightSystem.cs index 65948cfb98..3cb71b1a70 100644 --- a/Content.Shared/Light/SharedEmergencyLightSystem.cs +++ b/Content.Shared/Light/SharedEmergencyLightSystem.cs @@ -1,7 +1,5 @@ -namespace Content.Shared.Light -{ - public abstract class SharedEmergencyLightSystem : EntitySystem - { +namespace Content.Shared.Light; - } +public abstract class SharedEmergencyLightSystem : EntitySystem +{ } diff --git a/Content.Shared/Light/SharedHandheldLightSystem.cs b/Content.Shared/Light/SharedHandheldLightSystem.cs index 5101ca4f77..88fd07ba20 100644 --- a/Content.Shared/Light/SharedHandheldLightSystem.cs +++ b/Content.Shared/Light/SharedHandheldLightSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Actions; using Content.Shared.Clothing.EntitySystems; using Content.Shared.Item; +using Content.Shared.Light.Components; using Content.Shared.Toggleable; using Robust.Shared.Audio; using Robust.Shared.GameStates; diff --git a/Content.Shared/Light/SharedRgbLightControllerSystem.cs b/Content.Shared/Light/SharedRgbLightControllerSystem.cs index 7ac2b85a50..1bba91c5e7 100644 --- a/Content.Shared/Light/SharedRgbLightControllerSystem.cs +++ b/Content.Shared/Light/SharedRgbLightControllerSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Robust.Shared.GameStates; namespace Content.Shared.Light; diff --git a/Content.Shared/Light/SharedRotatingLightSystem.cs b/Content.Shared/Light/SharedRotatingLightSystem.cs new file mode 100644 index 0000000000..ab816870d1 --- /dev/null +++ b/Content.Shared/Light/SharedRotatingLightSystem.cs @@ -0,0 +1,5 @@ +namespace Content.Shared.Light; + +public abstract class SharedRotatingLightSystem : EntitySystem +{ +} diff --git a/Content.Shared/Vehicle/SharedVehicleSystem.cs b/Content.Shared/Vehicle/SharedVehicleSystem.cs index af7e7e7832..b18e66a1ee 100644 --- a/Content.Shared/Vehicle/SharedVehicleSystem.cs +++ b/Content.Shared/Vehicle/SharedVehicleSystem.cs @@ -13,7 +13,7 @@ using Content.Shared.Tag; using Content.Shared.Audio; using Content.Shared.Buckle; using Content.Shared.Hands; -using Content.Shared.Light.Component; +using Content.Shared.Light.Components; using Content.Shared.Popups; using Robust.Shared.Network; using Robust.Shared.Physics.Systems; diff --git a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml index d538c1df03..ac8d2c5417 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml @@ -314,6 +314,7 @@ maxCharge: 30000 startingCharge: 0 - type: EmergencyLight + - type: RotatingLight - type: Sprite sprite: Structures/Wallmounts/Lighting/emergency_light.rsi layers: